zeroMQ初体验-32.发布/订阅模式进阶-克隆模式-上

来源:互联网 发布:东风风神a30abs数据 编辑:程序博客网 时间:2024/05/18 00:36
 
0顶
0踩
zeroMQ初体验-33.发布/订阅模式进阶-克隆 ... |zeroMQ初体验-31.发布/订阅模式进阶-黑盒 ...
2011-05-26

zeroMQ初体验-32.发布/订阅模式进阶-克隆模式-上

    博客分类:
  • MQ
SocketCC++C#应用服务器
在发布/订阅模式中,特别是现实应用中,总会因为这样那样的问题导致订阅者丢失了所需的数据,如此,便有了重新获得的需求。通常来说,这个会由订阅者来完成,不过"千百个哈姆雷特"从工程的角度来看,实在不忍睹,完全违背了"复用"的概念。于是乎,"克隆模式"便呼之待出了。在发布端存储下这些消息,为了避免队列的堆积这样的杯具,也为了更好的订阅体验,kev-value似乎是不错的选择。

注意:这里的kev-value并非目前红火的nosql(虽然有些类似),可以理解成发布者的数据仓库(应该可以这么理解吧)。

为了简单明了,这里将会对整个机制做一个拆解。

更新数据的存储
模型图:

服务器:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone server Model One   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. int main (void)   
  9. {   
  10.     //  Prepare our context and publisher socket  
  11.     zctx_t *ctx = zctx_new ();   
  12.     void *publisher = zsocket_new (ctx, ZMQ_PUB);   
  13.     zsocket_bind (publisher, "tcp://*:5556");   
  14.     zclock_sleep (200);   
  15.   
  16.     zhash_t *kvmap = zhash_new ();   
  17.     int64_t sequence = 0;   
  18.     srandom ((unsigned) time (NULL));   
  19.   
  20.     while (!zctx_interrupted) {   
  21.         //  Distribute as key-value message  
  22.         kvmsg_t *kvmsg = kvmsg_new (++sequence);   
  23.         kvmsg_fmt_key  (kvmsg, "%d", randof (10000));   
  24.         kvmsg_fmt_body (kvmsg, "%d", randof (1000000));   
  25.         kvmsg_send     (kvmsg, publisher);   
  26.         kvmsg_store   (&kvmsg, kvmap);   
  27.     }   
  28.     printf (" Interrupted\n%d messages out\n", (int) sequence);   
  29.     zhash_destroy (&kvmap);   
  30.     zctx_destroy (&ctx);   
  31.     return 0;   
  32. }  

客户端:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone client Model One   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. int main (void)   
  9. {   
  10.     //  Prepare our context and updates socket  
  11.     zctx_t *ctx = zctx_new ();   
  12.     void *updates = zsocket_new (ctx, ZMQ_SUB);   
  13.     zsocket_connect (updates, "tcp://localhost:5556");   
  14.   
  15.     zhash_t *kvmap = zhash_new ();   
  16.     int64_t sequence = 0;   
  17.   
  18.     while (TRUE) {   
  19.         kvmsg_t *kvmsg = kvmsg_recv (updates);   
  20.         if (!kvmsg)   
  21.             break;          //  Interrupted  
  22.         kvmsg_store (&kvmsg, kvmap);   
  23.         sequence++;   
  24.     }   
  25.     printf (" Interrupted\n%d messages in\n", (int) sequence);   
  26.     zhash_destroy (&kvmap);   
  27.     zctx_destroy (&ctx);   
  28.     return 0;   
  29. }  

