针对寻址异步请求的ZMQ Python请求响应代理

时间:2015-01-20 17:13:44

标签: python request zeromq broker reply

我想利用ZMQ来实现(在python中)一个代理和一个客户端,它以异步方式处理对被寻址实体的请求 - 回复。客户端包含执行请求和回复的功能(唯一缺少的是确切的套接字类型/模式)。

请求可能是阻塞的,但是回复方需要能够在它们进入时处理并行(线程)请求。(即REP-socket不够好,因为它需要在下次接收之前发送)< / p>

它需要通过代理,因为有许多可能的实体可以做请求和回复,我只想绑定一定数量的端口(不是每个实体一个)。

Entity1                Broker                    Entity2
  REQ ------------- ROUTER ?????? -------------- ??????

Entity1将知道Entity2的ID,并使用它来确保特定地向Entity2发出请求。可以有任意数量的实体,但应该回答请求的所有实体都将注册ID。

我已经在上面的经纪人的右侧尝试过DEALER,但是那个人似乎只会发送循环请求。

所以有人知道一个好的模式/套接字我可以使用它来异步地处理特定的实体吗?

要点:

  • 请求方阻止
  • 用于绑定固定号码的代理/代理 港口
  • 回复套接字应由具体处理 请求者
  • 线索回复(回复方可以接收和处理 并行请求)

我已经非常广泛地阅读了ZMQ手册,但我还没有找到任何通过经纪人解决特定套接字的真正好的模式,所以非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

经过一些进一步的研究和测试后,我发现了一种似乎可以解决我所有需求的模式。

<强>模式

Requester               Broker                   Replier
  REQ ------------- ROUTER ROUTER -------------- DEALER
                (requests) (replies)

<强>请求者

客户端的请求端只是连接到代理上的请求路由器,发送请求并开始读取套接字以获得答复:

reqSocket.connect(self._reqAddress)
reqSocket.send_multipart([repId, message])
reply = reqSocket.recv_multipart()[0]

回复者ID包含在消息的第一部分中,例如:

Outgoing message: ['replierId', 'requestMsg']

请求路由器

if self.reqRouterSocket in socketEvents:
    multipart = self.reqRouterSocket.recv_multipart()
    multipart = [multipart[-2]] + multipart
    del multipart[-2]
    self.repRouterSocket.send_multipart(multipart)

即,请求路由器只移动有效负载的第一部分(作为replierId)并将其放在地址堆栈中的第一部分:

Incoming message: ['reqSocketAddr', '', 'replierId', 'requestMsg']
Outgoing message: ['replierId', 'reqSocketAddr', '', 'requestMsg']

传出消息从replier路由器发送。由于回复者将其套接字ID设置为“replierId”。并且已连接到replier路由器,该路由器识别此地址并能够成功传递请求。

<强>留言者

replier需要将其自己的套接字标识设置为某个已知值,以便直接进行如上所述的处理。

注意:在执行连接到回复路由器之前,必须设置DEALER套接字的套接字ID。设置套接字的标识:

self.dealerSocket.setsockopt(zmq.IDENTITY, 'replierId')

否则路由器不知道id并将抛出消息。

回复者侦听传入的请求。在我的情况下,这是所有线程和请求是异步处理。这就是使用DEALER套接字而不是常规REP的原因,这在同步情况下会更容易。 DEALER套接字可以接收进一步的请求,而不必首先回答第一个请求,REP必须这样做。然而,在回复方面所做的简化版本是:

multipart = self.dealerSocket.recv_multipart()
returnRoute = multipart[:-1]
requestMsg = multipart[-1]
reply = someFunction(requestMsg)
self.dealerSocket.send_multipart(returnRoute + [reply])

即,回复者只返回它所获得的内容,但改变了请求的回复:

Incoming message: ['replierId', 'reqSocketAddr', '', 'request']
Outgoing message: ['replierId', 'reqSocketAddr', '', 'reply']

然后将此外发消息发送回应答路由器。

回复路由器

在代理的这一侧选择路由器纯粹是因为它需要功能来解决许多连接的路由器中的特定套接字。

if self.repRouterSocket in socketEvents:
    multipart = self.repRouterSocket.recv_multipart()
    self.reqRouterSocket.send_multipart(multipart[1:])

即,只需弹出地址堆栈的第一个地址,然后再将消息发送到请求方。

Incoming message: ['replierId', 'reqSocketAddr', '', 'reply']
Outgoing message: ['reqSocketAddr', '', 'reply']

请求路由器识别该地址并将请求发送回请求者:

Incoming list: ['reply']

这种模式似乎符合我在问题中提出的要求。我希望它也可以用于其他人。