zmsg_t * mdwrk_recv (mdwrk_t *self, zmsg_t *reply) { // Format and send the reply if we were provided one assert (reply || !self->expect_reply); if (reply) { zmsg_t *msg = zmsg_dup (reply); zmsg_push (msg, MDPS_REPLY); zmsg_push (msg, MDPS_HEADER); zmsg_send (&msg, self->worker); } self->expect_reply = 1; while (1) { zmq_pollitem_t items [] = { { self->worker, 0, ZMQ_POLLIN, 0 } }; zmq_poll (items, 1, HEARTBEAT_INTERVAL * 1000); if (items [0].revents & ZMQ_POLLIN) { zmsg_t *msg = zmsg_recv (self->worker); self->liveness = HEARTBEAT_LIVENESS; // Don't try to handle errors, just assert noisily assert (zmsg_parts (msg) >= 3); char *header = zmsg_pop (msg); assert (strcmp (header, MDPS_HEADER) == 0); free (header); char *command = zmsg_pop (msg); if (strcmp (command, MDPS_REQUEST) == 0) return msg; // We have a request to process else if (strcmp (command, MDPS_HEARTBEAT) == 0) ; // Do nothing for heartbeats else if (strcmp (command, MDPS_DISCONNECT) == 0) break; // Return empty handed else { printf ("E: invalid input message (%d)\n", (int) command [1]); zmsg_dump (msg); } free (command); } else if (--self->liveness == 0) { s_sleep (RECONNECT_INTERVAL); s_connect_to_broker (self); } // Send HEARTBEAT if it's time if (s_clock () > self->heartbeat_at) { self->heartbeat_at = s_clock () + HEARTBEAT_INTERVAL; s_send (self->worker, "HEARTBEAT"); } } // We exit if we've been disconnected return NULL; }
void clone_set (clone_t *self, char *key, char *value) { assert (self); assert (endpoint); zmsg_t *msg = zmsg_new (value); zmsg_push (msg, key); zmsg_push (msg, "SET"); zmsg_send (&msg, self->control); }
zmsg_t * mdcli_send (mdcli_t *self, char *service, zmsg_t *request) { int retries_left = REQUEST_RETRIES; while (retries_left) { // Prefix request with protocol frames // Frame 1: "MDPCxy" (six bytes, MDP/Client x.y) // Frame 2: Service name (printable string) zmsg_t *msg = zmsg_dup (request); zmsg_push (msg, service); zmsg_push (msg, MDPC_HEADER); zmsg_send (&msg, self->client); while (1) { // Poll socket for a reply, with timeout zmq_pollitem_t items [] = { { self->client, 0, ZMQ_POLLIN, 0 } }; zmq_poll (items, 1, REQUEST_TIMEOUT * 1000); // If we got a reply, process it if (items [0].revents & ZMQ_POLLIN) { zmsg_t *msg = zmsg_recv (self->client); // Don't try to handle errors, just assert noisily assert (zmsg_parts (msg) >= 3); char *header = zmsg_pop (msg); assert (strcmp (header, MDPC_HEADER) == 0); free (header); char *service = zmsg_pop (msg); assert (strcmp (service, service) == 0); free (service); return msg; // Success } else if (--retries_left) { // Reconnect, and resend message s_connect_to_broker (self); zmsg_t *msg = zmsg_dup (request); zmsg_push (msg, service); zmsg_push (msg, MDPC_HEADER); zmsg_send (&msg, self->client); } else break; // Give up } } return NULL; }
END_TEST // -------------------------------------------------------------------------- /// _pop () multiple times. Mainly used to test the garbage collection. START_TEST(test_msg_pop_successively) { sam_selftest_introduce ("test_msg_pop_successively"); zmsg_t *zmsg = zmsg_new (); zmsg_pushstr (zmsg, "three"); zmsg_pushstr (zmsg, "two"); zmsg_pushstr (zmsg, "one"); char payload = '0'; zframe_t *frame = zframe_new (&payload, sizeof (payload)); zmsg_push (zmsg, frame); sam_msg_t *msg = sam_msg_new (&zmsg); zframe_t *zero; char *one; int rc = sam_msg_pop (msg, "fs", &zero, &one); ck_assert_int_eq (rc, 0); ck_assert_int_eq (sam_msg_size (msg), 2); char *two, *three; rc = sam_msg_pop (msg, "ss", &two, &three); ck_assert_int_eq (rc, 0); ck_assert_int_eq (sam_msg_size (msg), 0); sam_msg_destroy (&msg); }
void agent_router_message (agent_t *self) { zmsg_t *reply = zmsg_recv (self->router); // Frame 0 is server that replied char *endpoint = zmsg_pop (reply); server_t *server = (server_t *) zhash_lookup (self->servers, endpoint); assert (server); free (endpoint); if (!server->alive) { zlist_append (self->actives, server); server->alive = 1; } server->ping_at = s_clock () + PING_INTERVAL; server->expires = s_clock () + SERVER_TTL; // Frame 1 may be sequence number for reply if (zmsg_parts (reply) > 1 && atoi (zmsg_address (reply)) == self->sequence) { free (zmsg_pop (reply)); zmsg_push (reply, "OK"); zmsg_send (&reply, self->control); zmsg_destroy (&self->request); } zmsg_destroy (&reply); }
void agent_control_message (agent_t *self) { zmsg_t *msg = zmsg_recv (self->control); char *command = zmsg_pop (msg); if (strcmp (command, "CONNECT") == 0) { char *endpoint = zmsg_pop (msg); printf ("I: connecting to %s...\n", endpoint); int rc = zmq_connect (self->router, endpoint); assert (rc == 0); server_t *server = server_new (endpoint); zhash_insert (self->servers, endpoint, server); zhash_freefn (self->servers, endpoint, s_server_free); zlist_append (self->actives, server); server->ping_at = s_clock () + PING_INTERVAL; server->expires = s_clock () + SERVER_TTL; free (endpoint); } else if (strcmp (command, "REQUEST") == 0) { assert (!self->request); // Strict request-reply cycle // Prefix request with sequence number and empty envelope char sequence_text [10]; sprintf (sequence_text, "%u", ++self->sequence); zmsg_push (msg, sequence_text); // Take ownership of request message self->request = msg; msg = NULL; // Request expires after global timeout self->expires = s_clock () + GLOBAL_TIMEOUT; } free (command); zmsg_destroy (&msg); }
END_TEST // -------------------------------------------------------------------------- /// Try to _get () a zframe pointer. START_TEST(test_msg_get_f) { sam_selftest_introduce ("test_msg_get_f"); zmsg_t *zmsg = zmsg_new (); char payload = 'a'; zframe_t *frame = zframe_new (&payload, sizeof (payload)); int rc = zmsg_push (zmsg, frame); ck_assert_int_eq (rc, 0); sam_msg_t *msg = sam_msg_new (&zmsg); ck_assert_int_eq (sam_msg_size (msg), 1); zframe_t *ref; rc = sam_msg_get (msg, "f", &ref); ck_assert_int_eq (rc, 0); ck_assert_int_eq (sam_msg_size (msg), 1); ck_assert (zframe_eq (ref, frame)); zframe_destroy (&ref); // check idempotency of _get () rc = sam_msg_get (msg, "f", &ref); ck_assert_int_eq (rc, 0); ck_assert_int_eq (sam_msg_size (msg), 1); ck_assert (zframe_eq (ref, frame)); zframe_destroy (&ref); sam_msg_destroy (&msg); }
END_TEST // -------------------------------------------------------------------------- /// Try to _pop () a zframe pointer. START_TEST(test_msg_pop_f) { sam_selftest_introduce ("test_msg_pop_f"); zmsg_t *zmsg = zmsg_new (); char payload = 'a'; zframe_t *frame = zframe_new (&payload, sizeof (payload)), *ref = zframe_dup (frame); int rc = zmsg_push (zmsg, frame); ck_assert_int_eq (rc, 0); sam_msg_t *msg = sam_msg_new (&zmsg); ck_assert_int_eq (sam_msg_size (msg), 1); zframe_t *popped; rc = sam_msg_pop (msg, "f", &popped); ck_assert_int_eq (rc, 0); ck_assert (zframe_eq (ref, popped)); ck_assert_int_eq (sam_msg_size (msg), 0); zframe_destroy (&ref); sam_msg_destroy (&msg); }
static void * flcliapi_task (void *context) { agent_t *self = agent_new (context, "inproc://flcliapi"); zmq_pollitem_t items [] = { { self->control, 0, ZMQ_POLLIN, 0 }, { self->router, 0, ZMQ_POLLIN, 0 } }; while (!s_interrupted) { // Calculate tickless timer, up to 1 hour uint64_t tickless = s_clock () + 1000 * 3600; if (self->request && tickless > self->expires) tickless = self->expires; zhash_apply (self->servers, server_tickless, &tickless); int rc = zmq_poll (items, 2, (tickless - s_clock ()) * 1000); if (rc == -1 && errno == ETERM) break; // Context has been shut down if (items [0].revents & ZMQ_POLLIN) agent_control_message (self); if (items [1].revents & ZMQ_POLLIN) agent_router_message (self); // If we're processing a request, dispatch to next server if (self->request) { if (s_clock () >= self->expires) { // Request expired, kill it zmsg_t *reply = zmsg_new ("FAILED"); zmsg_send (&reply, self->control); zmsg_destroy (&self->request); } else { // Find server to talk to, remove any expired ones while (zlist_size (self->actives)) { server_t *server = (server_t *) zlist_first (self->actives); if (s_clock () >= server->expires) { zlist_pop (self->actives); server->alive = 0; } else { zmsg_t *request = zmsg_dup (self->request); zmsg_push (request, server->endpoint); zmsg_send (&request, self->router); break; } } } } // Disconnect and delete any expired servers // Send heartbeats to idle servers if needed zhash_apply (self->servers, server_ping, self->router); } agent_destroy (&self); return NULL; }
void zmsg_wrap (zmsg_t *self, zframe_t *frame) { assert (self); assert (frame); if (zmsg_pushmem (self, "", 0) == 0) zmsg_push (self, frame); }
void clone_connect (clone_t *self, char *address, int port) { assert (self); assert (endpoint); zmsg_t *msg = zmsg_new (address); zmsg_push (msg, "CONNECT"); zmsg_send (&msg, self->control); }
void flcliapi_connect (flcliapi_t *self, char *endpoint) { assert (self); assert (endpoint); zmsg_t *msg = zmsg_new (endpoint); zmsg_push (msg, "CONNECT"); zmsg_send (&msg, self->control); s_sleep (100); // Allow connection to come up }
int main(int argc, char **argv) { zctx_t *ctx; zwssock_t *sock; char *l = argc > 1 ? argv[1] : listen_on; int major, minor, patch; zmq_version (&major, &minor, &patch); printf("built with: ØMQ=%d.%d.%d czmq=%d.%d.%d\n", major, minor, patch, CZMQ_VERSION_MAJOR, CZMQ_VERSION_MINOR,CZMQ_VERSION_PATCH); ctx = zctx_new(); sock = zwssock_new_router(ctx); zwssock_bind(sock, l); zmsg_t* msg; zframe_t *id; while (!zctx_interrupted) { msg = zwssock_recv(sock); if (!msg) break; // first message is the routing id id = zmsg_pop(msg); while (zmsg_size(msg) != 0) { char * str = zmsg_popstr(msg); printf("%s\n", str); free(str); } zmsg_destroy(&msg); msg = zmsg_new(); zmsg_push(msg, id); zmsg_addstr(msg, "hello back"); zwssock_send(sock, &msg); } zwssock_destroy(&sock); zctx_destroy(&ctx); }
void worker(void *args, zctx_t *ctx, void *pipe) { long mashine_number = ((setting_t *) args)->mashine_number; long thread_number = ((setting_t *) args)->thread_number; long auto_increment = 0; struct timeval tp; void *worker = zsocket_new(ctx, ZMQ_DEALER); zsocket_connect(worker, "inproc://zid"); while (!zctx_interrupted) { zmsg_t *request = zmsg_recv(worker); /* drop message if its size is less than 2 */ if (zmsg_size(request) != 2) { zmsg_destroy(&request); continue; } /* sender id */ zframe_t *sender = zmsg_pop(request); /* number of id to generate */ char *num = zmsg_popstr(request); int n = atoi(num); free(num); if (n > 0) { /* response message */ zmsg_t *response = zmsg_new(); int i; for (i = 0; i < n; i++) { gettimeofday(&tp, NULL); zmsg_addstrf(response, "%ld", ((mashine_number << 59) | (thread_number << 56) | (auto_increment << 45) | (tp.tv_sec << 10) | (tp.tv_usec / 1000))); auto_increment++; if (auto_increment == 2048) { auto_increment = 0; } } /* push sender id */ zmsg_push(response, sender); /* send back reply */ zmsg_send(&response, worker); } else { zframe_destroy(&sender); } zmsg_destroy(&request); } }
zmsg_t *utils_gen_msg(const char *device_id, const char *msgid, const char *msg, char *bytes, int len) { zmsg_t *answer = zmsg_new(); if (bytes != NULL) { zframe_t *frame = zframe_new (bytes, len); zmsg_push(answer, frame); } zmsg_pushstr(answer, "%s", msg); zmsg_pushstr(answer, "%s", msgid); zmsg_pushstr(answer, "%s", device_id); return answer; }
int server_ping (char *key, void *server, void *socket) { server_t *self = (server_t *) server; if (s_clock () >= self->ping_at) { zmsg_t *ping = zmsg_new ("PING"); zmsg_push (ping, self->endpoint); zmsg_send (&ping, socket); self->ping_at = s_clock () + PING_INTERVAL; } return 0; }
int mdcli_send (mdcli_t *self, char *service, zmsg_t **request_p) { assert (self); assert (request_p); zmsg_t *request = *request_p; // 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) zmsg_push (request, service); zmsg_push (request, MDPC_CLIENT); zmsg_push (request, ""); if (self->verbose) { s_console ("I: send request to '%s' service:", service); zmsg_dump (request); } zmsg_send (&request, self->client); return 0; }
void SNetDistribZMQSend(zframe_t *payload, int type, int destination) { int rc; zframe_t *source_f = NULL; zframe_t *type_f = NULL; zmsg_t *msg = zmsg_new(); zmsg_push(msg, payload); SNetDistribPack(&type_f, &type, sizeof(int)); zmsg_push(msg, type_f); SNetDistribPack(&source_f, &node_location, sizeof(int)); zmsg_push(msg, source_f); rc = HTabSend(msg, destination); if (rc != 0) { SNetUtilDebugFatal("ZMQDistrib: Cannot send message to %d (%s): zmsg_send (%d)", destination, SNetDistribZMQHTabLookUp(destination)->host, rc); } }
static void s_worker_send ( broker_t *self, worker_t *worker, char *command, char *option, zmsg_t *msg) { msg = msg? zmsg_dup (msg): zmsg_new (NULL); // Stack protocol envelope to start of message if (option) // Optional frame after command zmsg_push (msg, option); zmsg_push (msg, command); zmsg_push (msg, MDPW_WORKER); // Stack routing envelope to start of message zmsg_wrap (msg, worker->identity, ""); if (self->verbose) { s_console ("I: sending %s to worker", mdps_commands [(int) *command]); zmsg_dump (msg); } zmsg_send (&msg, self->socket); }
zmsg_t * flclient_request (flclient_t *self, zmsg_t **request_p) { assert (self); assert (*request_p); zmsg_t *request = *request_p; // Prefix request with sequence number and empty envelope char sequence_text [10]; sprintf (sequence_text, "%u", ++self->sequence); zmsg_push (request, sequence_text); zmsg_push (request, ""); // Blast the request to all connected servers int server; for (server = 0; server < self->servers; server++) { zmsg_t *msg = zmsg_dup (request); zmsg_send (&msg, self->socket); } // Wait for a matching reply to arrive from anywhere // Since we can poll several times, calculate each one zmsg_t *reply = NULL; uint64_t endtime = s_clock () + GLOBAL_TIMEOUT; while (s_clock () < endtime) { zmq_pollitem_t items [] = { { self->socket, 0, ZMQ_POLLIN, 0 } }; zmq_poll (items, 1, (endtime - s_clock ()) * 1000); if (items [0].revents & ZMQ_POLLIN) { reply = zmsg_recv (self->socket); assert (zmsg_parts (reply) == 3); free (zmsg_pop (reply)); if (atoi (zmsg_address (reply)) == self->sequence) break; zmsg_destroy (&reply); } } zmsg_destroy (request_p); return reply; }
static void s_broker_client_msg(broker_t *self, zframe_t *sender, zmsg_t *msg) { assert (zmsg_size(msg) >= 2); // Service name + body zframe_t *service_frame = zmsg_pop(msg); service_t *service = s_service_require(self, service_frame); // Не должен создавать сервис, в случаи запроса от клиента // Set reply return identity to client sender zmsg_wrap(msg, zframe_dup(sender)); // If we got a MMI service request, process that internally if (zframe_size(service_frame) >= 4 && memcmp(zframe_data(service_frame), "mmi.", 4) == 0) { char *return_code; if (zframe_streq(service_frame, "mmi.service")) { char *name = zframe_strdup (zmsg_last (msg)); service_t *service = (service_t *) zhash_lookup(self->services, name); if (service) { if (service->workers) { return_code = "200"; } else { return_code = "404"; } } else { return_code = "401"; } free(name); } else { return_code = "501"; } zframe_reset(zmsg_last(msg), return_code, strlen(return_code)); // Remove & save client return envelope and insert the // protocol header and service name, then rewrap envelope. zframe_t *client = zmsg_unwrap (msg); zmsg_push(msg, zframe_dup(service_frame)); zmsg_pushstr(msg, MDPC_CLIENT); zmsg_wrap(msg, client); zmsg_send(&msg, self->socket); } else { // Else dispatch the message to the requested service s_service_dispatch(service, msg); } zframe_destroy(&service_frame); }
zmsg_t * flcliapi_request (flcliapi_t *self, zmsg_t **request_p) { assert (self); assert (*request_p); zmsg_push (*request_p, "REQUEST"); zmsg_send (request_p, self->control); zmsg_t *reply = zmsg_recv (self->control); if (reply) { char *status = zmsg_pop (reply); if (strcmp (status, "FAILED") == 0) zmsg_destroy (&reply); free (status); } return reply; }
char * clone_get (clone_t *self, char *key) { assert (self); assert (endpoint); zmsg_t *msg = zmsg_new (key); zmsg_push (msg, "GET"); zmsg_send (&msg, self->control); zmsg_t *reply = zmsg_recv (self->control); if (reply) { char *value = zmsg_pop (reply); zmsg_destroy (&reply); return value; } return NULL; }
int main (int argc, char *argv []) { int verbose = (argc > 1 && streq (argv [1], "-v")); zctx_t *ctx = zctx_new (); // Prepare server socket with predictable identity char *bind_endpoint = "tcp://*:5555"; char *connect_endpoint = "tcp://localhost:5555"; void *server = zsocket_new (ctx, ZMQ_ROUTER); zmq_setsockopt (server, ZMQ_IDENTITY, connect_endpoint, strlen (connect_endpoint)); zsocket_bind (server, bind_endpoint); printf ("I: service is ready at %s\n", bind_endpoint); while (!zctx_interrupted) { zmsg_t *request = zmsg_recv (server); if (verbose && request) zmsg_dump (request); if (!request) break; // Interrupted // Frame 0: identity of client // Frame 1: PING, or client control frame // Frame 2: request body zframe_t *identity = zmsg_pop (request); zframe_t *control = zmsg_pop (request); zmsg_t *reply = zmsg_new (); if (zframe_streq (control, "PING")) zmsg_addstr (reply, "PONG"); else { zmsg_add (reply, control); zmsg_addstr (reply, "OK"); } zmsg_destroy (&request); zmsg_push (reply, identity); if (verbose && reply) zmsg_dump (reply); zmsg_send (&reply, server); } if (zctx_interrupted) printf ("W: interrupted\n"); zctx_destroy (&ctx); return 0; }
zlist_t * fetch_rules(void * sock, char * channel) { zlist_t * rules = zlist_new(); /* if(!endpoint) { zclock_log("W: no reup endpoint defined, won't try te refresh rules"); return rules; }*/ // zsocket_connect(sock, endpoint); zstr_sendm(sock, ""); zstr_send(sock, channel); zmsg_t * tmp; // while(tmp=zmsg_recv(sock)) { // zmsg_dump(tmp); //} // exit(1); zmsg_t * msg = zmsg_recv(sock); kill_envelope(msg); char * status = zmsg_popstr(msg); if(strcmp("200", status) != 0) { zclock_log("W: reloading rules for %s failed: got |%s|", channel, status); return rules; } free(status); zmsg_destroy(&msg); while((msg=zmsg_recv(sock))) { zclock_log("once"); kill_envelope(msg); zmsg_dump(msg); zframe_t * header = zmsg_pop(msg); if(zframe_streq(header, "")) { // we're done zclock_log("got a null header, we're out"); zframe_destroy(&header); zmsg_destroy(&msg); break; } zmsg_push(msg, header); zlist_push(rules, msg); } return rules; }
int main (int argc, char *argv []) { int verbose = (argc > 1 && streq (argv [1], "-v")); mdcli_t *session = mdcli_new ("tcp://localhost:5555", verbose); // 1. Send 'echo' request to Titanic zmsg_t *request = zmsg_new ("Hello world"); zmsg_push (request, "echo"); zmsg_t *reply = s_service_call ( session, "titanic.request", &request); char *uuid = NULL; if (reply) { uuid = zmsg_pop (reply); zmsg_destroy (&reply); printf ("I: request UUID: %s\n", uuid); } // 2. Wait until we get a reply while (!s_interrupted) { s_sleep (100); request = zmsg_new (uuid); zmsg_t *reply = s_service_call ( session, "titanic.reply", &request); if (reply) { printf ("Reply: %s\n", zmsg_body (reply)); zmsg_destroy (&reply); // 3. Close request request = zmsg_new (uuid); reply = s_service_call (session, "titanic.close", &request); zmsg_destroy (&reply); break; } else { printf ("I: no reply yet, trying again...\n"); s_sleep (5000); // Try again in 5 seconds } } mdcli_destroy (&session); return 0; }
static void s_service_internal (broker_t *self, zframe_t *service_frame, zmsg_t *msg) { char *return_code; if (zframe_streq (service_frame, "mmi.service")) { char *name = zframe_strdup (zmsg_last (msg)); service_t *service = (service_t *) zhash_lookup (self->services, name); return_code = service && service->workers? "200": "404"; free (name); } else return_code = "501"; zframe_reset (zmsg_last (msg), return_code, strlen (return_code)); // Remove & save client return envelope and insert the // protocol header and service name, then rewrap envelope. zframe_t *client = zmsg_unwrap (msg); zmsg_push (msg, zframe_dup (service_frame)); zmsg_pushstr (msg, MDPC_CLIENT); zmsg_wrap (msg, client); zmsg_send (&msg, self->socket); }
int main(void) { zctx_t *ctx = zctx_new(); void *frontend = zsocket_new(ctx, ZMQ_ROUTER); void *backend = zsocket_new(ctx, ZMQ_ROUTER); // IPC doesn't yet work on MS Windows. #if (defined (WIN32)) zsocket_bind(frontend, "tcp://*:5672"); zsocket_bind(backend, "tcp://*:5673"); #else zsocket_bind(frontend, "ipc://frontend.ipc"); zsocket_bind(backend, "ipc://backend.ipc"); #endif int client_nbr; for (client_nbr = 0; client_nbr < NBR_CLIENTS; client_nbr++) zthread_new(client_task, NULL); int worker_nbr; for (worker_nbr = 0; worker_nbr < NBR_WORKERS; worker_nbr++) zthread_new(worker_task, NULL); // Queue of available workers zlist_t *workers = zlist_new(); // .split main load-balancer loop // Here is the main loop for the load balancer. It works the same way // as the previous example, but is a lot shorter because CZMQ gives // us an API that does more with fewer calls: while (1) { zmq_pollitem_t items[] = { { backend, 0, ZMQ_POLLIN, 0 }, { frontend, 0, ZMQ_POLLIN, 0 } }; // Poll frontend only if we have available workers int rc = zmq_poll(items, zlist_size(workers) ? 2 : 1, -1); if (rc == -1) break; // Interrupted // Handle worker activity on backend if (items[0].revents & ZMQ_POLLIN) { // Use worker identity for load-balancing zmsg_t *msg = zmsg_recv(backend); if (!msg) break; // Interrupted #if 0 // zmsg_unwrap is DEPRECATED as over-engineered, poor style zframe_t *identity = zmsg_unwrap(msg); #else zframe_t *identity = zmsg_pop(msg); zframe_t *delimiter = zmsg_pop(msg); zframe_destroy(&delimiter); #endif zlist_append(workers, identity); // Forward message to client if it's not a READY zframe_t *frame = zmsg_first(msg); if (memcmp(zframe_data(frame), WORKER_READY, strlen(WORKER_READY)) == 0) { zmsg_destroy(&msg); } else { zmsg_send(&msg, frontend); if (--client_nbr == 0) break; // Exit after N messages } } if (items[1].revents & ZMQ_POLLIN) { // Get client request, route to first available worker zmsg_t *msg = zmsg_recv(frontend); if (msg) { #if 0 // zmsg_wrap is DEPRECATED as unsafe zmsg_wrap(msg, (zframe_t *)zlist_pop(workers)); #else zmsg_pushmem(msg, NULL, 0); // delimiter zmsg_push(msg, (zframe_t *)zlist_pop(workers)); #endif zmsg_send(&msg, backend); } } } // When we're done, clean up properly while (zlist_size(workers)) { zframe_t *frame = (zframe_t *)zlist_pop(workers); zframe_destroy(&frame); } zlist_destroy(&workers); zctx_destroy(&ctx); return 0; }
int main (void) { zctx_t *ctx = zctx_new (); void *frontend = zsocket_new (ctx, ZMQ_ROUTER); void *backend = zsocket_new (ctx, ZMQ_ROUTER); zsocket_bind (frontend, "tcp://*:5555"); // For clients zsocket_bind (backend, "tcp://*:5556"); // For workers // List of available workers zlist_t *workers = zlist_new (); // Send out heartbeats at regular intervals uint64_t heartbeat_at = zclock_time () + HEARTBEAT_INTERVAL; while (1) { zmq_pollitem_t items [] = { { backend, 0, ZMQ_POLLIN, 0 }, { frontend, 0, ZMQ_POLLIN, 0 } }; // Poll frontend only if we have available workers int rc = zmq_poll (items, zlist_size (workers)? 2: 1, HEARTBEAT_INTERVAL * ZMQ_POLL_MSEC); if (rc == -1) break; // Interrupted // Handle worker activity on backend if (items [0].revents & ZMQ_POLLIN) { // Use worker address for LRU routing zmsg_t *msg = zmsg_recv (backend); if (!msg) break; // Interrupted // Any sign of life from worker means it's ready zframe_t *address = zmsg_unwrap (msg); worker_t *worker = s_worker_new (address); s_worker_ready (worker, workers); // Validate control message, or return reply to client if (zmsg_size (msg) == 1) { zframe_t *frame = zmsg_first (msg); if (memcmp (zframe_data (frame), PPP_READY, 1) && memcmp (zframe_data (frame), PPP_HEARTBEAT, 1)) { printf ("E: invalid message from worker"); zmsg_dump (msg); } zmsg_destroy (&msg); } else zmsg_send (&msg, frontend); } if (items [1].revents & ZMQ_POLLIN) { // Now get next client request, route to next worker zmsg_t *msg = zmsg_recv (frontend); if (!msg) break; // Interrupted zmsg_push (msg, s_workers_next (workers)); zmsg_send (&msg, backend); } // .split handle heartbeating // We handle heartbeating after any socket activity. First we send // heartbeats to any idle workers if it's time. Then we purge any // dead workers: if (zclock_time () >= heartbeat_at) { worker_t *worker = (worker_t *) zlist_first (workers); while (worker) { zframe_send (&worker->address, backend, ZFRAME_REUSE + ZFRAME_MORE); zframe_t *frame = zframe_new (PPP_HEARTBEAT, 1); zframe_send (&frame, backend, 0); worker = (worker_t *) zlist_next (workers); } heartbeat_at = zclock_time () + HEARTBEAT_INTERVAL; } s_workers_purge (workers); } // When we're done, clean up properly while (zlist_size (workers)) { worker_t *worker = (worker_t *) zlist_pop (workers); s_worker_destroy (&worker); } zlist_destroy (&workers); zctx_destroy (&ctx); return 0; }
zmsg_t * mdcli_send (mdcli_t *self, char *service, zmsg_t **request_p) { assert (self); assert (request_p); zmsg_t *request = *request_p; // Prefix request with protocol frames // Frame 1: "MDPCxy" (six bytes, MDP/Client x.y) // Frame 2: Service name (printable string) zmsg_push (request, service); zmsg_push (request, MDPC_CLIENT); if (self->verbose) { s_console ("I: send request to '%s' service:", service); zmsg_dump (request); } int retries_left = self->retries; while (retries_left && !s_interrupted) { zmsg_t *msg = zmsg_dup (request); zmsg_send (&msg, self->client); while (!s_interrupted) { // Poll socket for a reply, with timeout zmq_pollitem_t items [] = { { self->client, 0, ZMQ_POLLIN, 0 } }; zmq_poll (items, 1, self->timeout * 1000); // If we got a reply, process it if (items [0].revents & ZMQ_POLLIN) { zmsg_t *msg = zmsg_recv (self->client); if (self->verbose) { s_console ("I: received reply:"); zmsg_dump (msg); } // Don't try to handle errors, just assert noisily assert (zmsg_parts (msg) >= 3); char *header = zmsg_pop (msg); assert (streq (header, MDPC_CLIENT)); free (header); char *reply_service = zmsg_pop (msg); assert (streq (reply_service, service)); free (reply_service); zmsg_destroy (&request); return msg; // Success } else if (--retries_left) { if (self->verbose) s_console ("W: no reply, reconnecting..."); // Reconnect, and resend message s_mdcli_connect_to_broker (self); zmsg_t *msg = zmsg_dup (request); zmsg_send (&msg, self->client); } else { if (self->verbose) s_console ("W: permanent error, abandoning request"); break; // Give up } } } if (s_interrupted) printf ("W: interrupt received, killing client...\n"); zmsg_destroy (&request); return NULL; }