RabbitMQ六種模式介紹

參考:

RabbitMQ官網

鳥哥RabbitMQ教程

RabbitMQ常用交換機模式

RabbitMQ之RPC實現


導入RabbitMQ的依賴:

<dependency>
   <groupId>com.rabbitmq</groupId>
   <artifactId>amqp-client</artifactId>
   <version>3.4.1</version>
</dependency>

一、簡單隊列模式

圖示:

(P) -> [|||] -> (C)

P:代表生產者

紅色方塊:代表隊列

C:代表消費者

創建RabbitMQ連接工具類:

public class ConnectionUtil {
    public static void main(String[] args) throws Exception {
        System.out.println(getConnection());
    }

    public static Connection getConnection() throws Exception {
//        定義連接工廠
        ConnectionFactory factory = new ConnectionFactory();
//        服務地址
        factory.setHost("localhost");
//        端口號
        factory.setPort(5672);
//        vhost
        factory.setVirtualHost("testhost");
//        用戶名
        factory.setUsername("admin");
//        密碼
        factory.setPassword("admin");
        return factory.newConnection();
    }

}

1.發送消息

(P) -> [|||]

public class Send {

    private final static String QUEUE_NAME = "q_test_01";

    public static void main(String[] argv) throws Exception {
//      獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
//        從連接中創建通道
        Channel channel = connection.createChannel();
//        聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        //消息內容
        String message = "Hello World";
        channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
        System.out.println("[x] send " + message + "");
        //關閉通道
        channel.close();
        //關閉連接
        connection.close();
    }

}

2.接收消息

[|||] -> (C)

 

public class Recv {
    private final static String QUEUE_NAME = "q_test_01";

    public static void main(String[] argv) throws Exception {

        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        // 從連接中創建通道
        Channel channel = connection.createChannel();
        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);

        // 監聽隊列
        channel.basicConsume(QUEUE_NAME, true, consumer);

        // 獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [x] Received '" + message + "'");
        }
    }
}

二、Work模式

圖示:

 1個生產者,1個隊列,2個消費者

1.發送消息

public class Send {
    private final static String QUEUE_NAME = "test_queue_work";

    public static void main(String[] args) throws Exception {
        //獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        for (int i = 0; i < 100; i++) {
            //消息內容
            String message = "" + i;
            channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
            System.out.println(" [x] Sent '" + message + "'");
            Thread.sleep(10);
        }
        channel.close();
        connection.close();
    }
}

2.接受消息

消費者1:

public class Recv1 {
    private final static String QUEUE_NAME = "test_queue_work";