key-value库:
C代码 复制代码 收藏代码
  1. /*  ===================================================================== 
  2.     kvsimple - simple key-value message class for example applications 
  3.  
  4.     --------------------------------------------------------------------- 
  5.     Copyright (c) 1991-2011 iMatix Corporation <www.imatix.com> 
  6.     Copyright other contributors as noted in the AUTHORS file. 
  7.  
  8.     This file is part of the ZeroMQ Guide: http://zguide.zeromq.org 
  9.  
  10.     This is free software; you can redistribute it and/or modify it under 
  11.     the terms of the GNU Lesser General Public License as published by 
  12.     the Free Software Foundation; either version 3 of the License, or (at 
  13.     your option) any later version.  
  14.  
  15.     This software is distributed in the hope that it will be useful, but 
  16.     WITHOUT ANY WARRANTY; without even the implied warranty of 
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
  18.     Lesser General Public License for more details. 
  19.  
  20.     You should have received a copy of the GNU Lesser General Public 
  21.     License along with this program. If not, see  
  22.     <http://www.gnu.org/licenses/>.  
  23.     ===================================================================== 
  24. */  
  25.   
  26. #include "kvsimple.h"   
  27. #include "zlist.h"   
  28.   
  29. //  Keys are short strings   
  30. #define KVMSG_KEY_MAX   255   
  31.   
  32. //  Message is formatted on wire as 4 frames:  
  33. //  frame 0: key (0MQ string)   
  34. //  frame 1: sequence (8 bytes, network order)  
  35. //  frame 2: body (blob)   
  36. #define FRAME_KEY       0   
  37. #define FRAME_SEQ       1   
  38. #define FRAME_BODY      2   
  39. #define KVMSG_FRAMES    3   
  40.   
  41. //  Structure of our class   
  42. struct _kvmsg {   
  43.     //  Presence indicators for each frame  
  44.     int present [KVMSG_FRAMES];   
  45.     //  Corresponding 0MQ message frames, if any  
  46.     zmq_msg_t frame [KVMSG_FRAMES];   
  47.     //  Key, copied into safe C string   
  48.     char key [KVMSG_KEY_MAX + 1];   
  49. };   
  50.   
  51. //  ---------------------------------------------------------------------  
  52. //  Constructor, sets sequence as provided  
  53.   
  54. kvmsg_t *   
  55. kvmsg_new (int64_t sequence)   
  56. {   
  57.     kvmsg_t   
  58.         *self;   
  59.   
  60.     self = (kvmsg_t *) zmalloc (sizeof (kvmsg_t));   
  61.     kvmsg_set_sequence (self, sequence);   
  62.     return self;   
  63. }   
  64.   
  65. //  ---------------------------------------------------------------------  
  66. //  Destructor   
  67.   
  68. //  Free shim, compatible with zhash_free_fn  
  69. void  
  70. kvmsg_free (void *ptr)   
  71. {   
  72.     if (ptr) {   
  73.         kvmsg_t *self = (kvmsg_t *) ptr;   
  74.         //  Destroy message frames if any   
  75.         int frame_nbr;   
  76.         for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++)   
  77.             if (self->present [frame_nbr])   
  78.                 zmq_msg_close (&self->frame [frame_nbr]);   
  79.   
  80.         //  Free object itself   
  81.         free (self);   
  82.     }   
  83. }   
  84.   
  85. void  
  86. kvmsg_destroy (kvmsg_t **self_p)   
  87. {   
  88.     assert (self_p);   
  89.     if (*self_p) {   
  90.         kvmsg_free (*self_p);   
  91.         *self_p = NULL;   
  92.     }   
  93. }   
  94.   
  95. //  ---------------------------------------------------------------------  
  96. //  Reads key-value message from socket, returns new kvmsg instance.  
  97.   
  98. kvmsg_t *   
  99. kvmsg_recv (void *socket)   
  100. {   
  101.     assert (socket);   
  102.     kvmsg_t *self = kvmsg_new (0);   
  103.   
  104.     //  Read all frames off the wire, reject if bogus  
  105.     int frame_nbr;   
  106.     for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {   
  107.         if (self->present [frame_nbr])   
  108.             zmq_msg_close (&self->frame [frame_nbr]);   
  109.         zmq_msg_init (&self->frame [frame_nbr]);   
  110.         self->present [frame_nbr] = 1;   
  111.         if (zmq_recvmsg (socket, &self->frame [frame_nbr], 0) == -1) {   
  112.             kvmsg_destroy (&self);   
  113.             break;   
  114.         }   
  115.         //  Verify multipart framing   
  116.         int rcvmore = (frame_nbr < KVMSG_FRAMES - 1)? 1: 0;   
  117.         if (zsockopt_rcvmore (socket) != rcvmore) {   
  118.             kvmsg_destroy (&self);   
  119.             break;   
  120.         }   
  121.     }   
  122.     return self;   
  123. }   
  124.   
  125. //  ---------------------------------------------------------------------  
  126. //  Send key-value message to socket; any empty frames are sent as such.  
  127.   
  128. void  
  129. kvmsg_send (kvmsg_t *self, void *socket)   
  130. {   
  131.     assert (self);   
  132.     assert (socket);   
  133.   
  134.     int frame_nbr;   
  135.     for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {   
  136.         zmq_msg_t copy;   
  137.         zmq_msg_init (&copy);   
  138.         if (self->present [frame_nbr])   
  139.             zmq_msg_copy (&copy, &self->frame [frame_nbr]);   
  140.         zmq_sendmsg (socket, &copy,   
  141.             (frame_nbr < KVMSG_FRAMES - 1)? ZMQ_SNDMORE: 0);   
  142.         zmq_msg_close (&copy);   
  143.     }   
  144. }   
  145.   
  146. //  ---------------------------------------------------------------------  
  147. //  Return key from last read message, if any, else NULL  
  148.   
  149. char *   
  150. kvmsg_key (kvmsg_t *self)   
  151. {   
  152.     assert (self);   
  153.     if (self->present [FRAME_KEY]) {   
  154.         if (!*self->key) {   
  155.             size_t size = zmq_msg_size (&self->frame [FRAME_KEY]);   
  156.             if (size > KVMSG_KEY_MAX)   
  157.                 size = KVMSG_KEY_MAX;   
  158.             memcpy (self->key,   
  159.                 zmq_msg_data (&self->frame [FRAME_KEY]), size);   
  160.             self->key [size] = 0;   
  161.         }   
  162.         return self->key;   
  163.     }   
  164.     else  
  165.         return NULL;   
  166. }   
  167.   
  168. //  ---------------------------------------------------------------------  
  169. //  Return sequence nbr from last read message, if any  
  170.   
  171. int64_t   
  172. kvmsg_sequence (kvmsg_t *self)   
  173. {   
  174.     assert (self);   
  175.     if (self->present [FRAME_SEQ]) {   
  176.         assert (zmq_msg_size (&self->frame [FRAME_SEQ]) == 8);   
  177.         byte *source = zmq_msg_data (&self->frame [FRAME_SEQ]);   
  178.         int64_t sequence = ((int64_t) (source [0]) << 56)   
  179.                          + ((int64_t) (source [1]) << 48)   
  180.                          + ((int64_t) (source [2]) << 40)   
  181.                          + ((int64_t) (source [3]) << 32)   
  182.                          + ((int64_t) (source [4]) << 24)   
  183.                          + ((int64_t) (source [5]) << 16)   
  184.                          + ((int64_t) (source [6]) << 8)   
  185.                          +  (int64_t) (source [7]);   
  186.         return sequence;   
  187.     }   
  188.     else  
  189.         return 0;   
  190. }   
  191.   
  192. //  ---------------------------------------------------------------------  
  193. //  Return body from last read message, if any, else NULL  
  194.   
  195. byte *   
  196. kvmsg_body (kvmsg_t *self)   
  197. {   
  198.     assert (self);   
  199.     if (self->present [FRAME_BODY])   
  200.         return (byte *) zmq_msg_data (&self->frame [FRAME_BODY]);   
  201.     else  
  202.         return NULL;   
  203. }   
  204.   
  205. //  ---------------------------------------------------------------------  
  206. //  Return body size from last read message, if any, else zero  
  207.   
  208. size_t  
  209. kvmsg_size (kvmsg_t *self)   
  210. {   
  211.     assert (self);   
  212.     if (self->present [FRAME_BODY])   
  213.         return zmq_msg_size (&self->frame [FRAME_BODY]);   
  214.     else  
  215.         return 0;   
  216. }   
  217.   
  218. //  ---------------------------------------------------------------------  
  219. //  Set message key as provided   
  220.   
  221. void  
  222. kvmsg_set_key (kvmsg_t *self, char *key)   
  223. {   
  224.     assert (self);   
  225.     zmq_msg_t *msg = &self->frame [FRAME_KEY];   
  226.     if (self->present [FRAME_KEY])   
  227.         zmq_msg_close (msg);   
  228.     zmq_msg_init_size (msg, strlen (key));   
  229.     memcpy (zmq_msg_data (msg), key, strlen (key));   
  230.     self->present [FRAME_KEY] = 1;   
  231. }   
  232.   
  233. //  ---------------------------------------------------------------------  
  234. //  Set message sequence number   
  235.   
  236. void  
  237. kvmsg_set_sequence (kvmsg_t *self, int64_t sequence)   
  238. {   
  239.     assert (self);   
  240.     zmq_msg_t *msg = &self->frame [FRAME_SEQ];   
  241.     if (self->present [FRAME_SEQ])   
  242.         zmq_msg_close (msg);   
  243.     zmq_msg_init_size (msg, 8);   
  244.   
  245.     byte *source = zmq_msg_data (msg);   
  246.     source [0] = (byte) ((sequence >> 56) & 255);   
  247.     source [1] = (byte) ((sequence >> 48) & 255);   
  248.     source [2] = (byte) ((sequence >> 40) & 255);   
  249.     source [3] = (byte) ((sequence >> 32) & 255);   
  250.     source [4] = (byte) ((sequence >> 24) & 255);   
  251.     source [5] = (byte) ((sequence >> 16) & 255);   
  252.     source [6] = (byte) ((sequence >> 8)  & 255);   
  253.     source [7] = (byte) ((sequence)       & 255);   
  254.   
  255.     self->present [FRAME_SEQ] = 1;   
  256. }   
  257.   
  258. //  ---------------------------------------------------------------------  
  259. //  Set message body   
  260.   
  261. void  
  262. kvmsg_set_body (kvmsg_t *self, byte *body, size_t size)   
  263. {   
  264.     assert (self);   
  265.     zmq_msg_t *msg = &self->frame [FRAME_BODY];   
  266.     if (self->present [FRAME_BODY])   
  267.         zmq_msg_close (msg);   
  268.     self->present [FRAME_BODY] = 1;   
  269.     zmq_msg_init_size (msg, size);   
  270.     memcpy (zmq_msg_data (msg), body, size);   
  271. }   
  272.   
  273. //  ---------------------------------------------------------------------  
  274. //  Set message key using printf format   
  275.   
  276. void  
  277. kvmsg_fmt_key (kvmsg_t *self, char *format, …)   
  278. {   
  279.     char value [KVMSG_KEY_MAX + 1];   
  280.     va_list args;   
  281.   
  282.     assert (self);   
  283.     va_start (args, format);   
  284.     vsnprintf (value, KVMSG_KEY_MAX, format, args);   
  285.     va_end (args);   
  286.     kvmsg_set_key (self, value);   
  287. }   
  288.   
  289. //  ---------------------------------------------------------------------  
  290. //  Set message body using printf format   
  291.   
  292. void  
  293. kvmsg_fmt_body (kvmsg_t *self, char *format, …)   
  294. {   
  295.     char value [255 + 1];   
  296.     va_list args;   
  297.   
  298.     assert (self);   
  299.     va_start (args, format);   
  300.     vsnprintf (value, 255, format, args);   
  301.     va_end (args);   
  302.     kvmsg_set_body (self, (byte *) value, strlen (value));   
  303. }   
  304.   
  305. //  ---------------------------------------------------------------------  
  306. //  Store entire kvmsg into hash map, if key/value are set  
  307. //  Nullifies kvmsg reference, and destroys automatically when no longer  
  308. //  needed.   
  309.   
  310. void  
  311. kvmsg_store (kvmsg_t **self_p, zhash_t *hash)   
  312. {   
  313.     assert (self_p);   
  314.     if (*self_p) {   
  315.         kvmsg_t *self = *self_p;   
  316.         assert (self);   
  317.         if (self->present [FRAME_KEY]   
  318.         &&  self->present [FRAME_BODY]) {   
  319.             zhash_update (hash, kvmsg_key (self), self);   
  320.             zhash_freefn (hash, kvmsg_key (self), kvmsg_free);   
  321.         }   
  322.         *self_p = NULL;   
  323.     }   
  324. }   
  325.   
  326. //  ---------------------------------------------------------------------  
  327. //  Dump message to stderr, for debugging and tracing  
  328.   
  329. void  
  330. kvmsg_dump (kvmsg_t *self)   
  331. {   
  332.     if (self) {   
  333.         if (!self) {   
  334.             fprintf (stderr, "NULL");   
  335.             return;   
  336.         }   
  337.         size_t size = kvmsg_size (self);   
  338.         byte  *body = kvmsg_body (self);   
  339.         fprintf (stderr, "[seq:%" PRId64 "]", kvmsg_sequence (self));   
  340.         fprintf (stderr, "[key:%s]", kvmsg_key (self));   
  341.         fprintf (stderr, "[size:%zd] ", size);   
  342.         int char_nbr;   
  343.         for (char_nbr = 0; char_nbr < size; char_nbr++)   
  344.             fprintf (stderr, "%02X", body [char_nbr]);   
  345.         fprintf (stderr, "\n");   
  346.     }   
  347.     else  
  348.         fprintf (stderr, "NULL message\n");   
  349. }   
  350.   
  351. //  ---------------------------------------------------------------------  
  352. //  Runs self test of class   
  353.   
  354. int  
  355. kvmsg_test (int verbose)   
  356. {   
  357.     kvmsg_t   
  358.         *kvmsg;   
  359.   
  360.     printf (" * kvmsg: ");   
  361.   
  362.     //  Prepare our context and sockets   
  363.     zctx_t *ctx = zctx_new ();   
  364.     void *output = zsocket_new (ctx, ZMQ_DEALER);   
  365.     int rc = zmq_bind (output, "ipc://kvmsg_selftest.ipc");   
  366.     assert (rc == 0);   
  367.     void *input = zsocket_new (ctx, ZMQ_DEALER);   
  368.     rc = zmq_connect (input, "ipc://kvmsg_selftest.ipc");   
  369.     assert (rc == 0);   
  370.   
  371.     zhash_t *kvmap = zhash_new ();   
  372.   
  373.     //  Test send and receive of simple message  
  374.     kvmsg = kvmsg_new (1);   
  375.     kvmsg_set_key  (kvmsg, "key");   
  376.     kvmsg_set_body (kvmsg, (byte *) "body", 4);   
  377.     if (verbose)   
  378.         kvmsg_dump (kvmsg);   
  379.     kvmsg_send (kvmsg, output);   
  380.     kvmsg_store (&kvmsg, kvmap);   
  381.   
  382.     kvmsg = kvmsg_recv (input);   
  383.     if (verbose)   
  384.         kvmsg_dump (kvmsg);   
  385.     assert (streq (kvmsg_key (kvmsg), "key"));   
  386.     kvmsg_store (&kvmsg, kvmap);   
  387.   
  388.     //  Shutdown and destroy all objects   
  389.     zhash_destroy (&kvmap);   
  390.     zctx_destroy (&ctx);   
  391.   
  392.     printf ("OK\n");   
  393.     return 0;   
  394. }  


