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; }
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://127.0.0.1:5555"); zsocket_bind(backend, "tcp://127.0.0.1:5556"); zlist_t *workers = zlist_new(); uint64_t heartbeat_at = zclock_time() + HEARTBEAT_INTERVAL; while (true){ zmq_pollitem_t items [] ={ {backend, 0, ZMQ_POLLIN, 0}, {frontend, 0, ZMQ_POLLIN, 0} }; int rc = zmq_poll(items, zlist_size(worker)?2:1); if (rc == -1) break; if (items[0].revents & ZMQ_POLLIN){ zmsg_t *msg = zmsg_recv(backend); if (!msg) break; zframe_t *identity = zmsg_unwrap(msg); worker_t *worker = s_worker_new(identity); s_worker_ready(worker, workers); 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){ zmsg_t *msg = zmsg_recv(frontend); if (!msg) break; zframe_t *identity = s_workers_next(workers); zmsg_prepend(msg, &identity); zmsg_send(&msg, backend); } if (zclock_time() >= heartbeat_at){ worker_t *worker = (worker_t *)zlist_first(workers); while (worker){ zframe_send(&worker->identity, 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); } while (zlist_size(workers)){ worker_t *worker = (worker_t *)zlist_pop(workers); s_worker_destroy(&worker); } zlist_destroy(&workers); zctx_destroy(&ctx); return 0; }