/// <summary> /// Based on zmsg_dump /// https://github.com/imatix/zguide/blob/f94e8995a5e02d843434ace904a7afc48e266b3f/articles/src/multithreading/zmsg.c /// </summary> /// <param name="zmsg"></param> /// <param name="format"></param> /// <param name="args"></param> public static void DumpZmsg(this ZMessage zmsg, string format = null, params object[] args) { if (!string.IsNullOrWhiteSpace(format)) { format.DumpString(args); } using (var dmsg = zmsg.Duplicate()) foreach (var zfrm in dmsg) { zfrm.DumpZfrm(); } }
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); } }
public void ControlMessage(ZMessage msg) { // This method processes one message from our frontend class // (it's going to be CONNECT or REQUEST): string command; using (var commandFrame = msg.Pop()) { command = commandFrame.ReadString(); } if (command == "CONNECT") { string endpoint = msg[0].ReadString(); Console.WriteLine("I: connecting to {0}...", endpoint); Router.Connect(endpoint); var server = new Server(endpoint); this.Servers.Add(server); this.Actives.Add(server); } else if (command == "REQUEST") { if (this.Request != null) { // Strict request-reply cycle throw new InvalidOperationException(); } // Prefix request with sequence number and empty envelope msg.Prepend(new ZFrame(++sequence)); // Take ownership of request message this.Request = msg.Duplicate(); // Request expires after global timeout this.Expires = DateTime.UtcNow + GLOBAL_TIMEOUT; } }
/// <summary> /// Based on zmsg_dump /// https://github.com/imatix/zguide/blob/f94e8995a5e02d843434ace904a7afc48e266b3f/articles/src/multithreading/zmsg.c /// </summary> /// <param name="zmsg"></param> /// <param name="format"></param> /// <param name="args"></param> public static void DumpZmsg(this ZMessage zmsg, string format, params object[] args) { format.DumpString(args); using (var dmsg = zmsg.Duplicate()) foreach (var zfrm in dmsg) { byte[] data = zfrm.Read(); long size = zfrm.Length; // Dump the message as text or binary bool isText = true; for (int i = 0; i < size; i++) { if (data[i] < 32 || data[i] > 127) { isText = false; } } string datastr = isText ? Encoding.UTF8.GetString(data) : data.ToHexString(); "\tD: [{0,3:D3}]:{1}".DumpString(size, datastr); } }
// .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 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 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); }
public ZMessage Request(ZMessage request) { // This method does the hard work. It sends a request to all // connected servers in parallel (for this to work, all connections // must be successful and completed by this time). It then waits // for a single successful reply, and returns that to the caller. // Any other replies are just dropped: ZMessage reply = null; using (request) { // Prefix request with sequence number and empty envelope this.sequence++; request.Prepend(new ZFrame(this.sequence)); request.Prepend(new ZFrame()); // Blast the request to all connected servers for (int server = 0; server < this.servers; ++server) { using (var outgoing = request.Duplicate()) { this.socket.Send(outgoing); } } // Wait for a matching reply to arrive from anywhere // Since we can poll several times, calculate each one ZError error; DateTime endtime = DateTime.UtcNow + GLOBAL_TIMEOUT; var poll = ZPollItem.CreateReceiver(); while (endtime > DateTime.UtcNow) { if (this.socket.PollIn(poll, out reply, out error, endtime - DateTime.UtcNow)) { // Reply is [empty][sequence][OK] if (reply.Count < 3) { throw new InvalidOperationException(); } reply.RemoveAt(0); using (ZFrame sequenceFrame = reply.RemoveAt(0, false)) { int sequence = sequenceFrame.ReadInt32(); if (sequence == this.sequence) { break; // Reply is ok } } reply.Dispose(); } else { if (error == ZError.ETERM) { break; // Interrupted } if (error != ZError.EAGAIN) { throw new ZException(error); } } } } return(reply); }
// .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; }
public ZMessage Request(ZMessage request) { // This method does the hard work. It sends a request to all // connected servers in parallel (for this to work, all connections // must be successful and completed by this time). It then waits // for a single successful reply, and returns that to the caller. // Any other replies are just dropped: ZMessage reply = null; using (request) { // Prefix request with sequence number and empty envelope this.sequence++; request.Prepend(new ZFrame(this.sequence)); request.Prepend(new ZFrame()); // Blast the request to all connected servers for (int server = 0; server < this.servers; ++server) { using (var outgoing = request.Duplicate()) { this.socket.Send(outgoing); } } // Wait for a matching reply to arrive from anywhere // Since we can poll several times, calculate each one ZError error; DateTime endtime = DateTime.UtcNow + GLOBAL_TIMEOUT; var poll = ZPollItem.CreateReceiver(); while (endtime > DateTime.UtcNow) { if (this.socket.PollIn(poll, out reply, out error, endtime - DateTime.UtcNow)) { // Reply is [empty][sequence][OK] if (reply.Count < 3) { throw new InvalidOperationException(); } reply.RemoveAt(0); using (ZFrame sequenceFrame = reply.RemoveAt(0, false)) { int sequence = sequenceFrame.ReadInt32(); if (sequence == this.sequence) { break; // Reply is ok } } reply.Dispose(); } else { if (error == ZError.ETERM) break; // Interrupted if (error != ZError.EAGAIN) throw new ZException(error); } } } return reply; }
public void ControlMessage(ZMessage msg) { // This method processes one message from our frontend class // (it's going to be CONNECT or REQUEST): string command = msg.PopString(); if (command == "CONNECT") { string endpoint = msg.PopString(); Console.WriteLine("I: connecting to {0}...", endpoint); this.Router.Connect(endpoint); var server = new Server(endpoint); this.Servers.Add(server); this.Actives.Add(server); } else if (command == "REQUEST") { if (this.Request != null) { // Strict request-reply cycle throw new InvalidOperationException(); } // Prefix request with sequence number and empty envelope msg.Prepend(new ZFrame(++sequence)); // Take ownership of request message this.Request = msg.Duplicate(); // Request expires after global timeout this.Expires = DateTime.UtcNow + GLOBAL_TIMEOUT; } }