    public static void main(String[] args) throws Exception {
        //獲取到連接
        Connection connection = ConnectionUtil.getConnection();
        //獲取到mq通道
        Channel channel = connection.createChannel();
        //聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //同一時刻服務器只會發送一條消息給消費者
        channel.basicQos(1);
        //定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //監聽隊列,false表示手動返回完成狀態,true表示自動
        channel.basicConsume(QUEUE_NAME, true, consumer);

        //獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("[y] Received" + message);
            //休眠
            Thread.sleep(10);
            //返回確認狀態,註釋掉表示使用自動確認模式
//            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

消費者2:

public class Recv2 {

    private final static String QUEUE_NAME = "test_queue_work";

    public static void main(String[] argv) throws Exception {

        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 同一時刻服務器只會發一條消息給消費者
        //隊列只有在收到消費者發回的上一條消息 ack 確認後,纔會向該消費者發送下一條消息。
        channel.basicQos(1);

        // 定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 監聽隊列,false表示手動返回完成狀態,true表示自動
        channel.basicConsume(QUEUE_NAME, false, consumer);

        // 獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [x] Received '" + message + "'");
            //休眠1秒
            Thread.sleep(10000);
            //下面這行註釋掉表示使用自動確認模式,只有手動ack確認後,隊列纔會推送下一條消息到消費者
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

備註:

1.消費者1開啓了ack自動確認,

2.消費者2關閉了ack自動確認,使用的是手動ack確認,只有隊列收到了上N(N爲設置的Qos值)條消息的ack確認後纔會發送下N條消息。

3.怎樣才能做到按照每個消費者的能力分配消息呢?聯合使用 Qos 和 Acknowledge 就可以做到。
basicQos 方法設置了當前信道最大預獲取(prefetch)消息數量爲1。消息從隊列異步推送給消費者,消費者的 ack 也是異步發送給隊列,從隊列的視角去看,總是會有一批消息已推送但尚未獲得 ack 確認,Qos 的 prefetchCount 參數就是用來限制這批未確認消息數量的。設爲1時,隊列只有在收到消費者發回的上一條消息 ack 確認後,纔會向該消費者發送下一條消息。prefetchCount 的默認值爲0,即沒有限制,隊列會將所有消息儘快發給消費者。
 

4.消息的確認模式
消費者從隊列中獲取消息,服務端如何知道消息已經被消費呢?

4.1 模式1:自動確認
只要消息從隊列中獲取,無論消費者獲取到消息後是否成功消息,都認爲是消息已經成功消費。
4.2 模式2:手動確認
消費者從隊列中獲取消息後,服務器會將該消息標記爲不可用狀態,等待消費者的反饋,如果消費者一直沒有反饋,那麼該消息將一直處於不可用狀態。

開啓手動ack確認:
 

5.兩種分發方式

5.1 輪詢分發 :

使用任務隊列的優點之一就是可以輕易的並行工作。如果我們積壓了好多工作,我們可以通過增加工作者(消費者)來解決這一問題,使得系統的伸縮性更加容易。在默認情況下,RabbitMQ將逐個發送消息到在序列中的下一個消費者(而不考慮每個任務的時長等等,且是提前一次性分配,並非一個一個分配)。平均每個消費者獲得相同數量的消息。這種方式分發消息機制稱爲Round-Robin(輪詢)。

使用輪詢分發:兩個消費者的Qos值設爲相同的,關閉手動應答,改爲自動應答。

5.2 公平分發 :

雖然上面的分配法方式也還行,但是有個問題就是:比如:現在有2個消費者,所有的奇數的消息都是繁忙的,而偶數則是輕鬆的。按照輪詢的方式,奇數的任務交給了第一個消費者,所以一直在忙個不停。偶數的任務交給另一個消費者,則立即完成任務,然後閒得不行。而RabbitMQ則是不瞭解這些的。這是因爲當消息進入隊列,RabbitMQ就會分派消息。它不看消費者爲應答的數目,只是盲目的將消息發給輪詢指定的消費者。
使用公平分發:關閉自動應答,改爲手動應答。
 

測試數據:

消費者1:休眠10ms(能力強)

消費者2:休眠100ms(能力弱)

消費者1和消費者2都開啓了手動ack確認,消費者1消費了81條消息,消費者2消費了19條數據,消息順序沒規律。(公平分發)

消費者1和消費者2都開啓了自動ack確認,消費者1消費了50條消息,消費者2消費了50條數據,奇偶輪詢。(輪詢分發)

三、訂閱模式

特點:

1.1個生產者,多個消費者
2.每個消費者都有自己的一個隊列
3.生產者沒有將消息直接發送到隊列,而是發送到了交換機
4.每個隊列都要綁定到交換機
5.生產者發送的消息,經過交換機,到達隊列,實現一個消息被多個消費者獲取

發送消息:

public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_fanout";

    public static void main(String[] args) throws Exception {
        //獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        //聲明exchange,exchange一旦創建就不能改變,而服務器端創建了exchange,客戶端也創建一遍就會報錯
        channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
        //消息內容
        String message = "Hello World";
        //注意:消息發送到沒有隊列綁定的交換機時,消息將丟失,因爲,交換機沒有存儲消息的能力,消息只能存在在隊列中。
        channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
        System.out.println("sent " + message);
        channel.close();
        connection.close();

    }
}

接受消息:

消費者1:

public class Recv1 {
    private final static String QUEUE_NAME = "test_queue_work1";
    private final static String EXCHANGE_NAME = "test_exchange_fanout";

    public static void main(String[] args) throws Exception {
        //獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //綁定隊列到交換機
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
        //同一時刻服務器只會發送一條消息給消費者
        channel.basicQos(1);
        //定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //監聽隊列,手動返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);
        //獲取消息
        while (true) {
            //消費者接受隊列推送過來的消息
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [Recv] Received '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }


    }
}

消費者2:

public class Recv2 {

    private final static String QUEUE_NAME = "test_queue_work2";

    private final static String EXCHANGE_NAME = "test_exchange_fanout";

    public static void main(String[] argv) throws Exception {

        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 綁定隊列到交換機
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");

        // 同一時刻服務器只會發一條消息給消費者
        channel.basicQos(1);

        // 定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 監聽隊列,手動返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);

        // 獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [Recv2] Received '" + message + "'");
            Thread.sleep(10);

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

備註:

1.一個消費者隊列可以有多個消費者實例,只有其中一個消費者實例會消費 

2.在創建exchange時,一旦創建就不能改變,而服務端創建了exchange,客戶端也創建一遍就會報錯。

3.消息發送到沒有隊列綁定的交換機時,消息將丟失,因爲,交換機沒有存儲消息的能力,消息只能存在在隊列中。

在管理工具中查看隊列和交換機的綁定關係:

這裏寫圖片描述

交換機類型爲:fanout(廣播式交換機)

1.這種模式不需要指定Routing key路由鍵,一個交換機可以綁定多個隊列queue,一個queue可同時與多個exchange交換機進行綁定;

2.如果消息發送到交換機上,但是這個交換機上面沒有綁定的隊列,那麼這些消息將會被丟棄;

四、路由模式

交換機類型爲:direct(直連交換機)

說明:

1.任何發送到Direct Exchange的消息都會被轉發到指定RouteKey中指定的隊列Queue;
2.生產者生產消息的時候需要執行Routing Key路由鍵;
3.隊列綁定交換機的時候需要指定Binding Key,只有路由鍵與綁定鍵相同的話,才能將消息發送到綁定這個隊列的消費者;
4.如果vhost中不存在RouteKey中指定的隊列名,則該消息會被丟棄。

發送消息:

public class Send {
    private final static String EXCHANGE_NAME = "test_exchange_direct";

    public static void main(String[] args) throws Exception {
        //獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //聲明exchange,交換機類型爲:direct
        channel.exchangeDeclare(EXCHANGE_NAME, "direct");
        //消息內容
        String message = "新增商品";
//        消息的key爲:delete
        channel.basicPublish(EXCHANGE_NAME, "insert", null, message.getBytes());
        System.out.println("[x] sent " + message);
        channel.close();
        connection.close();
    }
}

接受消息:
消費者1:

public class Recv1 {
    private final static String QUEUE_NAME = "test_queue_direct_1";
    private final static String EXCHANGE_NAME= "test_exchange_direct";

    public static void main(String[] args) throws Exception {
        //獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //聲明隊列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //綁定隊列到交換機
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"update");
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"delete");
        //同一時刻服務器只會發送一條消息給消費者
        channel.basicQos(1);
        //定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //監聽隊列,手動返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);
        //獲取消息
        while (true) {
            //消費者接受隊列推送過來的消息
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [Recv] Received '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }

    }
}

消費者2:

public class Recv2 {
    private final static String QUEUE_NAME = "test_queue_direct_2";
    private final static String EXCHANGE_NAME = "test_exchange_direct";

    public static void main(String[] args) throws Exception {
        //獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);
        //綁定隊列到交換機
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "insert");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "delete");
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "update");

        //同一時刻服務器只會發送一條消息給消費者
        channel.basicQos(1);
        //定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //監聽隊列,手動返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);
        //獲取消息
        while (true) {
            //消費者接受隊列推送過來的消息
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [Recv] Received '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }

    }
}

 

五、主題模式(通配符模式)


交換機類型爲:topic

這裏寫圖片描述

1.任何發送到Topic Exchange的消息都會被轉發到所有滿足Route Key與Binding Key模糊匹配的隊列Queue上;
2.生產者發送消息的時候需要指定Route Key,同時綁定Exchange與Queue的時候也需要指定Binding Key;
3.#” 表示0個或多個關鍵字,“*”表示匹配一個關鍵字;
4.如果Exchange沒有發現能夠與RouteKey模糊匹配的隊列Queue,則會拋棄此消息;
5.如果Binding中的Routing key *,#都沒有,則路由鍵跟綁定鍵相等的時候才轉發消息,類似Direct Exchange;

6.如果Binding中的Routing key爲#或者#.#,則全部轉發,類似Fanout Exchange;

發送消息:

public class Send {

    private final static String EXCHANGE_NAME = "test_exchange_topic";

    public static void main(String[] argv) throws Exception {
        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明exchange
        channel.exchangeDeclare(EXCHANGE_NAME, "topic");

        // 消息內容
        String message = "Hello World!!";
        channel.basicPublish(EXCHANGE_NAME, "routekey.1", null, message.getBytes());
        System.out.println(" [x] Sent '" + message + "'");

        channel.close();
        connection.close();
    }
}

接受消息:

消費者1:

public class Recv1 {

    private final static String QUEUE_NAME = "test_queue_topic_work_1";

    private final static String EXCHANGE_NAME = "test_exchange_topic";

    public static void main(String[] argv) throws Exception {

        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 綁定隊列到交換機
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "routekey.*");

        // 同一時刻服務器只會發一條消息給消費者
        channel.basicQos(1);

        // 定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 監聽隊列,手動返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);

        // 獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [Recv_x] Received '" + message + "'");
            Thread.sleep(10);

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

消費者2:

public class Recv2 {
    private final static String QUEUE_NAME = "test_queue_topic_work_2";

    private final static String EXCHANGE_NAME = "test_exchange_topic";

    public static void main(String[] argv) throws Exception {

        // 獲取到連接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();

        // 聲明隊列
        channel.queueDeclare(QUEUE_NAME, false, false, false, null);

        // 綁定隊列到交換機
        channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "*.*");

        // 同一時刻服務器只會發一條消息給消費者
        channel.basicQos(1);

        // 定義隊列的消費者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        // 監聽隊列,手動返回完成
        channel.basicConsume(QUEUE_NAME, false, consumer);

        // 獲取消息
        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" [Recv2_x] Received '" + message + "'");
            Thread.sleep(10);

            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

備註:

  同一條消息可以發送到多個隊列上,一個隊列上只有一個消費者實例會消費消息。

六:RPC模式

RPC的處理流程:

1.當客戶端啓動時,創建一個匿名的回調隊列。
2.客戶端爲RPC請求設置2個屬性:replyTo,設置回調隊列名字;correlationId,標記request。
3.請求被髮送到rpc_queue隊列中。
4.RPC服務器端監聽rpc_queue隊列中的請求,當請求到來時,服務器端會處理並且把帶有結果的消息發送給客戶端。接收的隊列就是replyTo設定的回調隊列。
5.客戶端監聽回調隊列,當有消息時,檢查correlationId屬性,如果與request中匹配,那就是結果了。

 

RPC服務端;

public class RPCServer {
    private static final String RPC_QUEUE_NAME = "rpc_queue";

    //具體處理方法
    private static int fib(int n) {
        if (n == 0)
            return 0;
        if (n == 1)
            return 1;
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] argv) throws Exception {

        //從工廠中獲取連接
        Connection connection = ConnectionUtil.getConnection();
        //從連接中獲取信道
        final Channel channel = connection.createChannel();
        //name:隊列名字
        channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null);

        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(RPC_QUEUE_NAME, false, consumer);
        System.out.println(" [x] Awaiting RPC requests");

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            BasicProperties props = delivery.getProperties();
//          BasicProperties replyProps = new BasicProperties.Builder().correlationId(props.getCorrelationId()).build();
            AMQP.BasicProperties replyProps = new AMQP.BasicProperties.Builder()
                    .correlationId(props.getCorrelationId()).build();
            String message = new String(delivery.getBody());
            int n = Integer.parseInt(message);
            System.out.println(" [.] fib(" + message + ")");
            String repsonse = "" + fib(n);
            channel.basicPublish("", props.getReplyTo(), replyProps, repsonse.getBytes());
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
        }
    }
}

RPC客戶端:

public class RPCClient {
    private Connection connection;
    private Channel channel;
    private String requestQueueName = "rpc_queue";
    private String replyQueueName;

