Transport Protocols
NetMQ comes with support for three main protocols
- TCP (
tcp://
) - InProc (
inproc://
) - PGM (
pgm://
) — requires MSMQ and running as administrator
Each of these is discussed below.
TCP
TCP is the most commonly used protocol. As such, most example code will use TCP.
Example
Here is another trivial example:
using (var server = new ResponseSocket()) using (var client = new RequestSocket()) { server.Bind("tcp://*:5555"); client.Connect("tcp://localhost:5555"); Console.WriteLine("Sending Hello"); client.SendFrame("Hello"); var message = server.ReceiveFrameString(); Console.WriteLine("Received {0}", message); Console.WriteLine("Sending World"); server.SendFrame("World"); message = client.ReceiveFrameString(); Console.WriteLine("Received {0}", message); }
This code outputs:
Sending Hello Received Hello Sending World Received World
Address format
Notice the format of the address string passed to Bind()
and Connect()
. For TCP connections, it will resemble:
tcp://*:5555
This is made up of three parts:
- The protocol (
tcp
) - The host (an IP address, host name, or the wildcard
*
to match any) - The port number (
5555
)
InProc
InProc (in-process) allows you to connect sockets running with the same process. This is actually quite useful, and you may do this for several reasons:
- To do away with shared state/locks. When you send data down the wire (socket) there is no shared state to worry about. Each end of the socket will have its own copy.
- Being able to communicate between very disparate parts of a system.
NetMQ comes with several components that use InProc, such the as Actor model and Devices, which are discussed in their relevant documentation pages.
Example
For now let's demonstrate a simple InProc arrangement by sending a string (for simplicity) between two threads.
using (var end1 = new PairSocket()) using (var end2 = new PairSocket()) { end1.Bind("inproc://inproc-demo"); end2.Connect("inproc://inproc-demo"); var end1Task = Task.Run(() => { Console.WriteLine("ThreadId = {0}", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Sending hello down the inproc pipeline"); end1.SendFrame("Hello"); }); var end2Task = Task.Run(() => { Console.WriteLine("ThreadId = {0}", Thread.CurrentThread.ManagedThreadId); var message = end2.ReceiveFrameString(); Console.WriteLine(message); }); Task.WaitAll(new[] { end1Task, end2Task }); }
This outputs something similar to:
ThreadId = 12 ThreadId = 6 Sending hello down the inproc pipeline Hello
Address format
Notice the format of the address string passed to Bind()
and Connect()
. For InProc connections, it will resemble:
inproc://inproc-demo
This is made up of two parts:
- The protocol (
inproc
) - The identifier (
inproc-demo
which can be any string, uniquely identified within the scope of the process)
PGM
Pragmatic General Multicast (PGM) is a reliable multicast transport protocol for applications that require ordered or unordered, duplicate-free, multicast data delivery from multiple sources to multiple receivers.
PGM guarantees that a receiver in the group either receives all data packets from transmissions and repairs, or is able to detect unrecoverable data packet loss. PGM is specifically intended as a workable solution for multicast applications with basic reliability requirements. Its central design goal is simplicity of operation with due regard for scalability and network efficiency.
To use PGM with NetMQ, we do not have to do too much. We just need to follow these three pointers:
- The socket types are now
PublisherSocket
andSubscriberSocket
which are talked about in more detail in the pub-sub pattern documentation. - Make sure you are running the app as "Administrator"
- Make sure you have turned on the "Multicasting Support". You can do that as follows:
Example
Here is a small demo that use PGM, as well as PublisherSocket
and SubscriberSocket
and a few option values.
const int MegaBit = 1024; const int MegaByte = 1024; using (var pub = new PublisherSocket()) using (var sub1 = new SubscriberSocket()) using (var sub2 = new SubscriberSocket()) { pub.Options.MulticastHops = 2; pub.Options.MulticastRate = 40 * MegaBit; // 40 megabit pub.Options.MulticastRecoveryInterval = TimeSpan.FromMinutes(10); pub.Options.SendBuffer = MegaByte * 10; // 10 megabyte pub.Connect("pgm://224.0.0.1:5555"); sub1.Options.ReceiveBuffer = MegaByte * 10; sub1.Bind("pgm://224.0.0.1:5555"); sub1.Subscribe(""); sub2.Bind("pgm://224.0.0.1:5555"); sub2.Options.ReceiveBuffer = MegaByte * 10; sub2.Subscribe(""); Console.WriteLine("Server sending 'Hi'"); pub.Send("Hi"); bool more; Console.WriteLine("sub1 received = '{0}'", sub1.ReceiveString(out more)); Console.WriteLine("sub2 received = '{0}'", sub2.ReceiveString(out more)); }
Which when run gives the following sort of output:
Server sending 'Hi' sub1 received = 'Hi' sub2 received = 'Hi'
Address format
Notice the format of the address string passed to Bind()
and Connect()
. For InProc connections, it will resemble:
pgm://224.0.0.1:5555
This is made up of three parts:
- The protocol (
pgm
) - The host (an IP address such as
244.0.0.1
, host name, or the wildcard*
to match any) - The port number (
5555
)
Another good source for PGM information is NetMQ's PGM unit tests.