根据key获取数据
其实,当订阅者可以发出key来获取数据的时候,它已经不是一个纯粹的订阅者了,或许客户端的称谓会更合适些。
模型图:


服务器:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone server Model Two   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. staticint s_send_single (char *key, void *data, void *args);   
  9. staticvoid state_manager (void *args, zctx_t *ctx, void *pipe);   
  10.   
  11. int main (void)   
  12. {   
  13.     //  Prepare our context and sockets   
  14.     zctx_t *ctx = zctx_new ();   
  15.     void *publisher = zsocket_new (ctx, ZMQ_PUB);   
  16.     zsocket_bind (publisher, "tcp://*:5557");   
  17.   
  18.     int64_t sequence = 0;   
  19.     srandom ((unsigned) time (NULL));   
  20.   
  21.     //  Start state manager and wait for synchronization signal  
  22.     void *updates = zthread_fork (ctx, state_manager, NULL);   
  23.     free (zstr_recv (updates));   
  24.   
  25.     while (!zctx_interrupted) {   
  26.         //  Distribute as key-value message  
  27.         kvmsg_t *kvmsg = kvmsg_new (++sequence);   
  28.         kvmsg_fmt_key  (kvmsg, "%d", randof (10000));   
  29.         kvmsg_fmt_body (kvmsg, "%d", randof (1000000));   
  30.         kvmsg_send     (kvmsg, publisher);   
  31.         kvmsg_send     (kvmsg, updates);   
  32.         kvmsg_destroy (&kvmsg);   
  33.     }   
  34.     printf (" Interrupted\n%d messages out\n", (int) sequence);   
  35.     zctx_destroy (&ctx);   
  36.     return 0;   
  37. }   
  38.   
  39. //  Routing information for a key-value snapshot  
  40. typedefstruct {   
  41.     void *socket;           //  ROUTER socket to send to  
  42.     zframe_t *identity;     //  Identity of peer who requested state  
  43. } kvroute_t;   
  44.   
  45. //  Send one state snapshot key-value pair to a socket  
  46. //  Hash item data is our kvmsg object, ready to send  
  47. staticint  
  48. s_send_single (char *key, void *data, void *args)   
  49. {   
  50.     kvroute_t *kvroute = (kvroute_t *) args;   
  51.     //  Send identity of recipient first   
  52.     zframe_send (&kvroute->identity,   
  53.         kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);   
  54.     kvmsg_t *kvmsg = (kvmsg_t *) data;   
  55.     kvmsg_send (kvmsg, kvroute->socket);   
  56.     return 0;   
  57. }   
  58.   
  59. //  This thread maintains the state and handles requests from  
  60. //  clients for snapshots.   
  61. //   
  62. staticvoid  
  63. state_manager (void *args, zctx_t *ctx, void *pipe)   
  64. {   
  65.     zhash_t *kvmap = zhash_new ();   
  66.   
  67.     zstr_send (pipe, "READY");   
  68.     void *snapshot = zsocket_new (ctx, ZMQ_ROUTER);   
  69.     zsocket_bind (snapshot, "tcp://*:5556");   
  70.   
  71.     zmq_pollitem_t items [] = {   
  72.         { pipe, 0, ZMQ_POLLIN, 0 },   
  73.         { snapshot, 0, ZMQ_POLLIN, 0 }   
  74.     };   
  75.     int64_t sequence = 0;       //  Current snapshot version number  
  76.     while (!zctx_interrupted) {   
  77.         int rc = zmq_poll (items, 2, -1);   
  78.         if (rc == -1 && errno == ETERM)   
  79.             break;              //  Context has been shut down  
  80.   
  81.         //  Apply state update from main thread  
  82.         if (items [0].revents & ZMQ_POLLIN) {   
  83.             kvmsg_t *kvmsg = kvmsg_recv (pipe);   
  84.             if (!kvmsg)   
  85.                 break;          //  Interrupted  
  86.             sequence = kvmsg_sequence (kvmsg);   
  87.             kvmsg_store (&kvmsg, kvmap);   
  88.         }   
  89.         //  Execute state snapshot request  
  90.         if (items [1].revents & ZMQ_POLLIN) {   
  91.             zframe_t *identity = zframe_recv (snapshot);   
  92.             if (!identity)   
  93.                 break;          //  Interrupted  
  94.   
  95.             //  Request is in second frame of message  
  96.             char *request = zstr_recv (snapshot);   
  97.             if (streq (request, "ICANHAZ?"))   
  98.                 free (request);   
  99.             else {   
  100.                 printf ("E: bad request, aborting\n");   
  101.                 break;   
  102.             }   
  103.             //  Send state snapshot to client  
  104.             kvroute_t routing = { snapshot, identity };   
  105.   
  106.             //  For each entry in kvmap, send kvmsg to client  
  107.             zhash_foreach (kvmap, s_send_single, &routing);   
  108.   
  109.             //  Now send END message with sequence number  
  110.             printf ("Sending state shapshot=%d\n", (int) sequence);   
  111.             zframe_send (&identity, snapshot, ZFRAME_MORE);   
  112.             kvmsg_t *kvmsg = kvmsg_new (sequence);   
  113.             kvmsg_set_key  (kvmsg, "KTHXBAI");   
  114.             kvmsg_set_body (kvmsg, (byte *) "", 0);   
  115.             kvmsg_send     (kvmsg, snapshot);   
  116.             kvmsg_destroy (&kvmsg);   
  117.         }   
  118.     }   
  119.     zhash_destroy (&kvmap);   
  120. }  

