简体   繁体   English

zeromq:为什么经销商发送一条消息并从一位客户接收?

[英]zeromq: why dealer sends one message and receives from one client?

I'm trying to understand my code's behavior. 我试图了解我的代码的行为。 I'm using zeromq to create a server that sends a "ping" and waits for "pong" responses. 我正在使用zeromq创建一个服务器,该服务器发送“ ping”并等待“ pong”响应。 What i'm seeing is that when I send a ping, only one client receives it. 我看到的是,当我发送ping时,只有一个客户端收到它。 when I run this code and send "ping" for the first time i receive: 当我运行此代码并首次发送“ ping”时,我收到:

pong: A

and when i run it again, i get 当我再次运行它时,我得到

pong: B

why is that? 这是为什么? I want to send one "ping" and receive two pongs. 我想发送一个“ ping”并接收两个pong。

here's the code: 这是代码:

from threading import Thread
import zmq

class zmqdealer(object):
    def __init__(self, port):
        context = zmq.Context()
        self.sock = context.socket(zmq.DEALER)
        #self.sock.setsockopt(zmq.RCVTIMEO, 1000)
        self.sock.bind("tcp://*:%s" % port)
        thread = Thread(target=lambda: self.poll())
        thread.daemon = True
        thread.start()

    def poll(self):
        while True:
            reply = self.sock.recv()
            if reply != "":
                print(reply)

    def ping(self):
        self.sock.send_multipart(['', 'ping'])


class zmqrep(object):
    def __init__(self, ident,host, port):
        context = zmq.Context()
        self.sock = context.socket(zmq.REP)
        self.sock.connect("tcp://%s:%s" % (host, port))
        self.ident = ident
        thread = Thread(target=lambda: self.pong())
        thread.daemon = True
        thread.start()

    def pong(self):
        while True:
            request = self.sock.recv()
            if request == "ping":
                msg = "pong: %s" % self.ident
                self.sock.send(msg)


if __name__ == "__main__":
    port = 11112
    host = "localhost"
    server = zmqdealer(port)
    client1 = zmqrep('A',host,port)
    client2 = zmqrep('B',host,port)
    answer = raw_input('press <ENTER> to exit or type \'ping\' to get a pong\n')
    while True:
        if answer == "":
            break
        if answer == "ping":
            server.ping()
        answer = raw_input()

EDIT 编辑

I found a way to make this work. 我找到了一种使这项工作有效的方法。 I really hope there is another way because i genuinely hate this one! 我真的希望有另一种方式,因为我真的很讨厌这种方式! so it looks like dealer sends to the clients in a round robin fashion. 因此,看起来经销商以循环方式发送给客户。 so to make my ping work i had to send it to all the clients. 为了使ping工作有效,我必须将其发送给所有客户。 how? 怎么样? i subscribed to the monitor socket and added every connected client to a list. 我订阅了监视器套接字,并将每个连接的客户端添加到列表中。 every time i ping, i ping to every client. 每次ping时,都会对每个客户端执行ping操作。 look: 看:

import threading
import zmq
from zmq.utils import monitor

def threadify(func, daemon=True):
    thread = threading.Thread(target=func)
    thread.daemon = daemon
    thread.start()

class zmqdealer(object):

    def __init__(self, port):
        context = zmq.Context()
        self.sock = context.socket(zmq.DEALER)
        self.monitor_sock = self.sock.get_monitor_socket()
        self.sock.bind("tcp://*:%s" % port)
        self.connected_clients = {}
        threadify(func=self.poll)
        threadify(func=self.monitor)

    def poll(self):
        while True:
            reply = self.sock.recv()
            if reply != "":
                print reply


    def add_client(self, event):
        endpoint = event['endpoint']
        value = event['value']
        if endpoint in self.connected_clients:
            self.connected_clients[endpoint].append(value)
        else:
            self.connected_clients[endpoint] = [value]

    def remove_client(self, event):
        endpoint = event['endpoint']
        value = event['value']
        if endpoint in self.connected_clients \
                and value in self.connected_clients[endpoint]:
            self.connected_clients[endpoint].remove(value)

    def monitor(self):
        options = {zmq.EVENT_ACCEPTED: lambda e: self.add_client(e),
                   zmq.EVENT_DISCONNECTED: lambda e: self.remove_client(e)}
        while True:
            event = monitor.recv_monitor_message(self.monitor_sock)
            event_type = event['event']
            if event_type in options:
                options[event_type](event)

            event['event'] = event_types[event_type]
            print event

    def ping(self):
        connected_clients_amount = sum([len(clients) for clients in self.connected_clients.values()])
        for i in xrange(connected_clients_amount):
            self.sock.send_multipart(['', 'ping'])

        if connected_clients_amount <= 0:
            print "there are no connected clients!"


class zmqrep(object):
    def __init__(self, ident, host, port):
        context = zmq.Context()
        self.sock = context.socket(zmq.REP)
        self.sock.connect("tcp://%s:%s" % (host, port))
        self.identity = ident
        self.stopped = threading.Event()
        threadify(self.pong)

    def pong(self):
        while not self.stopped.isSet():
            request = self.sock.recv()
            if request == "ping":
                msg = "pong: %s" % self.identity
                self.sock.send(msg)
        self.sock.close()

    def stop(self):

        self.stopped.set()


if __name__ == "__main__":
    port = 11112
    host = "localhost"
    num = 5
    server = zmqdealer(port)
    clients = [zmqrep(i.__str__(), host, port) for i in xrange(num)]
    answer = raw_input('press <ENTER> to exit or type \'ping\' to get a pong\n')
    while True:
        if answer == "":
            break
        if answer == "ping":
            server.ping()
        if answer == "kill":
            if len(clients) > 0:
                die = clients[0]
                clients.remove(die)
                die.stop()
            else:
                print "there are no connected clients!\n"

        answer = raw_input()

Router/Dealer sockets are best used for distributing tasks. 路由器/经销商套接字最适合用于分发任务。 Say you have 10 tasks and 2 workers, you do not care who does what. 假设您有10个任务和2个工人,那么您不在乎谁在做什么。 Dealer/Router will distribute in a round robin fashion. 经销商/路由器将以循环方式分发。

Maybe Pub/Sub or Push/Pull sockets would fit your usecase better? 也许Pub / Sub或Push / Pull插槽更适合您的用例? They are both broadcast sockets. 它们都是广播套接字。

Here's an example of Push/Pull used in a similar fashion as what you're doing. 这是一个与您正在使用的方式类似的“推/拉” 示例

You often end up doing pairs of sockets, one to transmit and one other to receive results. 您通常最终会做一对套接字,一个用来传输,另一个用来接收结果。 You could for example do a PUSH with a ping message + random identifier, and ask clients to answer on PUB/SUB where you subscribe to this random identifier. 例如,您可以使用ping消息+随机标识符执行PUSH,并要求客户端在您订阅此随机标识符的PUB / SUB上进行回答。 This way you can match requests and responses. 这样,您可以匹配请求和响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM