I'm trying to create a C# Winform application that uses ZeroMQ (clrzmq .net bindings (x86) via nuget) in a pub/sub model.
After much searching, I can only find standalone C# examples where the code uses a while statement to process new messages indefinitely. When I try to use these examples, I don't know where to put the code, and it just blocks the gui and everything else.
I don't know if it's impossible to do without using another thread, but I was under the impression that ZeroMQ's asynchronous behaviors could work without coding extra threads. Perhaps I just don't know where to put the zeromq code, or perhaps I really do need another thread.
If someone could provide a simple pub/sub example with directions of where to actually insert the code into a default C# winform application it would be very appreciated.
I am assuming you are using the clrzmq ZeroMq wrapper in your project. As far as I know it is not possible to receive message non-blocking in a simple loop using clrzmq, it will block either indefinitely, for a specific amount of time (by supplying a timeout to the receive method) or until you receive a message.
However, it is fairly trivial to set up a thread to poll the socket periodically and push incoming messages to onto a Queue
. You may then use for example a simple WinForms Timer
to periodically dequeue any pending messages from that (shared) Queue
. Here is a working example of a threaded subscriber:
public class ZeroMqSubscriber
{
private readonly ZmqContext _zmqContext;
private readonly ZmqSocket _zmqSocket;
private readonly Thread _workerThread;
private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false);
private readonly object _locker = new object();
private readonly Queue<string> _queue = new Queue<string>();
public ZeroMqSubscriber(string endPoint)
{
_zmqContext = ZmqContext.Create();
_zmqSocket = _zmqContext.CreateSocket(SocketType.SUB);
_zmqSocket.Connect(endPoint);
_zmqSocket.SubscribeAll();
_workerThread = new Thread(ReceiveData);
_workerThread.Start();
}
public string[] GetMessages()
{
lock (_locker)
{
var messages = _queue.ToArray();
_queue.Clear();
return messages;
}
}
public void Stop()
{
_stopEvent.Set();
_workerThread.Join();
}
private void ReceiveData()
{
try
{
while (!_stopEvent.WaitOne(0))
{
var message = _zmqSocket.Receive(Encoding.UTF8,
new TimeSpan(0, 0, 0, 1));
if (string.IsNullOrEmpty(message))
continue;
lock (_locker)
_queue.Enqueue(message);
}
}
finally
{
_zmqSocket.Dispose();
_zmqContext.Dispose();
}
}
}
From the Form
you simply poll the Queue periodically (this example uses a Forms Timer
and simply appends the message data to a Textbox
):
private readonly ZeroMqSubscriber _zeroMqSubscriber =
new ZeroMqSubscriber("tcp://127.0.0.1:5000");
void ReceiveTimerTick(object sender, EventArgs e)
{
var messages = _zeroMqSubscriber.GetMessages();
foreach (var message in messages)
_textbox.AppendText(message + Environment.NewLine);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With