客户端:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone client Model Two   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. int main (void)   
  9. {   
  10.     //  Prepare our context and subscriber  
  11.     zctx_t *ctx = zctx_new ();   
  12.     void *snapshot = zsocket_new (ctx, ZMQ_DEALER);   
  13.     zsocket_connect (snapshot, "tcp://localhost:5556");   
  14.     void *subscriber = zsocket_new (ctx, ZMQ_SUB);   
  15.     zsocket_connect (subscriber, "tcp://localhost:5557");   
  16.   
  17.     zhash_t *kvmap = zhash_new ();   
  18.   
  19.     //  Get state snapshot   
  20.     int64_t sequence = 0;   
  21.     zstr_send (snapshot, "ICANHAZ?");   
  22.     while (TRUE) {   
  23.         kvmsg_t *kvmsg = kvmsg_recv (snapshot);   
  24.         if (!kvmsg)   
  25.             break;          //  Interrupted  
  26.         if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {   
  27.             sequence = kvmsg_sequence (kvmsg);   
  28.             printf ("Received snapshot=%d\n", (int) sequence);   
  29.             kvmsg_destroy (&kvmsg);   
  30.             break;          //  Done  
  31.         }   
  32.         kvmsg_store (&kvmsg, kvmap);   
  33.     }   
  34.     //  Now apply pending updates, discard out-of-sequence messages  
  35.     while (!zctx_interrupted) {   
  36.         kvmsg_t *kvmsg = kvmsg_recv (subscriber);   
  37.         if (!kvmsg)   
  38.             break;          //  Interrupted  
  39.         if (kvmsg_sequence (kvmsg) > sequence) {   
  40.             sequence = kvmsg_sequence (kvmsg);   
  41.             kvmsg_store (&kvmsg, kvmap);   
  42.         }   
  43.         else  
  44.             kvmsg_destroy (&kvmsg);   
  45.     }   
  46.     zhash_destroy (&kvmap);   
  47.     zctx_destroy (&ctx);   
  48.     return 0;   
  49. }  


