REQ/REP模式下的ZeroMQ FiniteStateMachineException

本文关键字:ZeroMQ FiniteStateMachineException 模式 REP REQ | 更新日期: 2023-09-27 18:11:35

我有两个简单的组件,它们应该使用REQ/REP ZeroMQ模式相互通信。服务器(REP套接字)在Python中使用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套接字):

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 Server的实现已经经过测试,通过与使用Python实现的REQ套接字通信可以正常工作。但是c# REQ套接字在循环的第一次迭代中抛出以下错误,并且没有消息到达服务器:

类型为'NetMQ '的未处理异常。NetMQ.dll中发生了FiniteStateMachineException附加信息:无法发送另一个请求

异常堆栈

:

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#代码取自库文档。是什么使代码抛出这个错误?

我正在使用:

  • pyzmq 14.7
  • NetMQ 3.3.3.4
  • 。NET 4.6

====================== 解决方案 ======================

正如@somdoron在他的回答中解释的那样,根本原因是两个套接字在能够被重用之前都需要完成发送/接收的完整周期。事实上,在python中实现的REP套接字也从未改变过它的状态,所以错误存在于python和c#代码中。下面是固定的代码:

代表插座

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);
            }
        }
    }
}

REQ/REP模式下的ZeroMQ FiniteStateMachineException

请求和响应套接字都是状态机,有了请求你必须先发送然后调用接收,你不能连续调用5个发送。

与Response相反,你必须先调用Receive。

如果一方只发送,另一方只接收,你可以使用Push-Pull模式而不是Req-Rep。如果需要双向通信,也可以使用Dealer-Router。无论如何,Req-Rep的用法似乎是不正确的。