zeromq client-server 异步模式
View Code
1 // 2 // Asynchronous client-to-server (DEALER to ROUTER) 3 // 4 // While this example runs in a single process, that is just to make 5 // it easier to start and stop the example. Each task has its own 6 // context and conceptually acts as a separate process. 7 8 #include "czmq.h" 9 10 // --------------------------------------------------------------------- 11 // This is our client task 12 // It connects to the server, and then sends a request once per second 13 // It collects responses as they arrive, and it prints them out. We will 14 // run several client tasks in parallel, each with a different random ID. 15 16 static void * 17 client_task (void *args) 18 { 19 zctx_t *ctx = zctx_new (); 20 void *client = zsocket_new (ctx, ZMQ_DEALER); 21 22 // Set random identity to make tracing easier 23 char identity [10]; 24 sprintf (identity, "%04X-%04X", randof (0x10000), randof (0x10000)); 25 zsockopt_set_identity (client, identity); 26 zsocket_connect (client, "tcp://localhost:5570"); 27 28 zmq_pollitem_t items [] = { { client, 0, ZMQ_POLLIN, 0 } }; 29 int request_nbr = 0; 30 while (1) { 31 // Tick once per second, pulling in arriving messages 32 int centitick; 33 for (centitick = 0; centitick < 100; centitick++) { 34 zmq_poll (items, 1, 10 * ZMQ_POLL_MSEC); 35 if (items [0].revents & ZMQ_POLLIN) { 36 zmsg_t *msg = zmsg_recv (client); 37 zframe_print (zmsg_last (msg), identity); 38 zmsg_destroy (&msg); 39 } 40 } 41 zstr_sendf (client, "request #%d", ++request_nbr); 42 } 43 zctx_destroy (&ctx); 44 return NULL; 45 } 46 47 // This is our server task. 48 // It uses the multithreaded server model to deal requests out to a pool 49 // of workers and route replies back to clients. One worker can handle 50 // one request at a time but one client can talk to multiple workers at 51 // once. 52 53 static void server_worker (void *args, zctx_t *ctx, void *pipe); 54 55 void *server_task (void *args) 56 { 57 zctx_t *ctx = zctx_new (); 58 59 // Frontend socket talks to clients over TCP 60 void *frontend = zsocket_new (ctx, ZMQ_ROUTER); 61 zsocket_bind (frontend, "tcp://*:5570"); 62 63 // Backend socket talks to workers over inproc 64 void *backend = zsocket_new (ctx, ZMQ_DEALER); 65 zsocket_bind (backend, "inproc://backend"); 66 67 // Launch pool of worker threads, precise number is not critical 68 int thread_nbr; 69 for (thread_nbr = 0; thread_nbr < 5; thread_nbr++) 70 zthread_fork (ctx, server_worker, NULL); 71 72 // Connect backend to frontend via a queue device 73 // We could do this: 74 // zmq_device (ZMQ_QUEUE, frontend, backend); 75 // But doing it ourselves means we can debug this more easily 76 77 // Switch messages between frontend and backend 78 while (1) { 79 zmq_pollitem_t items [] = { 80 { frontend, 0, ZMQ_POLLIN, 0 }, 81 { backend, 0, ZMQ_POLLIN, 0 } 82 }; 83 zmq_poll (items, 2, -1); 84 if (items [0].revents & ZMQ_POLLIN) { 85 zmsg_t *msg = zmsg_recv (frontend); 86 zmsg_send (&msg, backend); 87 } 88 if (items [1].revents & ZMQ_POLLIN) { 89 zmsg_t *msg = zmsg_recv (backend); 90 zmsg_send (&msg, frontend); 91 } 92 } 93 zctx_destroy (&ctx); 94 return NULL; 95 } 96 97 // Each worker task works on one request at a time and sends a random number 98 // of replies back, with random delays between replies: 99 100 static void 101 server_worker (void *args, zctx_t *ctx, void *pipe) 102 { 103 void *worker = zsocket_new (ctx, ZMQ_DEALER); 104 zsocket_connect (worker, "inproc://backend"); 105 106 while (1) { 107 // The DEALER socket gives us the address envelope and message 108 zmsg_t *msg = zmsg_recv (worker); 109 zframe_t *address = zmsg_pop (msg); 110 zframe_t *content = zmsg_pop (msg); 111 assert (content); 112 zmsg_destroy (&msg); 113 114 // Send 0..4 replies back 115 int reply, replies = randof (5); 116 for (reply = 0; reply < replies; reply++) { 117 // Sleep for some fraction of a second 118 zclock_sleep (randof (1000) + 1); 119 zframe_send (&address, worker, ZFRAME_REUSE + ZFRAME_MORE); 120 zframe_send (&content, worker, ZFRAME_REUSE); 121 } 122 zframe_destroy (&address); 123 zframe_destroy (&content); 124 } 125 } 126 127 // The main thread simply starts several clients, and a server, and then 128 // waits for the server to finish. 129 130 int main (void) 131 { 132 zctx_t *ctx = zctx_new (); 133 zthread_new (client_task, NULL); 134 zthread_new (client_task, NULL); 135 zthread_new (client_task, NULL); 136 zthread_new (server_task, NULL); 137 138 // Run for 5 seconds then quit 139 zclock_sleep (5 * 1000); 140 zctx_destroy (&ctx); 141 return 0; 142 }