重新发布更新
上面的模型中,数据都集中在一点,或许会有服务器崩溃而导致数据丢失的顾虑,那么,把数据放到客户端呢?
模型图:

服务器:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone server Model Three   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. staticint s_send_single (char *key, void *data, void *args);   
  9.   
  10. //  Routing information for a key-value snapshot  
  11. typedefstruct {   
  12.     void *socket;           //  ROUTER socket to send to  
  13.     zframe_t *identity;     //  Identity of peer who requested state  
  14. } kvroute_t;   
  15.   
  16. int main (void)   
  17. {   
  18.     //  Prepare our context and sockets   
  19.     zctx_t *ctx = zctx_new ();   
  20.     void *snapshot = zsocket_new (ctx, ZMQ_ROUTER);   
  21.     zsocket_bind (snapshot, "tcp://*:5556");   
  22.     void *publisher = zsocket_new (ctx, ZMQ_PUB);   
  23.     zsocket_bind (publisher, "tcp://*:5557");   
  24.     void *collector = zsocket_new (ctx, ZMQ_PULL);   
  25.     zsocket_bind (collector, "tcp://*:5558");   
  26.   
  27.     int64_t sequence = 0;   
  28.     zhash_t *kvmap = zhash_new ();   
  29.   
  30.     zmq_pollitem_t items [] = {   
  31.         { collector, 0, ZMQ_POLLIN, 0 },   
  32.         { snapshot, 0, ZMQ_POLLIN, 0 }   
  33.     };   
  34.     while (!zctx_interrupted) {   
  35.         int rc = zmq_poll (items, 2, 1000 * ZMQ_POLL_MSEC);   
  36.   
  37.         //  Apply state update sent from client  
  38.         if (items [0].revents & ZMQ_POLLIN) {   
  39.             kvmsg_t *kvmsg = kvmsg_recv (collector);   
  40.             if (!kvmsg)   
  41.                 break;          //  Interrupted  
  42.             kvmsg_set_sequence (kvmsg, ++sequence);   
  43.             kvmsg_send (kvmsg, publisher);   
  44.             kvmsg_store (&kvmsg, kvmap);   
  45.             printf ("I: publishing update %5d\n", (int) sequence);   
  46.         }   
  47.         //  Execute state snapshot request  
  48.         if (items [1].revents & ZMQ_POLLIN) {   
  49.             zframe_t *identity = zframe_recv (snapshot);   
  50.             if (!identity)   
  51.                 break;          //  Interrupted  
  52.   
  53.             //  Request is in second frame of message  
  54.             char *request = zstr_recv (snapshot);   
  55.             if (streq (request, "ICANHAZ?"))   
  56.                 free (request);   
  57.             else {   
  58.                 printf ("E: bad request, aborting\n");   
  59.                 break;   
  60.             }   
  61.             //  Send state snapshot to client  
  62.             kvroute_t routing = { snapshot, identity };   
  63.   
  64.             //  For each entry in kvmap, send kvmsg to client  
  65.             zhash_foreach (kvmap, s_send_single, &routing);   
  66.   
  67.             //  Now send END message with sequence number  
  68.             printf ("I: sending shapshot=%d\n", (int) sequence);   
  69.             zframe_send (&identity, snapshot, ZFRAME_MORE);   
  70.             kvmsg_t *kvmsg = kvmsg_new (sequence);   
  71.             kvmsg_set_key  (kvmsg, "KTHXBAI");   
  72.             kvmsg_set_body (kvmsg, (byte *) "", 0);   
  73.             kvmsg_send     (kvmsg, snapshot);   
  74.             kvmsg_destroy (&kvmsg);   
  75.         }   
  76.     }   
  77.     printf (" Interrupted\n%d messages handled\n", (int) sequence);   
  78.     zhash_destroy (&kvmap);   
  79.     zctx_destroy (&ctx);   
  80.   
  81.     return 0;   
  82. }   
  83.   
  84. //  Send one state snapshot key-value pair to a socket  
  85. //  Hash item data is our kvmsg object, ready to send  
  86. staticint  
  87. s_send_single (char *key, void *data, void *args)   
  88. {   
  89.     kvroute_t *kvroute = (kvroute_t *) args;   
  90.     //  Send identity of recipient first   
  91.     zframe_send (&kvroute->identity,   
  92.         kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);   
  93.     kvmsg_t *kvmsg = (kvmsg_t *) data;   
  94.     kvmsg_send (kvmsg, kvroute->socket);   
  95.     return 0;   
  96. }  

