在Windows上,在后台线程上接收zmq消息失败

时间:2019-04-18 19:00:32

标签: python multithreading sockets zeromq pyzmq

我试图通过在使用控制台输入发送消息的同时在后台线程上接收消息,来建立一个zmq.PAIR与两个对等方之间进行异步通信的hello世界风格示例:

server.py

import zmq
import threading

context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.bind('tcp://*:5556')

def print_incoming_messages():
    while True:
        msg = socket.recv_string()
        print(f'Message from client: {msg}')

recv_thread = threading.Thread(target=print_incoming_messages)
recv_thread.start()

while True:
    msg = input('Message to send: ')
    socket.send_string(msg)

client.py

import zmq
import threading

context = zmq.Context()
socket = context.socket(zmq.PAIR)
socket.connect('tcp://127.0.0.1:5556')

def print_incoming_messages():
    while True:
        msg = socket.recv_string()
        print(f'Message from server: {msg}')

recv_thread = threading.Thread(target=print_incoming_messages)
recv_thread.start()

while True:
    msg = input('Message to send: ')
    socket.send_string(msg)

这在Linux机器上完全可以正常工作,但是从Windows 10命令提示符运行时,socket.send_string会在任一进程中阻塞。这种差异的原因是什么?

该插座已正确设置,冲洗所有输出不会造成任何影响。读数本身也可以按预期工作,可以通过在浏览器中导航到127.0.0.1:5556进行验证。查看Wireshark中的回送接口,还可以发现连接设置正确,但没有消息发送。

但是,如果我在客户端中注释掉recv_thread.start(),则会通过Wireshark中验证的方式发送消息,这表明socket.recv_string会以某种方式阻止套接字发送,即使它不是在Linux上这样做。

我还可以通过使用两组PUSH / PULL(参见this answer)来实现所需的行为,但这并不能完全帮助解释当前示例中的情况。

这是在两个系统上的Python 3.7.1,pyzmq 18.0.0和libzmq 4.3.1上。

1 个答案:

答案 0 :(得分:2)

zmq套接字不是线程安全的,因此不应期望在不同线程的同一套接字上运行send和recv。不同平台上不同的线程行为可能是造成您所看到的行为差异的原因,但是由于zmq套接字的线程不安全性,此代码最终也可能导致段错误。使用Lock可能会解决问题。

作为旁注,PAIR是一种很少使用的套接字类型,并不经常用于生产或进程间通信。大多数PAIR的实际实例都作为用于线程间通信的Inproc套接字。例如,PAIR在重新连接时可能会有奇怪的行为。使用PUSH-PULL进行单向通信或使用DEALER-DEALER进行双向通信可能会以更预期的方式工作。