Python ZMQ响应器未收到消息

时间:2019-08-11 16:35:26

标签: python networking python-3.6 zeromq pyzmq

我正在尝试一个简单的zmq脚本,但是响应者不知何故没有收到第一条消息。

响应者如下:

def main():
    context = zmq.Context()
    socket = context.socket(zmq.REP)
    socket.connect("tcp://localhost:{}".format(5560))
    print("connected ...")
    while True:
          #  Wait for next request from client
          message = socket.recv_pyobj()
          #print (message)
          print(message)
if __name__ == '__main__':
    main()

我正在从另一个进程发送带有以下代码的请求:

def main():
    context = zmq.Context()
    socket = context.socket(zmq.REQ)
    socket.connect("tcp://localhost:{}".format(5560))
    print("sending object")
    socket.send_pyobj("ok")
    print("done")

if __name__ == '__main__':
    main()

有人知道为什么它没有到达吗?

2 个答案:

答案 0 :(得分:1)

您必须在.bind()代码段中添加REP IP地址,而不是.connect()。在REP / REQ pattern中,有请求和响应因素,因此您可以在响应者代码中抛出反馈。因此,您的代码将如下所示:

响应者:

import zmq

def main():
    context = zmq.Context()
    socket = context.socket(zmq.REP)
    socket.bind("tcp://127.0.0.1:5560")
    while True:
        message = socket.recv_pyobj()
        print(message)
        socket.send_string('Your message received.')

if __name__ == '__main__':
    main()

请求代码段:

import zmq

def main():
    context = zmq.Context()
    socket = context.socket(zmq.REQ)
    socket.connect("tcp://localhost:5560")
    print("sending object")
    socket.send_pyobj("ok")
    message = socket.recv()
    print(message)

if __name__ == '__main__':
    main()

退出(要求):

sending object
b'Your message received.'

退出(重复):

ok

[注意]:

  • 如果要发送没有任何响应的简单字符串,则使用PUSH / PULL或SUB / PUB模式代替REP / REQ更适合,并且也可以使用socket.send_string('ok')代替在请求部分使用socket.send_pyobj('ok'),在响应者中使用socket.recv()而不是socket.recv_pyobj()

  • 请注意,在.bind()情况下,请勿使用localhost字符串 Relevant Post

答案 1 :(得分:0)

  

Q 有人知道为什么它没有到达吗?

哦,我知道。

欢迎来到ZeroMQ零禅,有几个主要问题,这些问题决定着基于ZeroMQ的分布式计算系统如何以及如何工作。

如果对这个域感到陌生,可以从StackOverflow collection on ZeroMQ开始,并且愿意使用ZeroMQ或其他衍生工具( 等),请确保不要错过Pieter HINTJENS的必读书“ Code Connected。Volume 1”。

在两个地方,可能会丢失(或基本上无法传递)消息:

  • 第一个尚未完成的过程(假定已接收到消息)
  • 没有成功的.bind()(第二名)的可用资源(端口)

仅用于localhost(内部端口抽象网络为vmci://虚拟化)的严苛网络传输条件相关的问题


可固化:

def main():
    context = zmq.Context()
    socket = context.socket( zmq.REQ )
    socket.setsockopt(       zmq.LINGER,    0 )              # ALWAYS PREVENT BLOCKING
    socket.setsockopt(       zmq.IMMEDIATE, 1 )              # BLOCK UNTIL CONN-READY
    #ocket.setsockpt(        zmq.ZMQ_HANDSHAKE_IVL, ... )    # IF TWEAKING NETWORK-WIDE
    # OR:
    # a stone-age wait for the other part get started in a one-computer demo:
    # sleep( 20 )
    # :o)
    socket.connect(         "tcp://localhost:{}".format( 5560 ) )
    print(                  "Will try to dispatch an object to Context() instance" )
    socket.send_pyobj(      "ok" )
    print(                  ".send() method has returned from a blocking-call mode" )
    ...
    #--------------------------------------------------------# ALWAYS
    socket.close()                                           # ALWAYS RELEASE RESOURCES
    context.term()                                           # ALWAYS RELEASE RESOURCES
    #                                                        # ALWAYS (not all versions
    #                                                        #         have "friendly"
    #                                                        #         defeaults to rely
    #                                                        #         on others,
    #                                                        #         so be explicit)
    #--------------------------------------------------------# ALWAYS

一侧,显然不一定是REP,但由于while必须为.bind() ,因此在这里更合适,而另一侧只是.connect()到已知的连接目标:

def main():
    context = zmq.Context()
    socket = context.socket( zmq.REP )
    socket.setsockopt(       zmq.LINGER,    0 )              # ALWAYS PREVENT BLOCKING
    socket.setsockopt(       zmq.IMMEDIATE, 1 )              # BLOCK UNTIL CONN-READY
    #ocket.setsockpt(        zmq.ZMQ_HANDSHAKE_IVL, ... )    # IF TWEAKING NETWORK-WIDE
    socket.bind(            "tcp://localhost:{}".format( 5560 ) )
    print(                  ".bind() ...")
    try:
        while True:             # Wait for next request from client:
              message = socket.recv_pyobj()
              print( message )
    except:
        print( "EXC'd" )
    finally:
        #----------------------------------------------------# ALWAYS
        socket.unbind( "tcp://localhost:{}".format( 5560 ) ) # ALWAYS RELEASE PORT
        socket.close()                                       # ALWAYS RELEASE RESOURCES
        context.term()                                       # ALWAYS RELEASE RESOURCES
        #                                                    # ALWAYS (not all versions
        #                                                    #         have "friendly"
        #                                                    #         defeaults to rely
        #                                                    #         on others,
        #                                                    #         so be explicit)
        #----------------------------------------------------# ALWAYS

最后但并非最不重要的是,这将开始起作用,但由于REQ/REP-行为原型的原则可能遗漏,因此将无限期地挂起。一个必须询问(REQ.send()-s),另一个要回答的必须听问题REP.recv(),但是也必须回答... {{1} } ,然后我们才能以两步探戈的方式前进两个,而ASKER也必须让答案听 REP.send("something")

然后只有这样,ASKER才能通过另一个REQ.recv()发送另一个问题。

因此,您的发送REQ.send()部分,主要是接收REQ部分,在无限REP循环中,都必须进行修改,以便接收第二和以后的消息,即使while True:{...}-在一次射击后死亡,也从未听过REQ的任何回答的情况下。