private static void Main() { using (var frontend = new RouterSocket("@tcp://127.0.0.1:5559")) using (var backend = new DealerSocket("@tcp://127.0.0.1:5560")) { // Handler for messages coming in to the frontend frontend.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); backend.SendMultipartMessage(msg); // Relay this message to the backend }; // Handler for messages coming in to the backend backend.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); frontend.SendMultipartMessage(msg); // Relay this message to the frontend }; using (var poller = new NetMQPoller {backend, frontend}) { // Listen out for events on both sockets and raise events when messages come in poller.Run(); } } }
static void Main(string[] args) { SubscriberSocket socket = new SubscriberSocket(">tcp://localhost:1012"); socket.Subscribe("aaa"); socket.ReceiveReady += Socket_ReceiveReady; NetMQ.NetMQPoller poller = new NetMQ.NetMQPoller(); poller.Add(socket); poller.RunAsync(); Task.Factory.StartNew(() => { while (true) { Thread.Sleep(10 * 1000); var tmp = d; d = new List <TimeSpan>(); if (tmp.Any()) { Console.WriteLine($"{DateTime.Now}\t{tmp.Count / 10}/s\t{tmp.Average(x => x.TotalMilliseconds)}"); } else { Console.WriteLine("-"); } } }); Console.Read(); }
private void Run(PairSocket shim) { shim.ReceiveReady += OnShimReady; m_receiveSocket.ReceiveReady += OnSocketReady; m_poller = new NetMQPoller { m_receiveSocket, shim }; shim.SignalOK(); m_poller.Run(); m_receiveSocket.ReceiveReady -= OnSocketReady; }
///<summary> /// necessary indirection for the responsehandler to be used in sync or async fashion ///</summary> private XtResult SetupResponder <T, TResult>(ResponseHandler <T, TResult> handler, CancellationToken token) where T : class, new() where TResult : class { lock (concurrencyToken) { if (responderIsSetup) { throw new ZeroMqXtSocketException("Responder for this instance of Socket exists already. Use a new instance for each server!"); } responderIsSetup = true; respondingIsActive = true; } poller = new NetMQ.NetMQPoller(); responseSocket = new ResponseSocket(); // handle notifies when the server is set up eventHandle = new ManualResetEvent(false); // create a new background thread with the response callback Exception faultingException = null; _ = Task.Run(() => { try { responseSocket.Bind(_configuration.Address()); // add to poller and register handler poller.Add(responseSocket); receiveHandler = async(s, e) => await ResponseHandlerCallback(responseSocket, handler, token); responseSocket.ReceiveReady += receiveHandler; poller.RunAsync(); } catch (Exception exception) { faultingException = exception; _configuration.Logger.Log(new ErrorLogMsg(exception.GetType().Name + "-" + exception.Message)); Dispose(); } finally { // open resetevent after binding to the socket and when the poller is started eventHandle.Set(); } }, token); // wait for the Set inside the background thread so we can know at the calling client that the server is set up properly eventHandle.WaitOne(); return(faultingException == null ? XtResult.Success("setup-response") : XtResult.Failed(ZeroMqXtSocketException.FromException(faultingException), "setup-response")); }
public void ReceiveImplicitConnect_ValidScenario_ShouldReturnRequest () { const string hostAddress = "tcp://localhost:5557"; var loggingMessages = new List<string> (); // setup the counter socket for communication using (var broker = new RouterSocket ()) using (var poller = new NetMQPoller ()) using (var session = new MDPWorker (hostAddress, "test", new[] { (byte) '1' })) { broker.Bind (hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage (); // we expect to receive a 5 Frame message // [WORKER ADR][EMPTY]["MDPW01"]["READY"]["test"] if (msg.FrameCount != 5) Assert.Fail ("Message with wrong count of frames {0}", msg.FrameCount); // make sure the frames are as expected Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty)); Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01")); Assert.That (msg[3].BufferSize, Is.EqualTo (1)); Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Ready)); Assert.That (msg[4].ConvertToString (), Is.EqualTo ("test")); // tell worker to stop gracefully var reply = new NetMQMessage (); reply.Push (new[] { (byte) MDPCommand.Kill }); // push MDP Version reply.Push (msg[2]); // push separator reply.Push (NetMQFrame.Empty); // push worker address reply.Push (msg[0]); // send reply which is a request for the worker e.Socket.SendMultipartMessage (reply); }; poller.Add (broker); poller.RunAsync (); // set the event handler to receive the logging messages session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info); // initialise the worker - broker protocol session.Receive (null); Assert.That (loggingMessages.Count, Is.EqualTo (5)); Assert.That (loggingMessages[0], Is.EqualTo ("[WORKER] connected to broker at tcp://localhost:5557")); Assert.That (loggingMessages[1].Contains ("[WORKER] sending"), Is.True); Assert.That (loggingMessages[2].Contains ("[WORKER] received")); Assert.That (loggingMessages[4].Contains ("abandoning")); } }
public Task Listen() { _routerSocket = new RouterSocket(); _routerSocket.Bind($"tcp://{_options.Host}:{_options.Port}"); _routerSocket.ReceiveReady += _routerSocket_ReceiveReady; _pooler = new NetMQ.NetMQPoller(); _pooler.Add(_routerSocket); _pooler.RunAsync(); return(Task.FromResult(0)); }
/// <summary> /// setup the client with standard values /// verbose == false /// Connect the client to broker /// </summary> private MDPClientAsync() { m_client = null; m_connected = false; m_poller = new NetMQPoller(); Timeout = m_defaultTimeOut; m_timer = new NetMQTimer(Timeout); m_timer.Enable = false; m_poller.Add(m_timer); m_timer.Elapsed += (s, e) => OnProcessTimeOut(); m_poller.RunAsync(); }
public void Send_CorrectInputWithLogging_ShouldReturnCorrectReply() { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string>(); // setup the counter socket for communication using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClient(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); // we expect to receive a 4 Frame message // [client adrR][e][mdp header][service][request] if (msg.FrameCount != 5) Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount); // REQUEST socket will strip the his address + empty frame // ROUTER has to add the address prelude in order to identify the correct socket(!) // [client adr][e][mdp header][service][reply] var request = msg.Last.ConvertToString(); // get the request string msg.RemoveFrame(msg.Last); // remove the request frame msg.Append(new NetMQFrame(request + " OK")); // append the reply frame e.Socket.SendMultipartMessage(msg); }; poller.Add(broker); poller.RunAsync(); // set the event handler to receive the logging messages session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info); // well formed message var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); // correct call var reply = session.Send("echo", requestMessage); poller.Stop(); Assert.That(reply.FrameCount, Is.EqualTo(1)); Assert.That(reply.First.ConvertToString(), Is.EqualTo("REQUEST OK")); Assert.That(loggingMessages.Count, Is.EqualTo(3)); Assert.That(loggingMessages[0], Is.EqualTo("[CLIENT] connecting to broker at tcp://localhost:5555")); Assert.That(loggingMessages[1].Contains("[CLIENT INFO] sending"), Is.True); Assert.That(loggingMessages[2].Contains("[CLIENT INFO] received"), Is.True); } }
/// <summary> /// Start the server. /// </summary> public void StartServer() { if (ServerRunning) { return; } lock (_socketLock) { _socket = new RouterSocket(_connectionString); _socket.ReceiveReady += SocketReceiveReady; } _poller = new NetMQPoller { _socket }; _poller.RunAsync(); }
public void ReceiveMessageFailedIfWasNotProcessed() { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string>(); var serviceName = "echo"; Guid requestId = Guid.Empty; using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClientAsync(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { // doesn't reply to client var msg = e.Socket.ReceiveMultipartMessage(); }; session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info); session.ReplyReady += (s, e) => { Assert.IsTrue(false, "I'm not supposed to receive replies since broker is not sending them"); poller.Stop(); }; session.FailedRequest += (s, e) => { Assert.That(requestId, Is.Not.EqualTo(Guid.Empty)); Assert.That(e.RequestId, Is.EqualTo(requestId)); poller.Stop(); }; poller.Add(broker); var task = Task.Factory.StartNew(() => poller.Run()); var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); requestId = session.Send(serviceName, requestMessage); var result = task.Wait(session.Timeout + session.Timeout); Assert.IsTrue(result, $"During {session.Timeout}ms was not received a FailedReply"); } }
/// <summary> /// create worker with standard parameter /// HeartbeatDelay == 2500 milliseconds /// ReconnectDelay == 2500 milliseconds /// ConnectionRetries == 3 /// Verbose == false /// </summary> private MDPWorker() { HeartbeatDelay = TimeSpan.FromMilliseconds(2500); ReconnectDelay = TimeSpan.FromMilliseconds(2500); m_timer = new NetMQTimer(HeartbeatDelay); m_timer.Enable = false; m_timer.Elapsed += (s, e) => OnHeartbeat(); m_pollerQueue = new NetMQQueue<Action>(); m_pollerQueue.ReceiveReady += (sender, args) => { var action = args.Queue.Dequeue(); action.Invoke(); }; m_poller = new NetMQPoller(); m_poller.Add(m_pollerQueue); m_poller.Add(m_timer); m_poller.RunAsync(); }
public void Run(PairSocket shim) { m_pipe = shim; shim.SignalOK(); m_pipe.ReceiveReady += OnPipeReady; m_pingTimer = new NetMQTimer(interval: TimeSpan.Zero); m_pingTimer.Elapsed += PingElapsed; m_pingTimer.Enable = false; using (m_poller = new NetMQPoller { m_pipe, m_pingTimer }) { m_poller.Run(); } // the beacon might never been configured m_udpSocket?.Close(); }
/// <summary> /// ParanoidPirate.Queue [-v] /// /// Does load-balancing with heartbeating on worker tasks to detect /// crashed, blocked or slow running worker tasks . /// </summary> private static void Main(string[] args) { Console.Title = "NetMQ ParanoidPirate Queue"; // serves as flag for exiting the program var exit = false; // catch CTRL+C as exit command Console.CancelKeyPress += (s, e) => { e.Cancel = true; exit = true; }; var verbose = args.Length > 0 && args[0] == "-v"; using (var frontend = new RouterSocket()) using (var backend = new RouterSocket()) using (var poller = new NetMQPoller()) { frontend.Bind(Commons.QueueFrontend); backend.Bind(Commons.QueueBackend); var workers = new Workers(); // client sends to this socket frontend.ReceiveReady += (s, e) => { // only process incoming client requests // if we have workers available handle client requests as long as we have workers // storage capability of the socket otherwise and pick up later if (workers.Available) { // get all message frames! var request = frontend.ReceiveMultipartMessage(); if (verbose) Console.WriteLine("[QUEUE] received {0}", request); // get next available worker var worker = workers.Next(); // wrap message with worker's address var msg = Wrap(worker, request); if (verbose) Console.WriteLine("[QUEUE -> WORKER] sending {0}", msg); backend.SendMultipartMessage(msg); } }; // worker sends to this socket backend.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); if (verbose) Console.WriteLine("[QUEUE <- WORKER] received {0}", msg); // use workers identity for load-balancing var workerIdentity = Unwrap(msg); var worker = new Worker(workerIdentity); workers.Ready(worker); // just convenience var readableWorkerId = workerIdentity.ConvertToString(); if (msg.FrameCount == 1) { var data = msg[0].ConvertToString(); // the message is either READY or HEARTBEAT or corrupted switch (data) { case Commons.PPPHeartbeat: Console.WriteLine("[QUEUE <- WORKER] Received a Heartbeat from {0}", readableWorkerId); break; case Commons.PPPReady: Console.WriteLine("[QUEUE <- WORKER] Received a READY form {0}", readableWorkerId); break; default: Console.WriteLine("[QUEUE <- WORKER] ERROR received an invalid message!"); break; } } else { if (verbose) Console.WriteLine("[QUEUE -> CLIENT] sending {0}", msg); frontend.SendMultipartMessage(msg); } }; var timer = new NetMQTimer(Commons.HeartbeatInterval); // every specified ms QUEUE shall send a heartbeat to all connected workers timer.Elapsed += (s, e) => { // send heartbeat to every worker foreach (var worker in workers) { var heartbeat = new NetMQMessage(); heartbeat.Push(new NetMQFrame(Commons.PPPHeartbeat)); heartbeat.Push(worker.Identity); Console.WriteLine("[QUEUE -> WORKER] sending heartbeat!"); backend.SendMultipartMessage(heartbeat); } // restart timer e.Timer.Enable = true; // remove all dead or expired workers workers.Purge(); }; if (verbose) Console.WriteLine("[QUEUE] Start listening!"); poller.Add(frontend); poller.Add(backend); poller.RunAsync(); // hit CRTL+C to stop the while loop while (!exit) Thread.Sleep(100); } }
public DealerRouter() { const int delay = 3000; //Keep dealersocket reference within each three threads var clientSocketPerThread = new ThreadLocal <DealerSocket>(); using (var server = new RouterSocket("tcp://127.0.0.1:5556")) using (var poller = new NetMQPoller()) { for (int i = 0; i < 3; i++) { Task.Factory.StartNew(state => { DealerSocket client = null; if (!clientSocketPerThread.IsValueCreated) { client = new DealerSocket(); client.Options.Identity = Encoding.Unicode.GetBytes(state.ToString()); client.Connect("tcp://127.0.0.1:5556"); client.ReceiveReady += Client_ReceivedReady; clientSocketPerThread.Value = client; poller.Add(client); } else { client = clientSocketPerThread.Value; } //the dealersocket will provide an identity for message when it is created while (true) { var messageToServer = new NetMQMessage(); messageToServer.AppendEmptyFrame(); messageToServer.Append(state.ToString()); Console.WriteLine("======================================"); Console.WriteLine(" OUTGOING MESSAGE TO SERVER "); Console.WriteLine("======================================"); PrintFrames("Client Sending", messageToServer); client.SendMultipartMessage(messageToServer); Thread.Sleep(delay); } }, string.Format("client {0}", i), TaskCreationOptions.LongRunning); } poller.RunAsync(); while (true) { var clientMessage = server.ReceiveMultipartMessage(); Console.WriteLine("======================================"); Console.WriteLine(" INCOMING CLIENT MESSAGE FROM CLIENT "); Console.WriteLine("======================================"); PrintFrames("Server receiving", clientMessage); if (clientMessage.FrameCount == 3) { var clientAddress = clientMessage[0]; var clientOriginalMessage = clientMessage[2].ConvertToString(); string response = string.Format("{0} back from server {1} address {2}", clientOriginalMessage, DateTime.Now.ToLongTimeString(), clientAddress.ConvertToString()); var messageToClient = new NetMQMessage(); messageToClient.Append(clientAddress); messageToClient.AppendEmptyFrame(); messageToClient.Append(response); server.SendMultipartMessage(messageToClient); } } } }
public void Run(PairSocket shim) { m_pipe = shim; shim.SignalOK(); m_pipe.ReceiveReady += OnPipeReady; m_pingTimer = new NetMQTimer(interval: TimeSpan.Zero); m_pingTimer.Elapsed += PingElapsed; m_pingTimer.Enable = false; m_poller = new NetMQPoller { m_pipe, m_pingTimer }; m_poller.Run(); // the beacon might never been configured if (m_udpSocket != null) m_udpSocket.Close(); }
public void Receive_BrokerDisconnectedWithLogging_ShouldReturnRequest () { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string> (); // setup the counter socket for communication using (var broker = new RouterSocket ()) using (var poller = new NetMQPoller ()) using (var session = new MDPWorker (hostAddress, "test")) { broker.Bind (hostAddress); // we need to pick up any message in order to avoid errors but don't answer broker.ReceiveReady += (s, e) => e.Socket.ReceiveMultipartMessage (); poller.Add (broker); poller.RunAsync (); // speed up the test session.HeartbeatDelay = TimeSpan.FromMilliseconds (250); session.ReconnectDelay = TimeSpan.FromMilliseconds (250); // set the event handler to receive the logging messages session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info); // initialise the worker - broker protocol session.Receive (null); poller.Stop (); Assert.That (loggingMessages.Count (m => m.Contains ("retrying")), Is.EqualTo (3)); // 3 times retrying and 1 time initial connecting Assert.That (loggingMessages.Count (m => m.Contains ("localhost")), Is.EqualTo (4)); Assert.That (loggingMessages.Last ().Contains ("abandoning")); } }
private void RunActor(PairSocket shim) { // save the shim to the class to use later m_shim = shim; // create all subscriber, publisher and beacon using (m_subscriber = new SubscriberSocket()) using (m_publisher = new PublisherSocket()) using (m_beacon = new NetMQBeacon()) { // listen to actor commands m_shim.ReceiveReady += OnShimReady; // subscribe to all messages m_subscriber.Subscribe(""); // we bind to a random port, we will later publish this port // using the beacon m_randomPort = m_subscriber.BindRandomPort("tcp://*"); Console.WriteLine("Bus subscriber is bound to {0}", m_subscriber.Options.LastEndpoint); // listen to incoming messages from other publishers, forward them to the shim m_subscriber.ReceiveReady += OnSubscriberReady; // configure the beacon to listen on the broadcast port Console.WriteLine("Beacon is being configured to UDP port {0}", m_broadcastPort); m_beacon.Configure(m_broadcastPort); // publishing the random port to all other nodes Console.WriteLine("Beacon is publishing the Bus subscriber port {0}", m_randomPort); m_beacon.Publish(m_randomPort.ToString(), TimeSpan.FromSeconds(1)); // Subscribe to all beacon on the port Console.WriteLine("Beacon is subscribing to all beacons on UDP port {0}", m_broadcastPort); m_beacon.Subscribe(""); // listen to incoming beacons m_beacon.ReceiveReady += OnBeaconReady; // Create a timer to clear dead nodes NetMQTimer timer = new NetMQTimer(TimeSpan.FromSeconds(1)); timer.Elapsed += ClearDeadNodes; // Create and configure the poller with all sockets and the timer m_poller = new NetMQPoller { m_shim, m_subscriber, m_beacon, timer }; // signal the actor that we finished with configuration and // ready to work m_shim.SignalOK(); // polling until cancelled m_poller.Run(); } }
public void SendCorrectInputWithLoggingShouldReturnCorrectReply() { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string>(); var serviceName = "echo"; using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClientAsync(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); // we expect to receive a 4 Frame message // [client adrR][e][mdp header][service][request] if (msg.FrameCount != 6) Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount); // REQUEST socket will strip the his address + empty frame // ROUTER has to add the address prelude in order to identify the correct socket(!) // [client adr][e][mdp header][service][reply][requestId] var requestId = msg.Last.ConvertToString(); // get the requestId string msg.RemoveFrame(msg.Last); // remove the request frame var request = msg.Last.ConvertToString(); // get the request string msg.RemoveFrame(msg.Last); // remove the request frame msg.Append(new NetMQFrame(request + " OK")); // append the reply frame msg.Append(requestId); e.Socket.SendMultipartMessage(msg); }; session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info); session.ReplyReady += (s, e) => { var reply = e.Reply; Assert.That(reply.FrameCount, Is.EqualTo(1)); Assert.That(reply.First.ConvertToString(), Is.EqualTo("REQUEST OK")); poller.Stop(); }; int timeOutInMillis = 10000; var timer = new NetMQTimer(timeOutInMillis); // Used so it doesn't block if something goes wrong! timer.Elapsed += (s, e) => { Assert.Fail($"Waited {timeOutInMillis} and had no response from broker"); poller.Stop(); }; poller.Add(broker); poller.Add(timer); var task = Task.Factory.StartNew(() => poller.Run()); var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); session.Send(serviceName, requestMessage); task.Wait(); Assert.That(loggingMessages.Count, Is.EqualTo(3)); Assert.That(loggingMessages[0], Is.EqualTo("[CLIENT] connecting to broker at tcp://localhost:5555")); Assert.That(loggingMessages[1].Contains("[CLIENT INFO] sending"), Is.True); Assert.That(loggingMessages[2].Contains("[CLIENT INFO] received"), Is.True); } }
public void Receive_RequestWithWrongMDPComand_ShouldLogCorrectMessage () { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string> (); var first = true; // setup the counter socket for communication using (var broker = new RouterSocket ()) using (var poller = new NetMQPoller ()) using (var session = new MDPWorker (hostAddress, "test", Encoding.ASCII.GetBytes ("Worker"), 2)) { broker.Bind (hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage (); // we expect to receive a 5 Frame message // [WORKER ADR][EMPTY]["MDPW01"]["READY"]["test"] if (msg.FrameCount != 5) return; // it is a HEARTBEAT // make sure the frames are as expected Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty)); Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01")); Assert.That (msg[3].BufferSize, Is.EqualTo (1)); Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Ready)); Assert.That (msg[4].ConvertToString (), Is.EqualTo ("test")); // tell worker to stop gracefully var reply = new NetMQMessage (); if (first) { reply.Push (new[] { (byte) 0xff }); first = false; } else reply.Push (new[] { (byte) MDPCommand.Kill }); // push MDP Version reply.Push ("MDPW01"); // push separator reply.Push (NetMQFrame.Empty); // push worker address reply.Push (msg[0]); // send reply which is a request for the worker e.Socket.SendMultipartMessage (reply); }; // set the event handler to receive the logging messages session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info); poller.Add (broker); poller.RunAsync (); session.HeartbeatDelay = TimeSpan.FromMilliseconds (250); session.ReconnectDelay = TimeSpan.FromMilliseconds (250); // initialise the worker - broker protocol session.Receive (null); Assert.That (loggingMessages.Count (m => m.Contains ("[WORKER ERROR] invalid command received")), Is.EqualTo (1)); Assert.That (loggingMessages.Count (m => m.Contains ("abandoning")), Is.EqualTo (1)); } }
public void Receive_REPLYtoREQUEST_ShouldSendCorrectReply () { const string hostAddress = "tcp://localhost:5557"; var loggingMessages = new List<string> (); // setup the counter socket for communication using (var broker = new RouterSocket ()) using (var poller = new NetMQPoller ()) using (var session = new MDPWorker (hostAddress, "test", new[] { (byte) 'W', (byte) '1' })) { broker.Bind (hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage (); if (msg[3].Buffer[0] == (byte) MDPCommand.Ready) { // this is a READY message and we // send REQUEST message var request = new NetMQMessage (); request.Push ("echo test"); // [request] request.Push (NetMQFrame.Empty); // [e][request] request.Push ("C1"); // [client adr][e][request] request.Push (new[] { (byte) MDPCommand.Request }); // [command][client adr][e][request] request.Push (msg[2]); // [header][command][client adr][e][request] request.Push (NetMQFrame.Empty); // [e][header][command][client adr][e][request] request.Push (msg[0]); // [worker adr][e][header][command][client adr][e][request] // send reply which is a request for the worker e.Socket.SendMultipartMessage (request); } if (msg[3].Buffer[0] == (byte) MDPCommand.Reply) { // we expect to receive // [WORKER ADR][e]["MDPW01"][REPLY][CLIENT ADR][e][request == "echo test"] // make sure the frames are as expected Assert.That (msg[0].ConvertToString (), Is.EqualTo ("W1")); Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty)); Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01")); Assert.That (msg[3].BufferSize, Is.EqualTo (1)); Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Reply)); Assert.That (msg[4].ConvertToString (), Is.EqualTo ("C1")); Assert.That (msg[5], Is.EqualTo (NetMQFrame.Empty)); Assert.That (msg[6].ConvertToString (), Is.EqualTo ("echo test")); // tell worker to stop gracefully var reply = new NetMQMessage (); reply.Push (new[] { (byte) MDPCommand.Kill }); // push MDP Version reply.Push (msg[2]); // push separator reply.Push (NetMQFrame.Empty); // push worker address reply.Push (msg[0]); // send reply which is a request for the worker e.Socket.SendMultipartMessage (reply); } }; poller.Add (broker); poller.RunAsync (); // set the event handler to receive the logging messages session.LogInfoReady += (s, e) => loggingMessages.Add (e.Info); // initialise the worker - broker protocol // and get initial request var workerRequest = session.Receive (null); // just echo the request session.Receive (workerRequest); poller.Stop (); Assert.That (loggingMessages.Count, Is.EqualTo (8)); Assert.That (loggingMessages[0], Is.EqualTo ("[WORKER] connected to broker at tcp://localhost:5557")); Assert.That (loggingMessages[1].Contains ("Ready")); Assert.That (loggingMessages[2].Contains ("[WORKER] received")); Assert.That (loggingMessages[3].Contains ("Request")); Assert.That (loggingMessages[4].Contains ("Reply")); Assert.That (loggingMessages[6].Contains ("Kill")); Assert.That (loggingMessages[7].Contains ("abandoning")); } }
public void Send_WrongHeaderFromBrokerNoLogging_ShouldThrowApplicationException() { const string hostAddress = "tcp://localhost:5555"; // setup the counter socket for communication using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClient(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { // return empty reply var msg = e.Socket.ReceiveMultipartMessage(); // we expect to receive a 4 Frame message // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"] if (msg.FrameCount != 5) Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount); // REQUEST socket will strip the his address + empty frame // ROUTER has to add the address prelude in order to identify the correct socket(!) // [REQ ADR][EMPTY]["MDPC00"]["echo"]["REQUEST"] var clientAddress = msg.Pop(); msg.Pop(); // forget empty frame var mdpVersion = msg.Pop(); msg.Pop(); // drop service name version msg.Push("NoService"); msg.Push(mdpVersion); msg.Push(NetMQFrame.Empty); msg.Push(clientAddress); // reinsert the client's address e.Socket.SendMultipartMessage(msg); }; poller.Add(broker); poller.RunAsync(); // well formed message var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); try { session.Send("echo", requestMessage); } catch (ApplicationException ex) { Assert.That(ex.Message, Is.EqualTo("[CLIENT INFO] answered by wrong service: NoService")); } } }
public NetMQSynchronizationContext(NetMQPoller poller) { m_poller = poller; }
public void SendEmptyReplyFromBrokerWithLoggingShouldThrowApplicationException() { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string>(); // setup the counter socket for communication using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClientAsync(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { // return empty reply var msg = e.Socket.ReceiveMultipartMessage(); // we expect to receive a 4 Frame message // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"][requestId] if (msg.FrameCount != 6) Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount); // REQUEST socket will strip the his address + empty frame // ROUTER has to add the address prelude in order to identify the correct socket(!) // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"][requestId] e.Socket.SendMultipartMessage(msg); }; session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info); session.ReplyReady += (s, e) => { Assert.That(loggingMessages.Count, Is.EqualTo(3)); Assert.That(loggingMessages[0], Is.EqualTo("[CLIENT] connecting to broker at tcp://localhost:5555")); Assert.That(loggingMessages[1].Contains("[CLIENT INFO] sending"), Is.True); Assert.That(loggingMessages[2].Contains("[CLIENT INFO] received"), Is.True); poller.Stop(); // To unlock the Task.Wait() }; poller.Add(broker); var task = Task.Factory.StartNew(() => poller.Run()); // well formed message var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); // correct call session.Send("echo", requestMessage); int timeOutInMillis = 10000; var timer = new NetMQTimer(timeOutInMillis); // Used so it doesn't block if something goes wrong! timer.Elapsed += (s, e) => { Assert.Fail($"Waited {timeOutInMillis} and had no response from broker"); poller.Stop(); }; poller.Add(timer); task.Wait(); } }
/// <summary> /// run the broker - if not bound to endpoint automatically binds to known endpoint /// </summary> /// <param name="token">CancellationToken to cancel the method</param> /// <exception cref="InvalidOperationException">Can't start same broker more than once!</exception> public void RunSynchronous (CancellationToken token) { if (m_isRunning) throw new InvalidOperationException ("Can't start same broker more than once!"); if (!m_isBound) Bind (); m_isRunning = true; using (var poller = new NetMQPoller ()) { Socket.ReceiveReady += ProcessReceivedMessage; // get timer for scheduling heartbeat var timer = new NetMQTimer (HeartbeatInterval); // send every 'HeartbeatInterval' a heartbeat to all not expired workers timer.Elapsed += (s, e) => SendHeartbeat (); poller.Add (Socket); poller.Add (timer); Log ("Starting to listen for incoming messages ..."); // start the poller and wait for the return, which will happen once token is // signalling Cancel(!) Task.Factory.StartNew (poller.Run, token).Wait (); Log ("... Stopped!"); // clean up poller.Remove (timer); poller.Remove (Socket); // unregister event handler Socket.ReceiveReady -= ProcessReceivedMessage; } m_isRunning = false; }
/// <summary> /// Starts the server. /// </summary> public void StartServer() { if (ServerRunning) { return; } lock (_publisherSocketLock) { _publisherSocket = new PublisherSocket(_publisherConnectionString); } lock (_requestSocketLock) { _requestSocket = new ResponseSocket(_requestConnectionString); _requestSocket.ReceiveReady += RequestSocketReceiveReady; } _poller = new NetMQPoller { _requestSocket }; _poller.RunAsync(); }
public void ReconnectToBrokerIfIsNotReplying() { const string hostAddress = "tcp://localhost:5555"; const int timeOutToReconnectInMillis = 7500; var loggingMessages = new List<string>(); var serviceName = "echo"; var messagesReceivedOnBroker = 0; // setup the counter socket for communication using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClientAsync(hostAddress)) { session.Timeout = TimeSpan.FromMilliseconds(timeOutToReconnectInMillis); broker.Bind(hostAddress); broker.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); if (messagesReceivedOnBroker != 0) // doesn't respond if is the first message received! { // we expect to receive a 4 Frame message // [client adrR][e][mdp header][service][request] if (msg.FrameCount != 6) Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount); // REQUEST socket will strip the his address + empty frame // ROUTER has to add the address prelude in order to identify the correct socket(!) var requestId = msg.Last.ConvertToString(); // get the requestId string msg.RemoveFrame(msg.Last); // remove the request frame var request = msg.Last.ConvertToString(); // get the request string msg.RemoveFrame(msg.Last); // remove the request frame msg.Append(new NetMQFrame(request + " OK")); // append the reply frame msg.Append(requestId); e.Socket.SendMultipartMessage(msg); } messagesReceivedOnBroker++; }; session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info); session.ReplyReady += (s, e) => { var reply = e.Reply; Assert.That(reply.FrameCount, Is.EqualTo(1)); Assert.That(reply.First.ConvertToString(), Is.EqualTo("REQUEST OK")); poller.Stop(); }; var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); int timeOutInMillis = timeOutToReconnectInMillis + 3000; // Waits for the timeOut on the client var timer = new NetMQTimer(timeOutInMillis); timer.Elapsed += (s, e) => { session.Send(serviceName, requestMessage); // resends the request after timeout }; poller.Add(timer); poller.Add(broker); var task = Task.Factory.StartNew(() => poller.Run()); session.Send(serviceName, requestMessage); var result = task.Wait(timeOutToReconnectInMillis * 2); var numberOfConnects = loggingMessages.FindAll(x => x.Contains("[CLIENT] connecting to broker")).Count; Assert.IsTrue(numberOfConnects > 1); } }
public void SendWrongMDPVersionFromBrokerNoLoggingShouldThrowApplicationException() { const string hostAddress = "tcp://localhost:5555"; // setup the counter socket for communication using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClientAsync(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { // return empty reply var msg = e.Socket.ReceiveMultipartMessage(); // we expect to receive a 4 Frame message // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"][requestId] if (msg.FrameCount != 6) Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount); // REQUEST socket will strip the his address + empty frame // ROUTER has to add the address prelude in order to identify the correct socket(!) // [REQ ADR][EMPTY]["MDPC00"]["echo"]["REQUEST"][requestId] var clientAddress = msg.Pop(); msg.Pop(); // forget empty frame msg.Pop(); // drop the MDP Version Frame msg.Push("MDPC00"); // insert wrong MDP version msg.Push(NetMQFrame.Empty); msg.Push(clientAddress); // reinsert the client's address e.Socket.SendMultipartMessage(msg); }; int timeOutInMillis = 10000; var timer = new NetMQTimer(timeOutInMillis); // Used so it doesn't block if something goes wrong! timer.Elapsed += (s, e) => { Assert.Fail($"Waited {timeOutInMillis} and had no response from broker"); poller.Stop(); }; poller.Add(broker); poller.Add(timer); session.ReplyReady += (s, e) => { Assert.True(e.HasError()); Assert.That(e.Exception.Message, Is.StringContaining("MDP Version mismatch")); poller.Stop(); // To unlock the Task.Wait() }; session.FailedRequest += (s, e) => { Assert.True(e.HasError()); Assert.That(e.Exception.Message, Is.StringContaining("MDP Version mismatch")); poller.Stop(); // To unlock the Task.Wait() }; var task = Task.Factory.StartNew(() => poller.Run()); var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); session.Send("echo", requestMessage); task.Wait(); } }
/// <summary> /// the broker setting up the cluster /// /// /// State 2 ---+ +--- State n /// | | /// +----+----+ /// client 1 ---| | |--- worker 1 /// client 2 ---+---- BROKER 1 ----+--- worker 2 /// : | | | : /// client n ---+ +----+----+ +--- worker n /// | | /// BROKER 2 BROKER n /// /// BROKER 2 and n are not included and must be setup separately /// /// A minimum of two address must be supplied /// </summary> /// <param name="args">[0] = this broker's address /// [1] = 1st peer's address /// : /// [n] = nth peer address</param> /// <remarks> /// since "inproc://" is not working in NetMQ we use "tcp://" /// for each broker we need 5 ports which for this example are /// assigned as follows (in true life it should be configurable whether /// they are ports or tcp/ip addresses) /// /// this brokers address => local frontend binds to tcp://127.0.0.1:5555 /// cloud frontend binds to :5556 /// local backend binds to :5557 /// state backend binds to :5558 /// monitor PULL binds to :5559 /// /// the sockets are connected as follows /// /// this broker's monitor PUSH connects to tcp://127.0.0.1:5559 /// /// (if peer's address and port is tcp://127.0.0.1:5575) /// /// this broker's cloud backend connects to :5576 /// this broker's state frontend connects to :5578 /// /// this scheme is fix in this example /// </remarks> public static void Main(string[] args) { Console.Title = "NetMQ Inter-Broker Router"; const string baseAddress = "tcp://127.0.0.1:"; if (args.Length < 2) { Console.WriteLine("usage: program me peer1 [peer]*"); Console.WriteLine("each broker needs 5 port for his sockets!"); Console.WriteLine("place enough distance between multiple broker addresses!"); Environment.Exit(-1); } // trapping Ctrl+C as exit signal! Console.CancelKeyPress += (s, e) => { e.Cancel = true; s_keepRunning = false; }; // get random generator for later use var rnd = new Random(); // get list for registering the clients var clients = new List<byte[]>(NbrClients); // get a list of peer addresses var peers = new List<byte[]>(); // get all peer addresses - first is this broker! for (var i = 1; i < args.Length; i++) peers.Add(Encoding.UTF8.GetBytes(args[i])); // build this broker's address var me = baseAddress + args[0]; // get the port as integer for later use var myPort = int.Parse(args[0]); Console.WriteLine("[BROKER] The broker can be stopped by using CTRL+C!"); Console.WriteLine("[BROKER] setting up sockets ..."); // set up all the addresses needed in the due course var localFrontendAddress = me; var cloudFrontendAddress = baseAddress + (myPort + 1); var localBackendAddress = baseAddress + (myPort + 2); var stateBackendAddress = baseAddress + (myPort + 3); var monitorAddress = baseAddress + (myPort + 4); // create the context and all the sockets using (var localFrontend = new RouterSocket()) using (var localBackend = new RouterSocket()) using (var cloudFrontend = new RouterSocket()) using (var cloudBackend = new RouterSocket()) using (var stateBackend = new PublisherSocket()) using (var stateFrontend = new SubscriberSocket()) using (var monitor = new PullSocket()) { // give every socket an unique identity, e.g. LocalFrontend[Port] SetIdentities(myPort, localFrontend, cloudFrontend, localBackend, stateBackend, monitor, cloudBackend, stateFrontend); // subscribe to any message on the stateFrontend socket! stateFrontend.Subscribe(""); // bind the serving sockets localFrontend.Bind(localFrontendAddress); cloudFrontend.Bind(cloudFrontendAddress); localBackend.Bind(localBackendAddress); stateBackend.Bind(stateBackendAddress); monitor.Bind(monitorAddress); // connect sockets to peers for (var i = 1; i < args.Length; i++) { // build the cloud back end address var peerPort = int.Parse(args[i]); var address = baseAddress + (peerPort + 1); Console.WriteLine("[BROKER] connect to cloud peer {0}", address); // this cloudBackend connects to all peer cloudFrontends cloudBackend.Connect(address); // build the state front end address address = baseAddress + (peerPort + 3); Console.WriteLine("[BROKER] subscribe to state peer {0}", address); // this stateFrontend to all peer stateBackends stateFrontend.Connect(address); } // setup the local worker queue for LRU and monitor cloud capacity var workerQueue = new Queue<byte[]>(); int previousLocalCapacity = 0; // receive the capacity available from other peer(s) stateFrontend.ReceiveReady += (s, e) => { // the message should contain the available cloud capacity var capacity = e.Socket.ReceiveFrameString(); Debug.Assert(string.IsNullOrWhiteSpace(capacity), "StateFrontend: message was empty!"); int couldCapacity; Debug.Assert(int.TryParse(capacity, out couldCapacity), "StateFrontend: message did not contain a number!"); }; // get the status message and print it monitor.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveFrameString(); Console.WriteLine("[MONITOR] {0}", msg); }; // all local clients are connecting to this socket // they send a REQ and get a REPLY localFrontend.ReceiveReady += (s, e) => { // [client adr][empty][message id] var request = e.Socket.ReceiveMultipartMessage(); // register the local client for later identification if not known if (!clients.Any(n => AreSame(n, request[0]))) clients.Add(request[0].Buffer); // if we have local capacity send worker else send to cloud if (workerQueue.Count > 0) { // get the LRU worker adr var worker = workerQueue.Dequeue(); // wrap message with workers address var msg = Wrap(worker, request); // send message to the worker // [worker adr][empty][client adr][empty][data] localBackend.SendMultipartMessage(msg); } else { // get an random index for peers var peerIdx = rnd.Next(peers.Count - 2) + 2; // get peers address var peer = peers[peerIdx]; // wrap message with peer's address var msg = Wrap(peer, request); // [peer adr][empty][client adr][empty][data] cloudBackend.SendMultipartMessage(msg); } }; // the workers are connected to this socket // we get a REPLY either for a cloud client [worker adr][empty][peer adr][empty][peer client adr][empty][data] // or local client [worker adr][empty][client adr][empty][data] // or a READY message [worker adr][empty][WORKER_READY] localBackend.ReceiveReady += (s, e) => { // a worker can send "READY" or a request // or an REPLAY var msg = e.Socket.ReceiveMultipartMessage(); // just to make sure we received a proper message Debug.Assert(msg != null && msg.FrameCount > 0, "[LocalBackend] message was empty or frame count == 0!"); // get the workers identity var id = Unwrap(msg); // this worker done in either way so add it to available workers workerQueue.Enqueue(id); // if it is NOT a ready message we need to route the message // it could be a reply to a peer or a local client // [WORKER_READY] or [client adr][empty][data] or [peer adr][empty][peer client adr][empty][data] if (msg[0].Buffer[0] != WorkerReady) { Debug.Assert(msg.FrameCount > 2, "[LocalBackend] None READY message malformed"); // if the adr (first frame) is any of the clients send the REPLY there // and send it to the peer otherwise if (clients.Any(n => AreSame(n, msg.First))) localFrontend.SendMultipartMessage(msg); else cloudFrontend.SendMultipartMessage(msg); } }; // this socket is connected to all peers // we receive either a REQ or a REPLY form a peer // REQ [peer adr][empty][peer client adr][empty][message id] -> send to peer for processing // REP [peer adr][empty][client adr][empty][message id] -> send to local client cloudBackend.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); // just to make sure we received a message Debug.Assert(msg != null && msg.FrameCount > 0, "[CloudBackend] message was empty or frame count == 0!"); // we need the peers address for proper addressing var peerAdr = Unwrap(msg); // the remaining message must be at least 3 frames! Debug.Assert(msg.FrameCount > 2, "[CloudBackend] message malformed"); // if the id is any of the local clients it is a REPLY // and a REQ otherwise if (clients.Any(n => AreSame(n, msg.First))) { // [client adr][empty][message id] localFrontend.SendMultipartMessage(msg); } else { // add the peers address to the request var request = Wrap(peerAdr, msg); // [peer adr][empty][peer client adr][empty][message id] cloudFrontend.SendMultipartMessage(request); } }; // all peers are binding to this socket // we receive REPLY or REQ from peers // REQ [peer adr][empty][peer client adr][empty][data] -> send to local worker for processing // REP [peer adr][empty][client adr][empty][data] -> send to local client cloudFrontend.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage(); // just to make sure we received a message Debug.Assert(msg != null && msg.FrameCount > 0, "[CloudFrontend] message was empty or frame count == 0!"); // we may need the peers address for proper addressing var peerAdr = Unwrap(msg); // the remaining message must be at least 3 frames! Debug.Assert(msg.FrameCount > 2, "[CloudFrontend] message malformed"); // if the address is any of the local clients it is a REPLY // and a REQ otherwise if (clients.Any(n => AreSame(n, msg.First))) localFrontend.SendMultipartMessage(msg); else { // in order to know which per to send back the peers adr must be added again var original = Wrap(peerAdr, msg); // reduce the capacity to reflect the use of a worker by a cloud request previousLocalCapacity = workerQueue.Count; // get the LRU worker var workerAdr = workerQueue.Dequeue(); // wrap the message with the worker address and send var request = Wrap(workerAdr, original); localBackend.SendMultipartMessage(request); } }; // in order to reduce chatter we only check to see if we have local capacity to provide to cloud // periodically every 2 seconds with a timer var timer = new NetMQTimer((int)TimeSpan.FromSeconds(2).TotalMilliseconds); timer.Elapsed += (t, e) => { // send message only if the previous send information changed if (previousLocalCapacity != workerQueue.Count) { // set the information previousLocalCapacity = workerQueue.Count; // generate the message var msg = new NetMQMessage(); var data = new NetMQFrame(previousLocalCapacity.ToString()); msg.Append(data); var stateMessage = Wrap(Encoding.UTF8.GetBytes(me), msg); // publish info stateBackend.SendMultipartMessage(stateMessage); } // restart the timer e.Timer.Enable = true; }; // start all clients and workers as threads var clientTasks = new Thread[NbrClients]; var workerTasks = new Thread[NbrWorker]; for (var i = 0; i < NbrClients; i++) { var client = new Client(localFrontendAddress, monitorAddress, (byte)i); clientTasks[i] = new Thread(client.Run) { Name = string.Format("Client_{0}", i) }; clientTasks[i].Start(); } for (var i = 0; i < NbrWorker; i++) { var worker = new Worker(localBackendAddress, (byte)i); workerTasks[i] = new Thread(worker.Run) { Name = string.Format("Worker_{0}", i) }; workerTasks[i].Start(); } // create poller and add sockets & timer var poller = new NetMQPoller { localFrontend, localBackend, cloudFrontend, cloudBackend, stateFrontend, stateBackend, monitor, timer }; // start monitoring the sockets poller.RunAsync(); // we wait for a CTRL+C to exit while (s_keepRunning) Thread.Sleep(100); Console.WriteLine("Ctrl-C encountered! Exiting the program!"); if (poller.IsRunning) poller.Stop(); poller.Dispose(); } }
public void Run(PairSocket shim) { m_pipe = shim; shim.SignalOK(); m_pipe.ReceiveReady += OnPipeReady; m_pingTimer = new NetMQTimer(interval: TimeSpan.Zero); m_pingTimer.Elapsed += PingElapsed; m_pingTimer.Enable = false; using (m_poller = new NetMQPoller { m_pipe, m_pingTimer }) { m_poller.Run(); } // the beacon might never been configured #if NET35 m_udpSocket?.Close(); #else m_udpSocket?.Dispose(); #endif }
/// <summary> /// Stop the server. /// </summary> public void StopServer() { if (!ServerRunning) { return; } _poller?.Stop(); _poller?.Dispose(); lock (_socketLock) { if (_socket != null) { try { _socket.Disconnect(_connectionString); } finally { _socket.ReceiveReady -= SocketReceiveReady; _socket.Close(); _socket = null; } } } _poller = null; }
public void Run() { Console.WriteLine("[CLIENT {0}] Starting", m_id); var rnd = new Random(m_id); // each request shall have an unique id in order to recognize an reply for a request var messageId = new byte[5]; // create clientId for messages var clientId = new[] { m_id }; // a flag to signal that an answer has arrived bool messageAnswered = false; // we use a poller because we have a socket and a timer to monitor using (var clientPoller = new NetMQPoller()) using (var client = new RequestSocket()) using (var monitor = new PushSocket()) { client.Connect(m_localFrontendAddress); monitor.Connect(m_monitorAddress); client.Options.Identity = new[] { m_id }; var timer = new NetMQTimer((int)TimeSpan.FromSeconds(10).TotalMilliseconds); // use as flag to indicate exit var exit = false; // every 10 s check if message has been received, if not then send error message and ext // and restart timer otherwise timer.Elapsed += (s, e) => { if (messageAnswered) { e.Timer.Enable = true; } else { var msg = string.Format("[CLIENT {0}] ERR - EXIT - lost message {1}", m_id, messageId); // send an error message monitor.SendFrame(msg); // if poller is started than stop it if (clientPoller.IsRunning) clientPoller.Stop(); // mark the required exit exit = true; } }; // process arriving answers client.ReceiveReady += (s, e) => { // mark the arrival of an answer messageAnswered = true; // worker is supposed to answer with our request id var reply = e.Socket.ReceiveMultipartMessage(); if (reply.FrameCount == 0) { // something went wrong monitor.SendFrame(string.Format("[CLIENT {0}] Received an empty message!", m_id)); // mark the exit flag to ensure the exit exit = true; } else { var sb = new StringBuilder(); // create success message foreach (var frame in reply) sb.Append("[" + frame.ConvertToString() + "]"); // send the success message monitor.SendFrame(string.Format("[CLIENT {0}] Received answer {1}", m_id, sb.ToString())); } }; // add socket & timer to poller clientPoller.Add(client); clientPoller.Add(timer); // start poller in another thread to allow the continued processing clientPoller.RunAsync(); // if true the message has been answered // the 0th message is always answered messageAnswered = true; while (!exit) { // simulate sporadic activity by randomly delaying Thread.Sleep((int)TimeSpan.FromSeconds(rnd.Next(5)).TotalMilliseconds); // only send next message if the previous one has been replied to if (messageAnswered) { // generate random 5 byte as identity for for the message rnd.NextBytes(messageId); messageAnswered = false; // create message [client adr][empty][message id] and send it var msg = new NetMQMessage(); msg.Push(messageId); msg.Push(NetMQFrame.Empty); msg.Push(clientId); client.SendMultipartMessage(msg); } } // stop poller if needed if (clientPoller.IsRunning) clientPoller.Stop(); } }
/// <summary> /// setup the client with standard values /// verbose == false /// Connect the client to broker /// </summary> private MDPClientAsync() { m_client = null; m_connected = false; m_currentBrokerIndex = -1; // TODO use random!? m_pollerQueue = new NetMQQueue<Action>(); m_pollerQueue.ReceiveReady += (sender, args) => OnAction(args); m_requestQueue = new RequestsQueue(); m_requestQueue.FailedRequest += (s, e) => OnFailedRequest(e); m_poller = new NetMQPoller(); Timeout = m_defaultTimeOut; m_timer = new NetMQTimer(m_purgeCheckTime); m_timer.Enable = false; m_timer.Elapsed += (s, e) => OnPurgeRequest(); m_poller.Add(m_timer); m_poller.Add(m_pollerQueue); m_poller.Add(m_timer); m_poller.RunAsync(); }
public void Send_EmptyReplyFromBrokerWithLogging_ShouldThrowApplicationException() { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string>(); // setup the counter socket for communication using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClient(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { // return empty reply var msg = e.Socket.ReceiveMultipartMessage(); // we expect to receive a 4 Frame message // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"] if (msg.FrameCount != 5) Assert.Fail("Message with wrong count of frames {0}", msg.FrameCount); // REQUEST socket will strip the his address + empty frame // ROUTER has to add the address prelude in order to identify the correct socket(!) // [REQ ADR][EMPTY]["MDPC01"]["echo"]["REQUEST"] e.Socket.SendMultipartMessage(msg); }; poller.Add(broker); poller.RunAsync(); // set the event handler to receive the logging messages session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info); // well formed message var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); // correct call session.Send("echo", requestMessage); poller.Stop(); Assert.That(loggingMessages.Count, Is.EqualTo(3)); Assert.That(loggingMessages[0], Is.EqualTo("[CLIENT] connecting to broker at tcp://localhost:5555")); Assert.That(loggingMessages[1].Contains("[CLIENT INFO] sending"), Is.True); Assert.That(loggingMessages[2].Contains("[CLIENT INFO] received"), Is.True); } }
public void Send_WrongServiceNameWithLogging_ShouldLogPermanentError() { const string hostAddress = "tcp://localhost:5555"; var loggingMessages = new List<string>(); // setup the counter socket for communication using (var broker = new RouterSocket()) using (var poller = new NetMQPoller()) using (var session = new MDPClient(hostAddress)) { broker.Bind(hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { // just swallow message -> wrong service name e.Socket.ReceiveMultipartMessage(); }; poller.Add(broker); poller.RunAsync(); // set the event handler to receive the logging messages session.LogInfoReady += (s, e) => loggingMessages.Add(e.Info); // well formed message var requestMessage = new NetMQMessage(new[] { new NetMQFrame("REQUEST") }); // wrong service name session.Send("xyz", requestMessage); poller.Stop(); Assert.That(loggingMessages.Count, Is.EqualTo(7)); Assert.That(loggingMessages[6], Is.EqualTo("[CLIENT ERROR] permanent error, abandoning!")); } }
public void Receive_RequestWithTooLittleFrames_ShouldThrowApplicationException () { const string hostAddress = "tcp://localhost:5555"; // setup the counter socket for communication using (var broker = new RouterSocket ()) using (var poller = new NetMQPoller ()) using (var session = new MDPWorker (hostAddress, "test")) { broker.Bind (hostAddress); // we need to pick up any message in order to avoid errors broker.ReceiveReady += (s, e) => { var msg = e.Socket.ReceiveMultipartMessage (); // we expect to receive a 5 Frame message // [WORKER ADR][EMPTY]["MDPW01"]["READY"]["test"] if (msg.FrameCount != 5) Assert.Fail ("Message with wrong count of frames {0}", msg.FrameCount); // make sure the frames are as expected Assert.That (msg[1], Is.EqualTo (NetMQFrame.Empty)); Assert.That (msg[2].ConvertToString (), Is.EqualTo ("MDPW01")); Assert.That (msg[3].BufferSize, Is.EqualTo (1)); Assert.That (msg[3].Buffer[0], Is.EqualTo ((byte) MDPCommand.Ready)); Assert.That (msg[4].ConvertToString (), Is.EqualTo ("test")); // tell worker to stop gracefully var reply = new NetMQMessage (); reply.Push (new[] { (byte) MDPCommand.Kill }); // push separator reply.Push (NetMQFrame.Empty); // push worker address reply.Push (msg[0]); // send reply which is a request for the worker e.Socket.SendMultipartMessage (reply); }; poller.Add (broker); poller.RunAsync (); try { session.Receive (null); } catch (ApplicationException ex) { Assert.That (ex.Message, Is.EqualTo ("Malformed request received!")); } } }