为什么绑定的SUB只接收来自连接PUB的一条消息?

时间:2015-01-02 14:47:52

标签: c# zeromq

我正在为我的ZeroMQ CLR namespace制作示例,但我的PUB / SUB有问题。

为什么我只收到第一条消息?有时我会收到没有消息,如果我通过客户端进行调试(在PubSub_Client(arg);上),我会收到某些消息。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Security.Cryptography;

using ZeroMQ;

namespace ZeroMQ.Test
{
    static partial class Program
    {
        static string PubSub_FrontendAddress = "tcp://127.0.0.1:2772";

        public static void Main(string[] args)
        {
            if (args == null || args.Length < 1)
            {
                // say here were some arguments...
                args = new string[] { "World" };
            }

            // Setup the ZContext
            context = ZContext.Create();

            CancellationTokenSource cancellor0 = null;

            {
                // Create the "Server" cancellor and threads
                cancellor0 = new CancellationTokenSource();

                var serverThread = new Thread(PubSub_Server);
                serverThread.Start(cancellor0.Token);
                serverThread.Join(64);
            }

            {
                Thread.Sleep(1000);
                Console.WriteLine("Starting...");

                // foreach arg we are the Client, asking the Server
                foreach (string arg in args)
                {
                    PubSub_Client(arg);
                    // Thread.Sleep(1000);
                }

                Console.WriteLine("Ended...");
            }

            if (cancellor0 != null)
            {
                // Cancel the Server
                cancellor0.Cancel();
            }

            // we could have done here context.Terminate()

        }
        static void PubSub_Server(object cancelluS)
        {
            var cancellus = (CancellationToken)cancelluS;

            using (var socket = ZSocket.Create(context, ZSocketType.SUB))
            {
                socket.Bind(PubSub_FrontendAddress);

                socket.SubscribeAll();

                /* var poller = ZPollItem.Create(socket, (ZSocket _socket, out ZMessage message, out ZError _error) =>
                {

                    while (null == (message = _socket.ReceiveMessage(/* ZSocketFlags.DontWait, * out _error)))
                    {
                        if (_error == ZError.EAGAIN)
                        {
                            _error = ZError.None;
                            Thread.Sleep(1);

                            continue;
                        }

                        throw new ZException(_error);
                    }

                    return true;
                }); /**/

                while (!cancellus.IsCancellationRequested)
                {
                    ZError error;
                    ZMessage request;
                    /* if (!poller.TryPollIn(out request, out error, TimeSpan.FromMilliseconds(512)))
                    {
                        if (error == ZError.EAGAIN)
                        {
                            error = ZError.None;
                            Thread.Sleep(1);

                            continue;
                        }

                        throw new ZException(error);
                    } /**/

                    if (null == (request = socket.ReceiveMessage(ZSocketFlags.DontWait, out error)))
                    {
                        if (error == ZError.EAGAIN)
                        {
                            error = ZError.None;
                            Thread.Sleep(1);

                            continue;
                        }

                        throw new ZException(error);
                    } /**/

                    foreach (ZFrame frame in request)
                    {
                        string strg = frame.ReadString();
                        Console.WriteLine("{0} said hello!", strg);
                    }
                }

                socket.Unbind(PubSub_FrontendAddress);
            }
        }
        static void PubSub_Client(string name)
        {
            using (var socket = ZSocket.Create(context, ZSocketType.PUB))
            {
                using (var crypto = new RNGCryptoServiceProvider())
                {
                    var identity = new byte[8];
                    crypto.GetBytes(identity);
                    socket.Identity = identity;
                }

                socket.Connect(PubSub_FrontendAddress);

                using (var request = new ZMessage())
                {
                    request.Add(new ZFrame(name));

                    socket.Send(request);
                }

                socket.Disconnect(PubSub_FrontendAddress);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我的设计出现问题似乎错了:

  • 单个订阅者和多个发布者是一个奇怪的选择。我相信你有充分的理由,但你应该说出那是什么。将消息从多个客户端发送到单个服务器时,通常使用DEALER / ROUTER套接字。 PUB / SUB适用于大量订阅者的一小部分发布者。

  • 连接,发送一条消息然后立即断开连接的客户端是另一个非常不寻常的用例,我希望这只是一个例子:

    • 首先,您可以接受这样的问题,即在断开连接时不会发送消息。 [我不知道你的语言绑定的默认值是什么,所以这可能是也可能不是问题,但你至少应该检查以确保它不是。]
    • 另一方面,正如您已经发现的那样,连接套接字所需的时间存在问题,如果在套接字正确连接之前发送PUB消息,可能会导致PUB消息被丢弃。

如果你坚持以这种方式使用PUB / SUB,你需要一个带外协议来在发送pub消息之前同步PUB和SUB线程。有一些如何在zeromq指南中做这个可靠的pub / sub的例子。这将涉及同一线程中的第二组套接字以发送同步消息; DEALER套接字不会丢弃消息,这就是为什么它们适用于那个目的......

但是,除非有一些尚未披露的设计要求,否则DEALER / ROUTER套接字似乎是比PUB / SUB更好的选择。

答案 1 :(得分:0)

嗯......有一个comment by Martin Sustrik:&#34;问题是连接是异步的并需要一定的时间。&#34;

现在有Thread.Sleep(64) - 它有效......:

    static void PubSub_Client(string name)
    {
        using (var socket = ZSocket.Create(context, ZSocketType.PUB))
        {
            socket.Connect(PubSub_FrontendAddress);

            Thread.Sleep(64);

            using (var request = new ZMessage())
            {
                request.Add(new ZFrame(name));

                socket.Send(request);
            }

            socket.Disconnect(PubSub_FrontendAddress);
        }
    }

您知道建立连接的更好方法吗?