客户端:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone client Model Three   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. int main (void)   
  9. {   
  10.     //  Prepare our context and subscriber  
  11.     zctx_t *ctx = zctx_new ();   
  12.     void *snapshot = zsocket_new (ctx, ZMQ_DEALER);   
  13.     zsocket_connect (snapshot, "tcp://localhost:5556");   
  14.     void *subscriber = zsocket_new (ctx, ZMQ_SUB);   
  15.     zsocket_connect (subscriber, "tcp://localhost:5557");   
  16.     void *publisher = zsocket_new (ctx, ZMQ_PUSH);   
  17.     zsocket_connect (publisher, "tcp://localhost:5558");   
  18.   
  19.     zhash_t *kvmap = zhash_new ();   
  20.     srandom ((unsigned) time (NULL));   
  21.   
  22.     //  Get state snapshot   
  23.     int64_t sequence = 0;   
  24.     zstr_send (snapshot, "ICANHAZ?");   
  25.     while (TRUE) {   
  26.         kvmsg_t *kvmsg = kvmsg_recv (snapshot);   
  27.         if (!kvmsg)   
  28.             break;          //  Interrupted  
  29.         if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {   
  30.             sequence = kvmsg_sequence (kvmsg);   
  31.             printf ("I: received snapshot=%d\n", (int) sequence);   
  32.             kvmsg_destroy (&kvmsg);   
  33.             break;          //  Done  
  34.         }   
  35.         kvmsg_store (&kvmsg, kvmap);   
  36.     }   
  37.     int64_t alarm = zclock_time () + 1000;   
  38.     while (!zctx_interrupted) {   
  39.         zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } };   
  40.         int tickless = (int) ((alarm - zclock_time ()));   
  41.         if (tickless < 0)   
  42.             tickless = 0;   
  43.         int rc = zmq_poll (items, 1, tickless * ZMQ_POLL_MSEC);   
  44.         if (rc == -1)   
  45.             break;              //  Context has been shut down  
  46.   
  47.         if (items [0].revents & ZMQ_POLLIN) {   
  48.             kvmsg_t *kvmsg = kvmsg_recv (subscriber);   
  49.             if (!kvmsg)   
  50.                 break;          //  Interrupted  
  51.   
  52.             //  Discard out-of-sequence kvmsgs, incl. heartbeats  
  53.             if (kvmsg_sequence (kvmsg) > sequence) {   
  54.                 sequence = kvmsg_sequence (kvmsg);   
  55.                 kvmsg_store (&kvmsg, kvmap);   
  56.                 printf ("I: received update=%d\n", (int) sequence);   
  57.             }   
  58.             else  
  59.                 kvmsg_destroy (&kvmsg);   
  60.         }   
  61.         //  If we timed-out, generate a random kvmsg  
  62.         if (zclock_time () >= alarm) {   
  63.             kvmsg_t *kvmsg = kvmsg_new (0);   
  64.             kvmsg_fmt_key  (kvmsg, "%d", randof (10000));   
  65.             kvmsg_fmt_body (kvmsg, "%d", randof (1000000));   
  66.             kvmsg_send     (kvmsg, publisher);   
  67.             kvmsg_destroy (&kvmsg);   
  68.             alarm = zclock_time () + 1000;   
  69.         }   
  70.     }   
  71.     printf (" Interrupted\n%d messages in\n", (int) sequence);   
  72.     zhash_destroy (&kvmap);   
  73.     zctx_destroy (&ctx);   
  74.     return 0;   
  75. }  

