Python 如何在ZeroMQ中进行扇出?从一组主题转发到多个客户端
我需要实现一个服务器,该服务器通过控制通道(req-rep)接收指定一组主题的请求,然后作为响应发送指向将为此特定客户端打开的发布服务器套接字的URL或拒绝消息(因为权限不足) 我设法实现了一个一次只能处理一个客户机的版本(有两个无止境的循环),但我不知道使用哪种模式来同时处理多个客户机 对我来说,不同客户端的套接字保持分离是很重要的 以下是简化的代码:Python 如何在ZeroMQ中进行扇出?从一组主题转发到多个客户端,python,zeromq,Python,Zeromq,我需要实现一个服务器,该服务器通过控制通道(req-rep)接收指定一组主题的请求,然后作为响应发送指向将为此特定客户端打开的发布服务器套接字的URL或拒绝消息(因为权限不足) 我设法实现了一个一次只能处理一个客户机的版本(有两个无止境的循环),但我不知道使用哪种模式来同时处理多个客户机 对我来说,不同客户端的套接字保持分离是很重要的 以下是简化的代码: import zmq context = zmq.Context() upstream_port = 10000 upstream_hos
import zmq
context = zmq.Context()
upstream_port = 10000
upstream_host = 'localhost'
control_channel_port = 11000
upstream_addr = 'tcp://{}:{}'.format(upstream_host, upstream_port)
def should_grant(request):
'''
Permission checking - irrelevant to the question
'''
return True
def bind_downstream():
downstream = context.socket(zmq.PUB)
addr = 'tcp://*'
port = downstream.bind_to_random_port(addr)
return downstream, port
def bind_control_channel():
control_channel_sock = context.socket(zmq.REP)
control_channel_sock.bind('tcp://*:{}'.format(control_channel_port))
return control_channel_sock
def connect_upstream(topics):
raw_data = context.socket(zmq.SUB)
for t in topics:
raw_data.setsockopt_unicode(zmq.SUBSCRIBE, unicode(t))
raw_data.connect(upstream_addr)
return raw_data
if __name__ == '__main__':
print("Binding control channel socket on {}".format('tcp://*:{}'.format(control_channel_port)))
control_channel = bind_control_channel()
while True:
request = control_channel.recv_json()
print("Received request {}".format(request))
if should_grant(request):
(downstream_sock, downstream_port) = bind_downstream()
print("Downstream socket open on {}".format('tcp://*:{}'.format(downstream_port)))
print("Connecting to upstream on {}".format(upstream_addr))
upstream_sock = connect_upstream(request['topics'])
control_channel.send_json({'status': 'ok', 'port': downstream_port})
while True:
parts = upstream_sock.recv_multipart() # Simple forwarding
downstream_sock.send_multipart(parts)
else:
control_channel.send_json({'status': 'rejected'})
正确的方法是使用线程 主程序或线程将处理控制通道循环。一旦出现连接,您就可以创建上游和下游套接字,但在线程中处理实际传输。我不确定下面的代码是否有效,因为我没有一个客户机可以使用它,但请尝试一下,看看会发生什么。不过你还是会明白的
from threading import Thread
....
....
class ClientManager(Thread):
def __init__(self, ups, downs):
super(ClientManager, self).__init__(self)
self.upstream_socket = ups
self.downstream_socket = downs
def run(self):
while True:
_parts = self.upstream_socket.recv_multipart()
self.downstream_socket.send_multipart(_parts)
if __name__ == '__main__':
print("Binding control channel socket on {}".format('tcp://*:{}'.format(control_channel_port)))
control_channel = bind_control_channel()
while True:
request = control_channel.recv_json()
print("Received request {}".format(request))
if should_grant(request):
(downstream_sock, downstream_port) = bind_downstream()
print("Downstream socket open on {}".format('tcp://*:{}'.format(downstream_port)))
print("Connecting to upstream on {}".format(upstream_addr))
upstream_sock = connect_upstream(request['topics'])
control_channel.send_json({'status': 'ok', 'port': downstream_port})
_nct = ClientManager(upstream_sock, downstream_sock)
_nct.daemon = True
_nct.start()
else:
control_channel.send_json({'status': 'rejected'})
这没有按原样工作-断言“组必须为无”失败;必须使用,但否则这似乎工作的权利!它做同样的事情。我更喜欢子类化线程,但它在您的情况下没有任何区别。至少现在问题已经解决了。恕我直言,这种粗略的方法在两个方面是糟糕的/错误的——首先:ZeroMQ明确表示,它的设计在知情的情况下不是线程安全的,
Socket()
——实例的访问点不应该传递给其他线程第二:python GIL步进线程池交错执行不会产生比单一纯-[SERIAL]
代码执行更好的性能(这也可以避免“不共享”Socket()
-实例的需要)。您可能希望修改该方法,以避免设计违反已知的最佳实践。