ZeroMQ路由器和经销商是否必须在同一个(Python)流程中才能实现双向通信?

时间:2015-03-25 09:10:23

标签: python zeromq router

这是一个简单的req-rep服务。通常zmq.REP和zmq.REQ就足够了,但这不是我正在构建的应用程序。以下是执行客户端服务器通信的脚本。服务器在一个线程中运行。通信按预期工作。客户端发送消息,服务器接收消息,然后向客户端发送消息,客户端接收消息。

import time
from threading import Thread
import zmq

def worker_thread():
    cxt = zmq.Context.instance()
    worker = cxt.socket(zmq.DEALER)
    worker.setsockopt(zmq.IDENTITY, 'A')
    worker.connect("tcp://127.0.0.1:5559")

    for _ in range(10):
        request = worker.recv()
        print 'worker recieved'
        worker.send_multipart(['A', "data_recieved"])

cxt = zmq.Context.instance()
client = cxt.socket(zmq.ROUTER)
client.bind('tcp://127.0.0.1:5559')

Thread(target=worker_thread).start()
time.sleep(2)

for _ in range(10):
    client.send_multipart(['A', 'data'])
    request = client.recv()
    print 'worker responded'

当此代码分为两个脚本(客户端和服务器)时,通信失败。客户端发送消息,但服务器从不接收消息。代码如下:

客户端:

import time
import zmq

cxt = zmq.Context.instance()
client = cxt.socket(zmq.ROUTER)
client.bind('tcp://127.0.0.1:5559')

for _ in range(10):
    client.send_multipart(['A', 'data'])
    request = client.recv()
    print 'worker responded'

服务器:

import time
import zmq

cxt = zmq.Context.instance()
worker = cxt.socket(zmq.DEALER)
worker.setsockopt(zmq.IDENTITY, 'A')
worker.connect("tcp://127.0.0.1:5559")

for _ in range(10):
    request = worker.recv()
    print 'worker recieved'
    worker.send_multipart(['A', "data_recieved"])

我能想到的唯一原因可能是导致通信失败的原因是zmq.ROUTER和zmq.DEALER在不同的脚本中运行,因而是单独的进程。

1 个答案:

答案 0 :(得分:0)

我认为你错误地颠倒了两种套接字类型。

路由器套接字的行为类似于Rep套接字,Dealer的行为类似于Req。有关详细信息,请参阅:http://zeromq.org/tutorials:dealer-and-router

路由器和经销商是特殊的,因为它们允许异步消息传递,其中Req / Rep专门用于同步交换。我不知道为什么你的第一个脚本有效,但你应该尝试反转套接字。

这是C#中的一个例子,它在python中模仿你的。这是两个独立的过程。

流程A:

const string Endpoint = "tcp://127.0.0.1:5559";

void Main()
{
    using (var ctx = NetMQContext.Create())
    using (var worker = ctx.CreateRouterSocket())
    {
        worker.Connect(Endpoint);

        for (int i = 0; i < 10; i++)
        {
            NetMQMessage message = router.ReceiveMessage();
            Console.WriteLine("#{0}: worker received: {1}", i, string.Join(", ", message.Select(t => t.ConvertToString())));
            message.Clear();
            message.Append("A");
            message.Append("data_recieved");
            worker.SendMessage(message);
        }
    }
}

流程B:

const string Endpoint = "tcp://127.0.0.1:5559";

void Main()
{
    using (var ctx = NetMQContext.Create())
    using (var client = ctx.CreateDealerSocket())
    {
        client.Options.Identity = Encoding.ASCII.GetBytes("A");
        client.Bind(Endpoint);

        var message = new NetMQMessage();
        for (int i = 0; i < 10; i++)
        {
            message.Clear();
            message.Append("A");
            message.Append("data");
            client.SendMessage(message);
            var response = client.ReceiveMessage();
            Console.WriteLine("#{0}: worker responded", i);
        }
    }
}

输出似乎是您所期望的:

流程A:

#0: worker received: A, A, data
#1: worker received: A, A, data
#2: worker received: A, A, data
#3: worker received: A, A, data
#4: worker received: A, A, data
#5: worker received: A, A, data
#6: worker received: A, A, data
#7: worker received: A, A, data
#8: worker received: A, A, data
#9: worker received: A, A, data

流程B:

#0: worker responded
#1: worker responded
#2: worker responded
#3: worker responded
#4: worker responded
#5: worker responded
#6: worker responded
#7: worker responded
#8: worker responded
#9: worker responded

干杯