克隆子树
事实上,并不是所有的消费者都愿意消费发布者所提供的所有信息,那么,针对特别的群体,只需提供一个子集就可以了。
服务器:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone server Model Four   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. staticint s_send_single (char *key, void *data, void *args);   
  9.   
  10. //  Routing information for a key-value snapshot  
  11. typedefstruct {   
  12.     void *socket;           //  ROUTER socket to send to  
  13.     zframe_t *identity;     //  Identity of peer who requested state  
  14.     char *subtree;          //  Client subtree specification  
  15. } kvroute_t;   
  16.   
  17. int main (void)   
  18. {   
  19.     //  Prepare our context and sockets   
  20.     zctx_t *ctx = zctx_new ();   
  21.     void *snapshot = zsocket_new (ctx, ZMQ_ROUTER);   
  22.     zsocket_bind (snapshot, "tcp://*:5556");   
  23.     void *publisher = zsocket_new (ctx, ZMQ_PUB);   
  24.     zsocket_bind (publisher, "tcp://*:5557");   
  25.     void *collector = zsocket_new (ctx, ZMQ_PULL);   
  26.     zsocket_bind (collector, "tcp://*:5558");   
  27.   
  28.     int64_t sequence = 0;   
  29.     zhash_t *kvmap = zhash_new ();   
  30.   
  31.     zmq_pollitem_t items [] = {   
  32.         { collector, 0, ZMQ_POLLIN, 0 },   
  33.         { snapshot, 0, ZMQ_POLLIN, 0 }   
  34.     };   
  35.     while (!zctx_interrupted) {   
  36.         int rc = zmq_poll (items, 2, 1000 * ZMQ_POLL_MSEC);   
  37.   
  38.         //  Apply state update sent from client  
  39.         if (items [0].revents & ZMQ_POLLIN) {   
  40.             kvmsg_t *kvmsg = kvmsg_recv (collector);   
  41.             if (!kvmsg)   
  42.                 break;          //  Interrupted  
  43.             kvmsg_set_sequence (kvmsg, ++sequence);   
  44.             kvmsg_send (kvmsg, publisher);   
  45.             kvmsg_store (&kvmsg, kvmap);   
  46.             printf ("I: publishing update %5d\n", (int) sequence);   
  47.         }   
  48.         //  Execute state snapshot request  
  49.         if (items [1].revents & ZMQ_POLLIN) {   
  50.             zframe_t *identity = zframe_recv (snapshot);   
  51.             if (!identity)   
  52.                 break;          //  Interrupted  
  53.   
  54.             //  Request is in second frame of message  
  55.             char *request = zstr_recv (snapshot);   
  56.             char *subtree = NULL;   
  57.             if (streq (request, "ICANHAZ?")) {   
  58.                 free (request);   
  59.                 subtree = zstr_recv (snapshot);   
  60.             }   
  61.             else {   
  62.                 printf ("E: bad request, aborting\n");   
  63.                 break;   
  64.             }   
  65.             //  Send state snapshot to client  
  66.             kvroute_t routing = { snapshot, identity, subtree };   
  67.   
  68.             //  For each entry in kvmap, send kvmsg to client  
  69.             zhash_foreach (kvmap, s_send_single, &routing);   
  70.   
  71.             //  Now send END message with sequence number  
  72.             printf ("I: sending shapshot=%d\n", (int) sequence);   
  73.             zframe_send (&identity, snapshot, ZFRAME_MORE);   
  74.             kvmsg_t *kvmsg = kvmsg_new (sequence);   
  75.             kvmsg_set_key  (kvmsg, "KTHXBAI");   
  76.             kvmsg_set_body (kvmsg, (byte *) subtree, 0);   
  77.             kvmsg_send     (kvmsg, snapshot);   
  78.             kvmsg_destroy (&kvmsg);   
  79.             free (subtree);   
  80.         }   
  81.     }   
  82.     printf (" Interrupted\n%d messages handled\n", (int) sequence);   
  83.     zhash_destroy (&kvmap);   
  84.     zctx_destroy (&ctx);   
  85.   
  86.     return 0;   
  87. }   
  88.   
  89. //  Send one state snapshot key-value pair to a socket  
  90. //  Hash item data is our kvmsg object, ready to send  
  91. staticint  
  92. s_send_single (char *key, void *data, void *args)   
  93. {   
  94.     kvroute_t *kvroute = (kvroute_t *) args;   
  95.     kvmsg_t *kvmsg = (kvmsg_t *) data;   
  96.     if (strlen (kvroute->subtree) <= strlen (kvmsg_key (kvmsg))   
  97.     &&  memcmp (kvroute->subtree,   
  98.                 kvmsg_key (kvmsg), strlen (kvroute->subtree)) == 0) {   
  99.         //  Send identity of recipient first  
  100.         zframe_send (&kvroute->identity,   
  101.             kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);   
  102.         kvmsg_send (kvmsg, kvroute->socket);   
  103.     }   
  104.     return 0;   
  105. }  

