【问题标题】:NetMQ gets stuck when I try to dispose the Poller (Request-Reply pattern)当我尝试处理轮询器时,NetMQ 卡住了(请求-回复模式)
【发布时间】:2021-10-12 07:13:52
【问题描述】:

这是我第一个使用 NetMQ (ZMQ) 框架的项目,所以,也许我不明白如何准确地使用它。

我创建了一个包含两个应用程序的 Windows 窗体项目,一个向另一个发送“ping”并接收“pong”作为答案。该协议没有那么复杂并且使用请求-回复模式,所有命令都有一个标识目标的第一部分,如“查询”或“通知”,第二部分包含命令或消息本身。在这种情况下,一个应用发送“query-ping”,另一个应用发送“inform-pong”。

我创建了一个类来封装所有的脏活,这样主窗体就可以很简单的使用协议了。一切正常,但是当我尝试关闭应用程序时,它卡在轮询器中并且应用程序永远不会关闭。在 Visual Studio 中,我可以看到暂停和停止按钮,但没有收到任何异常或错误:

当我点击暂停按钮时,我收到这条消息(应用程序处于中断模式):

如果我点击“继续执行”,应用会回到相同的状态并且永远不会关闭。

如果我删除轮询器,应用程序将正常关闭,但当然,轮询器不起作用,应用程序不再响应。

这是来自 Form1 的代码:

using CommomLib;
using System;
using System.Windows.Forms;

namespace Test1
{
    public partial class Form1 : Form
    {

        ZmqCommunication zmqComm = new ZmqCommunication();
        int portNumber;
        string status;

        public Form1()
        {
            InitializeComponent();
            
            InitializeZmqComm();
        }

        public void InitializeZmqComm()
        {
            // Calls the ZMQ initialization.
            portNumber = zmqComm.InitializeComm();
            if (portNumber == 0)
                status = "Ini error";
            else
                status = "Ini ok";
        }

        // Executes a ping command.
        private void button1_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
            richTextBox1.AppendText(zmqComm.RequestPing(55001) + "\n");
        }


    }

}

这是来自我的 NetMQ 类的代码。它位于一个单独的库项目中。在我的 Dispose 方法中,我尝试了 Remove、Dispose 和 StopAsync 的所有组合,但没有任何效果:

using NetMQ;
using NetMQ.Sockets;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;

namespace CommomLib
{
    public class ZmqCommunication
    {
        ResponseSocket serverComm = new ResponseSocket();
        NetMQPoller serverPoller;

        int _portNumber;

        public ZmqCommunication()
        {
            _portNumber = 55000;
        }

        // Problem here! The serverPoller gets stuck. 
        public void Dispose()
        {
            //serverPoller.RemoveAndDispose(serverComm);
            //serverComm.Dispose();

            if (serverPoller.IsDisposed)
                Debug.WriteLine("A");

            //serverPoller.RemoveAndDispose(serverComm);
            serverPoller.Remove(serverComm);
            //serverPoller.StopAsync();
            serverPoller.Dispose();

            serverComm.Dispose();

            if (serverPoller.IsDisposed)
                Debug.WriteLine("B");

            Thread.Sleep(500);

            if (serverPoller.IsDisposed)
                Debug.WriteLine("C");

            Thread.Sleep(500);

            if (serverPoller.IsDisposed)
                Debug.WriteLine("D");

        }

        // ZMQ initialization.
        public int InitializeComm()
        {
            bool ok = true;
            bool tryAgain = true;

            // Looks for a port.
            while (tryAgain && ok)
            {
                try
                {
                    serverComm.Bind("tcp://127.0.0.1:" + _portNumber);
                    tryAgain = false;
                }
                catch (NetMQ.AddressAlreadyInUseException)
                {
                    _portNumber++;
                    tryAgain = true;
                }
                catch
                {
                    ok = false;
                }
            }

            if (!ok)
                return 0;   // Error.


            // Set up the pooler.
            serverPoller = new NetMQPoller { serverComm };
            serverComm.ReceiveReady += (s, a) =>
                {
                    RequestInterpreter();
                };

            // start polling (on this thread)
            serverPoller.RunAsync();

            return _portNumber;
        }

        // Message interpreter.
        private void RequestInterpreter()
        {

            List<string> message = new List<string>();

            if (serverComm.TryReceiveMultipartStrings(ref message, 2))
            {
                if (message[0].Contains("query"))
                {
                    // Received the command "ping" and answers with a "pong".
                    if (message[1].Contains("ping"))
                    {
                        serverComm.SendMoreFrame("inform").SendFrame("pong");
                    }

                }
            }

        }

        // Send the command "ping".
        public string RequestPing(int port)
        {

            using (var requester = new RequestSocket())
            {
                Debug.WriteLine("Running request port {0}", port);

                requester.Connect("tcp://127.0.0.1:" + port);

                List<string> msgResp = new List<string>();

                requester.SendMoreFrame("query").SendFrame("ping");

                if (requester.TryReceiveMultipartStrings(new TimeSpan(0, 0, 10), ref msgResp, 2))
                {
                    if (msgResp[0].Contains("inform"))
                    {
                        return msgResp[1];
                    }
                }

            }

            return "error";

        }


    }
}

【问题讨论】:

    标签: c# winforms zeromq netmq


    【解决方案1】:

    你能不能尝试调用 NetMQConfig.Cleanup();在窗口关闭事件中?

    【讨论】:

      【解决方案2】:

      放置一个断点,看看你是否能到达 ZmqCommunication.Dispose - 这可能是问题 - 表单类没有释放 ZmqCommunication 类。

      【讨论】:

        【解决方案3】:

        感谢大家的回答,他们不是解决方案,而是为我指明了正确的方向。

        经过大量调试,我发现这是一个愚蠢的问题。我有两个几乎相同的程序(我都同时打开了),其中一个有 Dispose() 方法,另一个没有。在调试过程中,在断点处,我以为我在一个程序中,但我在另一个程序中。真傻。

        【讨论】:

        • 哈哈,是这样的……很高兴我能帮上忙
        猜你喜欢
        • 2013-09-14
        • 1970-01-01
        • 2015-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-05
        相关资源
        最近更新 更多