// // Load-balancing broker in C# // // Clients and workers are shown here in-process. // While this example runs in a single process, that is just to make // it easier to start and stop the example. Each thread may have its own // context and conceptually acts as a separate process. // // Author: metadings // // Basic request-reply client using REQ socket static void LBBroker_Client(ZContext context, int i) { // Create a socket using (var client = new ZSocket(context, ZSocketType.REQ)) { // Set a printable identity client.IdentityString = "CLIENT" + i; // Connect client.Connect("inproc://frontend"); using (var request = new ZMessage()) { request.Add(new ZFrame("Hello")); // Send request client.Send(request); } // Receive reply using (ZMessage reply = client.ReceiveMessage()) { reply.DumpZmsg("---Client received from broker---"); Console.WriteLine("CLIENT{0}: {1}", i, reply[0].ReadString()); } } }
public void SendToBroker(string command, string option, ZMessage msg) { using (msg = msg != null ? msg.Duplicate() : new ZMessage()) { if (!string.IsNullOrEmpty(option)) msg.Prepend(new ZFrame(option)); msg.Prepend(new ZFrame(command)); msg.Prepend(new ZFrame(MdpCommon.MDPW_WORKER)); msg.Prepend(new ZFrame(string.Empty)); if (Verbose) msg.DumpZmsg("I: sending '{0:X}|{0}' to broker", command.ToMdCmd()); Worker.Send(msg); } }
public void SendToBroker(string command, string option, ZMessage msg) { using (msg = msg != null ? msg.Duplicate() : new ZMessage()) { if (!string.IsNullOrEmpty(option)) { msg.Prepend(new ZFrame(option)); } msg.Prepend(new ZFrame(command)); msg.Prepend(new ZFrame(MdpCommon.MDPW_WORKER)); msg.Prepend(new ZFrame(string.Empty)); if (Verbose) { msg.DumpZmsg("I: sending '{0:X}|{0}' to broker", command.ToMdCmd()); } Worker.Send(msg); } }
// .until // .skip // The send method now just sends one message, without waiting for a // reply. Since we're using a DEALER socket we have to send an empty // frame at the start, to create the same envelope that the REQ socket // would normally make for us: public int Send(string service, ZMessage request, CancellationTokenSource cancellor) { if (request == null) { throw new NotImplementedException(); } if (cancellor.IsCancellationRequested || (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) { _context.Shutdown(); } // Prefix request with protocol frames // Frame 0: empty (REQ emulation) // Frame 1: "MDPCxy" (six bytes, MDP/Client x.y) // Frame 2: Service name (printable string) request.Prepend(new ZFrame(service)); request.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); request.Prepend(new ZFrame(string.Empty)); if (Verbose) { request.DumpZmsg("I: send request to '{0}' service:", service); } ZError error; if (!Client.Send(request, out error)) { ; } { if (Equals(error, ZError.ETERM)) { cancellor.Cancel(); // Interrupted } //throw new ZException(error); } return(0); }
public static void Identity(string[] args) { // // Demonstrate request-reply identities // // Author: metadings // using (var context = new ZContext()) using (var sink = new ZSocket(context, ZSocketType.ROUTER)) { sink.Bind("inproc://example"); // First allow 0MQ to set the identity using (var anonymous = new ZSocket(context, ZSocketType.REQ)) { anonymous.Connect("inproc://example"); anonymous.Send(new ZFrame("ROUTER uses REQ's generated 5 byte identity")); } using (ZMessage msg = sink.ReceiveMessage()) { msg.DumpZmsg("--------------------------"); } // Then set the identity ourselves using (var identified = new ZSocket(context, ZSocketType.REQ)) { identified.IdentityString = "PEER2"; identified.Connect("inproc://example"); identified.Send(new ZFrame("ROUTER uses REQ's socket identity")); } using (ZMessage msg = sink.ReceiveMessage()) { msg.DumpZmsg("--------------------------"); } } }
// .split worker send method // This method formats and sends a command to a worker. The caller may // also provide a command option, and a message payload: public void Send(string command, string option, ZMessage msg) { msg = msg != null ? msg.Duplicate() : new ZMessage(); // Stack protocol envelope to start of message if (!string.IsNullOrEmpty(option)) { msg.Prepend(new ZFrame(option)); } msg.Prepend(new ZFrame(command)); msg.Prepend(new ZFrame(MdpCommon.MDPW_WORKER)); // Stack routing envelope to start of message msg.Wrap(Identity.Duplicate()); if (Broker.Verbose) { msg.DumpZmsg("I: sending '{0:X}|{0}' to worker", command.ToMdCmd()); } Broker.Socket.Send(msg); }
static void Main(string[] args) { // // Demonstrate request-reply identities // // Author: metadings // using (var context = new ZContext()) using (var sink = new ZSocket(context, ZSocketType.ROUTER)) { sink.Bind("inproc://example"); // First allow 0MQ to set the identity using (var anonymous = new ZSocket(context, ZSocketType.REQ)) { anonymous.Connect("inproc://example"); anonymous.Send(new ZFrame("ROUTER uses REQ's generated 5 byte identity")); ZMessage msg = sink.ReceiveMessage(); msg.DumpZmsg("-------------anonymous-------------"); using (msg) using (ZMessage newMsg = new ZMessage()) { //send three frame, but the client received is the only data frame, it's the 3rd frame. newMsg.Add(msg[0]); newMsg.Add(new ZFrame()); newMsg.Add(new ZFrame("router to REQ")); sink.Send(newMsg); } using (ZMessage routerMsg = anonymous.ReceiveMessage()) { routerMsg.DumpZmsg("-------------anonymous-------------"); } } // Then set the identity ourselves using (var identified = new ZSocket(context, ZSocketType.REQ)) { identified.IdentityString = "PEER2"; identified.Connect("inproc://example"); identified.Send(new ZFrame("ROUTER uses REQ's socket identity")); ZMessage msg = sink.ReceiveMessage(); msg.DumpZmsg("------------identified--------------"); using (msg) using (ZMessage newMsg = new ZMessage()) { //send three frame, but the client received is the only data frame, it's the 3rd frame. newMsg.Add(msg[0]); //here, this is very important. If we do not add the empty frame, client will receive nothing. newMsg.Add(new ZFrame()); newMsg.Add(new ZFrame("router to REQ")); sink.Send(newMsg); } using (ZMessage routerMsg = identified.ReceiveMessage()) { routerMsg.DumpZmsg("-------------identified-------------"); } } using (var DEALERIdentify = new ZSocket(context, ZSocketType.DEALER)) { DEALERIdentify.Connect("inproc://example"); DEALERIdentify.Send(new ZFrame("ROUTER uses Dealer's generated 5 byte identity, But there is no empty frame as separeator")); ZMessage msg = sink.ReceiveMessage(); msg.DumpZmsg("------------DEALERIdentify--------------"); using (msg) using (ZMessage newMsg = new ZMessage()) { //send three frame, but the client received is the only data frame, it's the 3rd frame. newMsg.Add(msg[0]); //here, this is very important. That there is no separeator for Dealer!!!!!!!!!!!!!!, If we add the empty frame, it will be treat as data frame //newMsg.Add(new ZFrame()); newMsg.Add(new ZFrame("router to REQ")); sink.Send(newMsg); } using (ZMessage routerMsg = DEALERIdentify.ReceiveMessage()) { routerMsg.DumpZmsg("-------------DEALERIdentify-------------"); } } } Console.WriteLine(); Console.WriteLine("Press any key to exit..."); Console.ReadLine(); }
// .split worker send method // This method formats and sends a command to a worker. The caller may // also provide a command option, and a message payload: public void Send(string command, string option, ZMessage msg) { msg = msg != null ? msg.Duplicate() : new ZMessage(); // Stack protocol envelope to start of message if (!string.IsNullOrEmpty(option)) msg.Prepend(new ZFrame(option)); msg.Prepend(new ZFrame(command)); msg.Prepend(new ZFrame(MdpCommon.MDPW_WORKER)); // Stack routing envelope to start of message msg.Wrap(Identity.Duplicate()); if(Broker.Verbose) msg.DumpZmsg("I: sending '{0:X}|{0}' to worker", command.ToMdCmd()); Broker.Socket.Send(msg); }
// .split broker worker_msg method // This method processes one READY, REPLY, HEARTBEAT, or // DISCONNECT message sent to the broker by a worker: public void WorkerMsg(ZFrame sender, ZMessage msg) { if(msg.Count < 1) // At least, command throw new InvalidOperationException(); ZFrame command = msg.Pop(); //string id_string = sender.ReadString(); bool isWorkerReady; //string id_string; using (var sfrm = sender.Duplicate()) { var idString = sfrm.Read().ToHexString(); isWorkerReady = Workers.ContainsKey(idString); } Worker worker = RequireWorker(sender); using (msg) using (command) { if (command.StrHexEq(MdpCommon.MdpwCmd.READY)) { if (isWorkerReady) // Not first command in session worker.Delete(true); else if (command.Length >= 4 && command.ToString().StartsWith("mmi.")) // Reserd servicee name worker.Delete(true); else { // Attach worker to service and mark as idle using (ZFrame serviceFrame = msg.Pop()) { worker.Service = RequireService(serviceFrame); worker.Service.Workers++; worker.Waiting(); } } } else if (command.StrHexEq(MdpCommon.MdpwCmd.REPLY)) { if (isWorkerReady) { // Remove and save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(new ZFrame(worker.Service.Name)); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); worker.Waiting(); } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { if (isWorkerReady) { worker.Expiry = DateTime.UtcNow + MdpCommon.HEARTBEAT_EXPIRY; } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) worker.Delete(false); else { msg.DumpZmsg("E: invalid input message"); } } }
// .split send request and wait for reply // Here is the {{send}} method. It sends a request to the broker and gets // a reply even if it has to retry several times. It takes ownership of // the request message, and destroys it when sent. It returns the reply // message, or NULL if there was no reply after multiple attempts: public ZMessage Send(string service, ZMessage request, CancellationTokenSource cancellor) { if (request == null) { throw new InvalidOperationException(); } // Prefix request with protocol frames // Frame 1: "MDPCxy" (six bytes, MDP/Client x.y) // Frame 2: Service name (printable string) request.Prepend(new ZFrame(service)); request.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); if (Verbose) { request.DumpZmsg("I: send request to '{0}' service:", service); } int retriesLeft = Retries; while (retriesLeft > 0 && !cancellor.IsCancellationRequested) { if (cancellor.IsCancellationRequested || (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) { _context.Shutdown(); } // Copy the Request and send on Client ZMessage msgreq = request.Duplicate(); ZError error; if (!Client.Send(msgreq, out error)) { if (Equals(error, ZError.ETERM)) { cancellor.Cancel(); break; // Interrupted } } var p = ZPollItem.CreateReceiver(); ZMessage msg; // .split body of send // On any blocking call, {{libzmq}} will return -1 if there was // an error; we could in theory check for different error codes, // but in practice it's OK to assume it was {{EINTR}} (Ctrl-C): // Poll the client Message if (Client.PollIn(p, out msg, out error, Timeout)) { // If we got a reply, process it if (Verbose) { msg.DumpZmsg("I: received reply"); } if (msg.Count < 3) { throw new InvalidOperationException(); } using (ZFrame header = msg.Pop()) if (!header.ToString().Equals(MdpCommon.MDPC_CLIENT)) { throw new InvalidOperationException(); } using (ZFrame replyService = msg.Pop()) if (!replyService.ToString().Equals(service)) { throw new InvalidOperationException(); } request.Dispose(); return(msg); } else if (Equals(error, ZError.ETERM)) { cancellor.Cancel(); break; // Interrupted } else if (Equals(error, ZError.EAGAIN)) { if (--retriesLeft > 0) { if (Verbose) { "W: no reply, reconnecting...".DumpString(); } ConnectToBroker(); } else { if (Verbose) { "W: permanent error, abandoning".DumpString(); } break; // Give up } } } if (cancellor.IsCancellationRequested) { "W: interrupt received, killing client...\n".DumpString(); } request.Dispose(); return(null); }
// .split send request and wait for reply // Here is the {{send}} method. It sends a request to the broker and gets // a reply even if it has to retry several times. It takes ownership of // the request message, and destroys it when sent. It returns the reply // message, or NULL if there was no reply after multiple attempts: public ZMessage Send(string service, ZMessage request, CancellationTokenSource cancellor) { if (request == null) throw new InvalidOperationException(); // Prefix request with protocol frames // Frame 1: "MDPCxy" (six bytes, MDP/Client x.y) // Frame 2: Service name (printable string) request.Prepend(new ZFrame(service)); request.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); if (Verbose) request.DumpZmsg("I: send request to '{0}' service:", service); int retriesLeft = Retries; while (retriesLeft > 0 && !cancellor.IsCancellationRequested) { if (cancellor.IsCancellationRequested || (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) _context.Shutdown(); // Copy the Request and send on Client ZMessage msgreq = request.Duplicate(); ZError error; if (!Client.Send(msgreq, out error)) { if (Equals(error, ZError.ETERM)) { cancellor.Cancel(); break; // Interrupted } } var p = ZPollItem.CreateReceiver(); ZMessage msg; // .split body of send // On any blocking call, {{libzmq}} will return -1 if there was // an error; we could in theory check for different error codes, // but in practice it's OK to assume it was {{EINTR}} (Ctrl-C): // Poll the client Message if (Client.PollIn(p, out msg, out error, Timeout)) { // If we got a reply, process it if (Verbose) msg.DumpZmsg("I: received reply"); if(msg.Count < 3) throw new InvalidOperationException(); using (ZFrame header = msg.Pop()) if (!header.ToString().Equals(MdpCommon.MDPC_CLIENT)) throw new InvalidOperationException(); using (ZFrame replyService = msg.Pop()) if(!replyService.ToString().Equals(service)) throw new InvalidOperationException(); request.Dispose(); return msg; } else if (Equals(error, ZError.ETERM)) { cancellor.Cancel(); break; // Interrupted } else if (Equals(error, ZError.EAGAIN)) { if (--retriesLeft > 0) { if (Verbose) "W: no reply, reconnecting...".DumpString(); ConnectToBroker(); } else { if (Verbose) "W: permanent error, abandoning".DumpString(); break; // Give up } } } if (cancellor.IsCancellationRequested) { "W: interrupt received, killing client...\n".DumpString(); } request.Dispose(); return null; }
// .split broker worker_msg method // This method processes one READY, REPLY, HEARTBEAT, or // DISCONNECT message sent to the broker by a worker: public void WorkerMsg(ZFrame sender, ZMessage msg) { if (msg.Count < 1) // At least, command { throw new InvalidOperationException(); } ZFrame command = msg.Pop(); //string id_string = sender.ReadString(); bool isWorkerReady; //string id_string; using (var sfrm = sender.Duplicate()) { var idString = sfrm.Read().ToHexString(); isWorkerReady = Workers.ContainsKey(idString); } Worker worker = RequireWorker(sender); using (msg) using (command) { if (command.StrHexEq(MdpCommon.MdpwCmd.READY)) { if (isWorkerReady) { // Not first command in session worker.Delete(true); } else if (command.Length >= 4 && command.ToString().StartsWith("mmi.")) { // Reserd servicee name worker.Delete(true); } else { // Attach worker to service and mark as idle using (ZFrame serviceFrame = msg.Pop()) { worker.Service = RequireService(serviceFrame); worker.Service.Workers++; worker.Waiting(); } } } else if (command.StrHexEq(MdpCommon.MdpwCmd.REPLY)) { if (isWorkerReady) { // Remove and save client return envelope and insert the // protocol header and service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(new ZFrame(worker.Service.Name)); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); worker.Waiting(); } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.HEARTBEAT)) { if (isWorkerReady) { worker.Expiry = DateTime.UtcNow + MdpCommon.HEARTBEAT_EXPIRY; } else { worker.Delete(true); } } else if (command.StrHexEq(MdpCommon.MdpwCmd.DISCONNECT)) { worker.Delete(false); } else { msg.DumpZmsg("E: invalid input message"); } } }
// .until // .skip // The send method now just sends one message, without waiting for a // reply. Since we're using a DEALER socket we have to send an empty // frame at the start, to create the same envelope that the REQ socket // would normally make for us: public int Send(string service, ZMessage request, CancellationTokenSource cancellor) { if (request == null) throw new NotImplementedException(); if (cancellor.IsCancellationRequested || (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) _context.Shutdown(); // Prefix request with protocol frames // Frame 0: empty (REQ emulation) // Frame 1: "MDPCxy" (six bytes, MDP/Client x.y) // Frame 2: Service name (printable string) request.Prepend(new ZFrame(service)); request.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); request.Prepend(new ZFrame(string.Empty)); if (Verbose) request.DumpZmsg("I: send request to '{0}' service:", service); ZError error; if(!Client.Send(request, out error)); { if (Equals(error, ZError.ETERM)) cancellor.Cancel(); // Interrupted //throw new ZException(error); } return 0; }