客户端:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone client Model Four   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvsimple.c"   
  7.   
  8. #define SUBTREE "/client/"   
  9.   
  10. int main (void)   
  11. {   
  12.     //  Prepare our context and subscriber  
  13.     zctx_t *ctx = zctx_new ();   
  14.     void *snapshot = zsocket_new (ctx, ZMQ_DEALER);   
  15.     zsocket_connect (snapshot, "tcp://localhost:5556");   
  16.     void *subscriber = zsocket_new (ctx, ZMQ_SUB);   
  17.     zsocket_connect (subscriber, "tcp://localhost:5557");   
  18.     zsockopt_set_subscribe (subscriber, SUBTREE);   
  19.     void *publisher = zsocket_new (ctx, ZMQ_PUSH);   
  20.     zsocket_connect (publisher, "tcp://localhost:5558");   
  21.   
  22.     zhash_t *kvmap = zhash_new ();   
  23.     srandom ((unsigned) time (NULL));   
  24.   
  25.     //  Get state snapshot   
  26.     int64_t sequence = 0;   
  27.     zstr_sendm (snapshot, "ICANHAZ?");   
  28.     zstr_send  (snapshot, SUBTREE);   
  29.     while (TRUE) {   
  30.         kvmsg_t *kvmsg = kvmsg_recv (snapshot);   
  31.         if (!kvmsg)   
  32.             break;          //  Interrupted  
  33.         if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {   
  34.             sequence = kvmsg_sequence (kvmsg);   
  35.             printf ("I: received snapshot=%d\n", (int) sequence);   
  36.             kvmsg_destroy (&kvmsg);   
  37.             break;          //  Done  
  38.         }   
  39.         kvmsg_store (&kvmsg, kvmap);   
  40.     }   
  41.   
  42.     int64_t alarm = zclock_time () + 1000;   
  43.     while (!zctx_interrupted) {   
  44.         zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } };   
  45.         int tickless = (int) ((alarm - zclock_time ()));   
  46.         if (tickless < 0)   
  47.             tickless = 0;   
  48.         int rc = zmq_poll (items, 1, tickless * ZMQ_POLL_MSEC);   
  49.         if (rc == -1)   
  50.             break;              //  Context has been shut down  
  51.   
  52.         if (items [0].revents & ZMQ_POLLIN) {   
  53.             kvmsg_t *kvmsg = kvmsg_recv (subscriber);   
  54.             if (!kvmsg)   
  55.                 break;          //  Interrupted  
  56.   
  57.             //  Discard out-of-sequence kvmsgs, incl. heartbeats  
  58.             if (kvmsg_sequence (kvmsg) > sequence) {   
  59.                 sequence = kvmsg_sequence (kvmsg);   
  60.                 kvmsg_store (&kvmsg, kvmap);   
  61.                 printf ("I: received update=%d\n", (int) sequence);   
  62.             }   
  63.             else  
  64.                 kvmsg_destroy (&kvmsg);   
  65.         }   
  66.         //  If we timed-out, generate a random kvmsg  
  67.         if (zclock_time () >= alarm) {   
  68.             kvmsg_t *kvmsg = kvmsg_new (0);   
  69.             kvmsg_fmt_key  (kvmsg, "%s%d", SUBTREE, randof (10000));   
  70.             kvmsg_fmt_body (kvmsg, "%d", randof (1000000));   
  71.             kvmsg_send     (kvmsg, publisher);   
  72.             kvmsg_destroy (&kvmsg);   
  73.             alarm = zclock_time () + 1000;   
  74.         }   
  75.     }   
  76.     printf (" Interrupted\n%d messages in\n", (int) sequence);   
  77.     zhash_destroy (&kvmap);   
  78.     zctx_destroy (&ctx);   
  79.     return 0;