REQ/REP 模式中的 ZeroMQ FiniteStateMachineException [英] ZeroMQ FiniteStateMachineException in REQ/REP pattern
问题描述
我有两个简单的组件,它们应该使用 REQ/REP ZeroMQ 模式相互通信.服务器(REP Socket)使用pyzmq在Python中实现:
I have two simple components which are supposed to communicate with each other using the REQ/REP ZeroMQ pattern. The Server (REP Socket) is implemented in Python using pyzmq:
import zmq
def launch_server():
print "Launching server"
with zmq.Context.instance() as ctx:
socket = ctx.socket(zmq.REP)
socket.bind('tcp://127.0.0.1:5555')
while True:
msg = socket.recv()
print "EOM\n\n"
使用 NetMQ 库用 C# 编写的客户端(REQ 套接字):
The Client (REQ socket) written in C# using the NetMQ library:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetMQ;
namespace PyNetMQTest
{
class Program
{
static void Main(string[] args)
{
string msg;
NetMQ.Sockets.RequestSocket socket = new NetMQ.Sockets.RequestSocket();
socket.Connect("tcp://127.0.0.1:5555");
for(int i=0; i<5; i++)
socket.SendFrame("test_"+i);
}
}
}
Python 服务器实现已经过测试,并且通过与使用 Python 实现的 REQ 套接字进行通信可以正常工作.但是 C# REQ 套接字在循环的第一次迭代中抛出以下错误并且没有消息到达服务器:
The Python Server implementation has been tested and works fine by talking to a REQ socket implemented using Python. But the C# REQ socket throws the following error within the first iteration of the loop and no messages reach the Server whatsoever:
NetMQ.dll 中发生类型为NetMQ.FiniteStateMachineException"的未处理异常附加信息:Req.XSend - 无法发送另一个请求
堆栈跟踪:
at NetMQ.Core.Patterns.Req.XSend(Msg& msg)
at NetMQ.Core.SocketBase.TrySend(Msg& msg, TimeSpan timeout, Boolean more)
at NetMQ.NetMQSocket.TrySend(Msg& msg, TimeSpan timeout, Boolean more)
at NetMQ.OutgoingSocketExtensions.Send(IOutgoingSocket socket, Msg& msg, Boolean more)
at NetMQ.OutgoingSocketExtensions.SendFrame(IOutgoingSocket socket, String message, Boolean more)
at PyNetMQTest.Program.Main(String[] args) in d:\users\emes\documents\visual studio 2015\Projects\PyNetMQ Test\PyNetMQTest\Program.cs:line 20
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
这些是我使用 ZMQ 的第一步,C# 代码取自库文档.是什么让代码抛出这个错误?
These are the first my first steps with ZMQ and the C# code is taken from the library documentation. What makes the code throw this error?
我正在使用:
- pyzmq 14.7
- NetMQ 3.3.3.4
- .NET 4.6
====================== 解决方案 =======================
正如@somdoron 在他的回答中所解释的那样,可能的情况是两个套接字都需要完成发送/接收的完整周期,然后才能被重用.事实上,在 python 中实现的 REP 套接字也没有改变它的状态,所以错误出现在 python 和 C# 代码中.这是固定代码:
As explained by @somdoron in his answer, th roor casue was that both sockets need to go the full cycle of send/receive before beeing able to be reused. As a matter of fact the REP socket implemented in python did not ever change it's state either so the error was in both, the python AND the C# code. Here is the fixed code:
REP 套接字
import zmq
def launch_server():
print "Launching server"
with zmq.Context.instance() as ctx:
socket = ctx.socket(zmq.REP)
socket.bind('tcp://127.0.0.1:5555')
while True:
msg = socket.recv()
socket.send("reply to "+msg)
print "EOM\n\n"
请求套接字
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetMQ;
namespace PyNetMQTest
{
class Program
{
static void Main(string[] args)
{
NetMQ.Sockets.RequestSocket socket = new NetMQ.Sockets.RequestSocket();
socket.Connect("tcp://127.0.0.1:5555");
string msg, reply;
while (true)
{
Console.WriteLine("Type message: ");
msg = Console.ReadLine();
Console.WriteLine("Sending : " + msg);
socket.SendFrame(msg);
reply = socket.ReceiveFrameString();
Console.WriteLine("Received: " + reply + Environment.NewLine);
}
}
}
}
推荐答案
Request 和 Response 套接字是状态机,使用 Request 必须先 Send 再调用 Receive,不能连续调用 5 个 Send.
Request and Response sockets are state machines, with Request you must first Send and then call Receive, you cannot call 5 consecutive Send.
与响应相反,您必须先调用接收.
With Response its the opposite, you must call Receive first.
如果一侧仅发送而另一侧仅接收,则您可以使用推拉模式而不是 Req-Rep.如果需要双向通信,您也可以使用经销商路由器.无论如何,似乎 Req-Rep 的用法是不正确的.
If one side is only sending and the other only receiving you can use Push-Pull pattern instead of Req-Rep. You can also use Dealer-Router if needed both ways communication. Anyway it seems the usage of Req-Rep is incorrect.
这篇关于REQ/REP 模式中的 ZeroMQ FiniteStateMachineException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!