// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if (msg.Count < 2) { throw new InvalidOperationException(); } using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "404"; } else { returnCode = "501"; } var client = msg.Unwrap(); msg.Clear(); msg.Add(new ZFrame(returnCode)); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(msg); } } }
public ZMessage Request(ZMessage request) { // To implement the request method, the frontend object sends a message // to the backend, specifying a command "REQUEST" and the request message: request.Prepend(new ZFrame("REQUEST")); this.Actor.Frontend.Send(request); ZMessage reply; ZError error; if (null != (reply = this.Actor.Frontend.ReceiveMessage(out error))) { using (ZFrame statusFrame = reply.Pop()) { string status = statusFrame.ReadString(); if (status == "FAILED") { reply.Dispose(); reply = null; } } } return(reply); }
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); } }
// Majordomo Protocol client example // Uses the mdcli API to hide all MDP aspects static void Main(string[] args) { CancellationTokenSource cts = new CancellationTokenSource(); Console.CancelKeyPress += (s, ea) => { ea.Cancel = true; cts.Cancel(); }; using (MajordomoClient session = new MajordomoClient("tcp://127.0.0.1:5555", ProgramerHelper.Verbose)) { int count; for (count = 0; count < 100000; count++) { ZMessage request = new ZMessage(); request.Prepend(new ZFrame("Hello world")); using (ZMessage reply = session.Send("echo", request, cts)) if (reply == null) { break; } // Interrupt or failure } Console.WriteLine("{0} requests/replies processed\n", count); } }
// Majordomo Protocol client example // Uses the mdcli API to hide all MDP aspects public static void MDClient(string[] args) { bool verbose = (args.Any(e => e.ToLower().Equals("-v") || e.ToLower().Equals("--verbose"))); Console.WriteLine("Verbose: {0}", verbose); CancellationTokenSource cts = new CancellationTokenSource(); Console.CancelKeyPress += (s, ea) => { ea.Cancel = true; cts.Cancel(); }; using (MajordomoClient session = new MajordomoClient("tcp://127.0.0.1:5555", verbose)) { int count; for (count = 0; count < 100000; count++) { ZMessage request = new ZMessage(); request.Prepend(new ZFrame("Hello world")); using (ZMessage reply = session.Send("echo", request, cts)) if (reply == null) break; // Interrupt or failure } Console.WriteLine("{0} requests/replies processed\n", count); } }
// Majordomo Protocol client example // Uses the mdcli API to hide all MDP aspects public static void MDClient2(string[] args) { CancellationTokenSource cts = new CancellationTokenSource(); Console.CancelKeyPress += (s, ea) => { ea.Cancel = true; cts.Cancel(); }; using (MajordomoClient session = new MajordomoClient("tcp://127.0.0.1:5555", Verbose)) { int count; for (count = 0; count < 100000 && !cts.IsCancellationRequested; count++) { ZMessage request = new ZMessage(); request.Prepend(new ZFrame("Hello world")); session.Send("echo", request, cts); } for (count = 0; count < 100000 && !cts.IsCancellationRequested; count++) { using (ZMessage reply = session.Recv(cts)) if (reply == null) break; // Interrupt or failure } Console.WriteLine("{0} replies received\n", count); } }
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); }
// .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 Titanic reply service // The {{titanic.reply}} task checks if there's a reply for the specified // request (by UUID), and returns a 200 (OK), 300 (Pending), or 400 // (Unknown) accordingly: private static void Titanic_Reply(ZContext context, CancellationTokenSource cts, bool verbose) { using (var worker = new MajordomoWorker("tcp://127.0.0.1:5555", "titanic.reply", verbose)) { ZMessage reply = null; while (true) { var request = worker.Recv(reply, cts); if (request == null) { break; // Interrupted, exit } var g = Guid.Parse(request.Pop().ReadString()); var reqfn = TitanicCommon.RequestFilename(g); var repfn = TitanicCommon.ReplyFilename(g); if (File.Exists(repfn)) { reply = repfn.DeserializeFromXml <ZMessage>(); reply.Prepend(new ZFrame("200")); } else { reply = new ZMessage(); if (File.Exists(reqfn)) { reply.Prepend(new ZFrame("300")); //Pending } else { reply.Prepend(new ZFrame("400")); //Unknown } } request.Dispose(); } } }
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; } }
// .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 static void FLServer3(string[] args) { // // Freelance server - Model 3 // Uses an ROUTER/ROUTER socket but just one thread // // Author: metadings // // Prepare server socket with predictable identity string bind_endpoint = "tcp://*:5555"; string connect_endpoint = "tcp://127.0.0.1:5555"; using (var context = new ZContext()) using (var server = new ZSocket(context, ZSocketType.ROUTER)) { Console.CancelKeyPress += (s, ea) => { ea.Cancel = true; context.Shutdown(); }; server.IdentityString = connect_endpoint; server.Bind(bind_endpoint); Console.WriteLine("I: service is ready as {0}", bind_endpoint); ZError error; ZMessage request; while (true) { if (null == (request = server.ReceiveMessage(out error))) { if (error == ZError.ETERM) break; // Interrupted throw new ZException(error); } using (var response = new ZMessage()) { ZFrame identity; using (request) { if (Verbose) Console_WriteZMessage("Receiving", request); // Frame 0: identity of client // Frame 1: PING, or client control frame // Frame 2: request body identity = request.Pop(); ZFrame control = request.Pop(); string controlMessage = control.ReadString(); if (controlMessage == "PING") { control.Dispose(); response.Add(new ZFrame("PONG")); } else { response.Add(control); response.Add(new ZFrame("OK")); } } response.Prepend(identity); if (Verbose) Console_WriteZMessage("Sending ", response); if (!server.Send(response, out error)) { if (error == ZError.ETERM) break; // Interrupted throw new ZException(error); } } } if (error == ZError.ETERM) { Console.WriteLine("W: interrupted"); } } }
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; } }
// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if(msg.Count < 2) throw new InvalidOperationException(); using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "404"; } else returnCode = "501"; var client = msg.Unwrap(); msg.Clear(); msg.Add(new ZFrame(returnCode)); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(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"); } } }
public ZMessage Request(ZMessage request) { // To implement the request method, the frontend object sends a message // to the backend, specifying a command "REQUEST" and the request message: request.Prepend(new ZFrame("REQUEST")); this.Actor.Frontend.Send(request); ZMessage reply; ZError error; if (null != (reply = this.Actor.Frontend.ReceiveMessage(out error))) { string status = reply.PopString(); if (status == "FAILED") { reply.Dispose(); reply = null; } } return reply; }
public void RouterMessage(ZMessage reply) { // This method processes one message from a connected // server: // Frame 0 is server that replied string endpoint = reply.PopString(); Server server = this.Servers.Single(s => s.Endpoint == endpoint); if (!server.Alive) { this.Actives.Add(server); server.Refresh(true); } // Frame 1 may be sequence number for reply int sequence = reply.PopInt32(); if (sequence == this.sequence) { reply.Prepend(new ZFrame("OK")); this.Pipe.Send(reply); this.Request.Dispose(); this.Request = 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"); } } }
// .split broker client_msg method // Process a request coming from a client. We implement MMI requests // directly here (at present, we implement only the mmi.service request): public void ClientMsg(ZFrame sender, ZMessage msg) { // service & body if(msg.Count < 2) throw new InvalidOperationException(); using (ZFrame serviceFrame = msg.Pop()) { Service service = RequireService(serviceFrame); // Set reply return identity to client sender msg.Wrap(sender.Duplicate()); //if we got a MMI Service request, process that internally if (serviceFrame.Length >= 4 && serviceFrame.ToString().StartsWith("mmi.")) { string returnCode; if (serviceFrame.ToString().Equals("mmi.service")) { string name = msg.Last().ToString(); returnCode = Services.ContainsKey(name) && Services[name].Workers > 0 ? "200" : "400"; } else returnCode = "501"; using (var resetableFrame = msg.Pop()) { msg.Prepend(new ZFrame(returnCode)); } //ToDo check c implementation throw new NotImplementedException("ToDo: fix this section, never tested. contains errors mmi services never called with the mdclient/mdbroker/mdworker examples"); //## following code has some errors // Remove & save client return envelope and insert the // protocol header and Service name, then rewrap envelope. ZFrame client = msg.Unwrap(); msg.Prepend(serviceFrame); msg.Prepend(new ZFrame(MdpCommon.MDPC_CLIENT)); msg.Wrap(client); Socket.Send(msg); } else { // Else dispatch the message to the requested Service service.Dispatch(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); }
// .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; }