zeromq:如何做 REQ-multiple-REP?

zeromq: how to do REQ-multiple-REP?

使用zeromq,我基本上想做一个'REQ-multiple-REP'模式:客户端向服务器发送1条消息,然后服务器发送多个回复直到完成。 'multiple replies' 给那个客户:不是一般出版物。

我可以自己解决这个问题:有一个正常的 REQ-REP 套接字,当服务器收到请求时,它会创建一个新的 PUB,在回复客户端时使用该 PUB 的地址进行回复,然后客户端然后 SUB 到 PUB,服务器已经开始将消息放入其中。

但这感觉很笨拙。有没有更好的办法? zeromq 是否已经为这个用例提供了一些很酷的东西?

您也许可以与 XPUB/XSUB 合作 REQ/REP 做一些事情。

这些可以永久设置,即客户端和服务器都在同一个 XPUB/XSUB 连接上。当客户端想要发出请求时,它可以通过其 XSUB 套接字发送客户端唯一的订阅消息。服务器读取并记住它。客户端然后发送一个 REQ,其中再次包含订阅消息作为请求的字段之一。服务器在 REP 上响应,所有进一步的服务器响应都通过其 XPUB 发送,使用它之前从客户端收到的订阅消息来标记响应。所有其他未订阅的客户将不会收到不适合他们自己的回复。然后,客户端通过其 XSUB 套接字发送 unsub 取消订阅这些响应(在收到最后一个响应后;服务器可能必须在最后一个响应中包含 "last response" 标志)。对于下一个请求,它使用不同的客户端唯一 ID,以便可以将该请求的响应与上一个请求的响应区分开来。

这仍然不是很优雅,但至少它不会一直建立/拆除套接字连接。

伪代码 - 服务器。您需要阅读指南的这一部分:Pub-Sub Message Envelopes

while (run)
    zmq_poll(XPUB socket, X REP socket)
    if (ZPUB socket ready)
        zmq_recv(client subscription message)
        if (message was a subscription)
            store subscription info (i.e. the client's unique topic for responses)
        else if (message was unsubscribe)
            forget client's unique topic for responses
    else if (X REP socket ready AND client unique topic received)
        zmq_recv(client request including client topic for responses)
        process the request
        zmq_send(REP socket, first response)
        s_sendmore(XPUB socket, client's unique topic for responses)
        s_send(XPUB socket, second response)
        s_sendmore(XPUB socket, client's unique topic for responses)
        s_send(XPUB socket, third response)
    else if (X REP socket ready AND client unique topic *not* received)
       error condition
    end if
loop

和客户

create unique topic for response (a random, unique string) // Caution - I think there's a length limit
zmq_send(ZSUB socket, '[=11=]x01`+ unique topic string)
zmq_setsockopt(ZSUB socket, ZMQ_SUBSCRIBE, unique topic for responses) // may not be necessary - it's a ZSUB socket, and the socket may have already picked this up from the previous zmq_send().
zmq_send(REQ socket, request including unique topic string)
zmq_recv(REQ socket, first response)
zmq_recv(ZSUB socket, second response)
zmq_recv(ZSUB socket, third response)
zmq_setsockopt(ZSUB socket, ZMQ_UNSUBSCRIBE, unique topic for responses) // this may not be necessary, and the follow line might do the same thing
zmq_send(ZSUB socket, '[=11=]x00`+ unique topic string)

Dealer/Router 对应该适用于您的用例,其中请求由经销商替换,回复由路由器替换。

重要的部分是路由器套接字行为。任何传入消息都将是多部分的,并且至少包含 1 个 'routing' 帧、1 个空帧以及您发送的任意多个内容帧。

发送给经销商的任何消息都会弹出第一帧,并使用它来确定将消息发送给哪个客户端。