    public RPCClient() throws Exception {
        //建立一個連接和一個通道,併爲回調聲明一個唯一的'回調'隊列
        connection = ConnectionUtil.getConnection();
        channel = connection.createChannel();
        //定義一個臨時變量的接受隊列名
        replyQueueName = channel.queueDeclare().getQueue();
    }
    //發送RPC請求
    public String call(String message) throws IOException, InterruptedException {
        //生成一個唯一的字符串作爲回調隊列的編號
        String corrId = UUID.randomUUID().toString();
        //發送請求消息,消息使用了兩個屬性:replyto和correlationId
        //服務端根據replyto返回結果,客戶端根據correlationId判斷響應是不是給自己的
        AMQP.BasicProperties props = new AMQP.BasicProperties.Builder().correlationId(corrId).replyTo(replyQueueName)
                .build();

        //發佈一個消息,requestQueueName路由規則
        channel.basicPublish("", requestQueueName, props, message.getBytes("UTF-8"));

        //由於我們的消費者交易處理是在單獨的線程中進行的,因此我們需要在響應到達之前暫停主線程。
        //這裏我們創建的 容量爲1的阻塞隊列ArrayBlockingQueue,因爲我們只需要等待一個響應。
        final BlockingQueue<String> response = new ArrayBlockingQueue<String>(1);

        // String basicConsume(String queue, boolean autoAck, Consumer callback)
        channel.basicConsume(replyQueueName, true, new DefaultConsumer(channel) {
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties,
                                       byte[] body) throws IOException {
                //檢查它的correlationId是否是我們所要找的那個
                if (properties.getCorrelationId().equals(corrId)) {
                    //如果是,則響應BlockingQueue
                    response.offer(new String(body, "UTF-8"));
                }
            }
        });
        return response.take();
    }

    public void close() throws IOException {
        connection.close();
    }

    public static void main(String[] argv) {
        RPCClient fibonacciRpc = null;
        String response = null;
        try {
            fibonacciRpc = new RPCClient();

            System.out.println(" [x] Requesting fib(30)");
            response = fibonacciRpc.call("30");
            System.out.println(" [.] Got '" + response + "'");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fibonacciRpc != null) {
                try {
                    fibonacciRpc.close();
                } catch (IOException _ignore) {
                }
            }
        }
    }

}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章