我正在使用此程序使用PULL
测试ROUTER
套接字。我创建/绑定ROUTER
,然后连接一个带有标识的PULL套接字; ROUTER
然后使用其标识(基本的zeromq包络)发送专门为客户端发送的消息
public static void main(String[] o){
ZContext routerCtx = new ZContext();
Socket rtr = routerCtx.createSocket( ZMQ.ROUTER);
rtr.setRouterMandatory(true);
rtr.bind("tcp://*:5500");
ZContext clientCtx = new ZContext();
Socket client1 = clientCtx.createSocket( ZMQ.PULL);
client1.setIdentity("client1".getBytes());
client1.connect("tcp://localhost:5500");
try{
//Thread.currentThread().sleep(2000);
rtr.sendMore("client1");
rtr.sendMore("");
rtr.send("Hello!");
System.out.println( client1.recvStr());
System.out.println("Client Received: " + client1.recvStr());
}catch(Exception e1){
System.out.println( "Could not send to client1: " + e1.getMessage());
}
routerCtx.destroy();
clientCtx.destroy();
}
期望的结果是打印Client Received: Hello!"
,但是ROUTER会抛出与不可寻址消息一致的异常;我在这种情况下使用setRouterMandatory(true)
抛出异常,但是,客户端显式设置了身份,服务器发送到该身份,所以我不明白为什么会引发异常。< / p>
如果我通过取消注释Thread.currentThread().sleep(2000);
来添加稍微的延迟,则消息传递成功,但我鄙视使用睡眠和等待,它会产生混乱和脆弱的代码,但更重要的是,没有回答& #34;为什么&#34;
答案 0 :(得分:0)
为什么会这样?
你有竞争条件。 client1.connect
调用会启动连接过程,但无法保证在您调用rtr.sendMore("client1");
时建立实际连接。您的sleep()
解决方法几乎证明了这一点。
将PULL
更改为DEALER
是朝着正确方向迈出的一步,因为DEALER
可以发送和接收。为了避免需要睡眠和等待,您必须更改协议。对上面的代码进行简单的更改就是让DEALER
连接,然后立即向ROUTER
发送“HELLO”消息(可能只是一个空消息)。必须重新设计路由器代码,使其在从DEALER
收到HELLO消息之前不执行任何操作。收到HELLO消息后,您知道连接已成功建立,您可以安全地发送聊天消息。
此外,此协议不需要您的路由器提前知道客户端ID。相反,您可以从HELLO消息中提取它。从DEALER到ROUTER的消息保证是多部分消息,第一部分是客户端ID。