简体   繁体   English

当我尝试处理轮询器时,NetMQ 卡住了(请求-回复模式)

[英]NetMQ gets stuck when I try to dispose the Poller (Request-Reply pattern)

This is my first project using the NetMQ (ZMQ) framework, so, maybe I didn't understand how to use it exactly.这是我第一个使用 NetMQ (ZMQ) 框架的项目,所以,也许我不明白如何准确地使用它。

I create a Windows Forms project with two applications, one send a "ping" to the other and receives a "pong" as an answer.我创建了一个带有两个应用程序的 Windows Forms 项目,一个向另一个应用程序发送“ping”并接收“pong”作为答案。 The protocol is not so complex and uses the Request-Reply pattern, all the commands have a first part that identifies the objective, like "query" or "inform", and a second part that contains the command or the message itself.该协议并不那么复杂,并且使用请求-回复模式,所有命令都有一个标识目标的第一部分,如“查询”或“通知”,第二部分包含命令或消息本身。 In this case one app send a "query-ping" and the other answer with "inform-pong".在这种情况下,一个应用程序发送一个“query-ping”,另一个应用程序发送一个“inform-pong”。

I create a class to encapsulate all the dirty job, so the main form can use the protocol in a very simple way.我创建了一个 class 来封装所有脏活,这样主窗体就可以非常简单地使用协议。 Everything is working fine, but when I try to close the app, it gets stuck in the poller and the app never closes.一切正常,但是当我尝试关闭应用程序时,它卡在轮询器中并且应用程序永远不会关闭。 In Visual Studio I can see the pause and stop button but I don't get any exception or errors:在 Visual Studio 中,我可以看到暂停和停止按钮,但没有出现任何异常或错误:

在此处输入图像描述

and when I click in pause button I get this message (The application is in break mode):当我单击暂停按钮时,我收到此消息(应用程序处于中断模式):

在此处输入图像描述

If I click in 'Continue execution' the app back to same state and never closes.如果我单击“继续执行”,应用程序将返回相同的 state 并且永远不会关闭。

If I remove the poller the app closes normally, but of course, the poller doesn't work and the app doesn't answer anymore.如果我删除轮询器,应用程序将正常关闭,但当然,轮询器不起作用,应用程序不再应答。

This is the code from the Form1:这是来自 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");
        }


    }

}

And this is the code from my NetMQ class.这是来自我的 NetMQ class 的代码。 It is in a separated library project.它位于一个单独的库项目中。 In my Dispose method I tried all combinations of Remove, Dispose and StopAsync and nothing works:在我的 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";

        }


    }
}

Place a breakpoint and see if you even get to ZmqCommunication.Dispose - that might be the issue - the form class not disposing the ZmqCommunication class.放置一个断点,看看您是否甚至到达 ZmqCommunication.Dispose - 这可能是问题所在 - 表格 class 没有处理 ZmqCommunication class。

Can you try to call NetMQConfig.Cleanup();您可以尝试调用 NetMQConfig.Cleanup(); in window close event?在 window 关闭事件中?

Thanks guys for the answers, they were not the solution but pointed me in the right direction.感谢大家的回答,他们不是解决方案,而是为我指明了正确的方向。

After a lot of debugging, I figured out it was a silly problem.经过大量调试,我发现这是一个愚蠢的问题。 I have two programs almost identical (I had both opened at the same time), one of them had the method Dispose() and the other no.我有两个几乎相同的程序(我都同时打开了),其中一个有 Dispose() 方法,另一个没有。 During the debugging, in the breaking point, I thought I was in one program but I was in the other one.在调试过程中,在断点处,我以为我在一个程序中,但我在另一个程序中。 Really silly.真的很傻。

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

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