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

标签 python multithreading sockets zeromq pyzmq

我正在尝试通过在后台线程上接收消息,同时使用控制台输入发送消息,在两个对等点之间使用 zmq.PAIR 建立一个 hello world 风格的异步通信示例:

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 会阻塞任一进程。造成这种差异的原因是什么?

socket 设置正确,刷新所有输出没有什么区别。读数本身也按预期工作,可以通过在浏览器中导航到 127.0.0.1:5556 来验证。查看 Wireshark 中的环回接口(interface)还可以发现连接已正确设置,但没有发送任何消息。

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

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

这适用于两个系统上的 Python 3.7.1、pyzmq 18.0.0 和 libzmq 4.3.1。

最佳答案

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

顺便说一句,PAIR 是一种很少使用的套接字类型,通常不用于生产或进程间通信。大多数现实世界中的 PAIR 实例都是作为线程间通信的进程内套接字。例如,PAIR 在重新连接时可能会出现奇怪的行为。使用 PUSH-PULL 进行单向通信或使用 DEALER-DEALER 进行双向通信可能会以更预期的方式表现。

关于python - 在 Windows 上,后台线程接收 zmq 消息失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55752288/

相关文章:

java CyclicBarrier 不会因重置而损坏

c - 测量udp服务器发送数据和客户端接收数据之间的延迟

python-3.x - 如何在 Python 中修复 '[Errno 98] Address already in use'

java - 为什么像获取和添加这样的原子操作会返回被更改变量的旧值?

c++ - 为什么 std::atomic 初始化不进行原子释放,以便其他线程可以看到初始化值?

Java:TCP套接字连接。客户端接收 null/readline() 返回 null

python - 如何使用具有分类特征的 RNN 的嵌入层 - RecoSys 的分类任务

python - Pandas:从数据透视表中的一列中减去另一列

Python按具有相同属性的列表中的相邻项目分组

Python-验证某个值是否在列中,并用不同列中的值替换