zeroMQ初体验-32.发布/订阅模式进阶-克隆模式-上
来源:互联网 发布:东风风神a30abs数据 编辑:程序博客网 时间:2024/05/18 00:36
0顶
0踩
0踩
zeroMQ初体验-33.发布/订阅模式进阶-克隆 ... |zeroMQ初体验-31.发布/订阅模式进阶-黑盒 ...
2011-05-26
zeroMQ初体验-32.发布/订阅模式进阶-克隆模式-上
- 博客分类:
- MQ
SocketCC++C#应用服务器
在发布/订阅模式中,特别是现实应用中,总会因为这样那样的问题导致订阅者丢失了所需的数据,如此,便有了重新获得的需求。通常来说,这个会由订阅者来完成,不过"千百个哈姆雷特"从工程的角度来看,实在不忍睹,完全违背了"复用"的概念。于是乎,"克隆模式"便呼之待出了。在发布端存储下这些消息,为了避免队列的堆积这样的杯具,也为了更好的订阅体验,kev-value似乎是不错的选择。
注意:这里的kev-value并非目前红火的nosql(虽然有些类似),可以理解成发布者的数据仓库(应该可以这么理解吧)。
为了简单明了,这里将会对整个机制做一个拆解。
更新数据的存储
模型图:
服务器:
客户端:
key-value库:
根据key获取数据
其实,当订阅者可以发出key来获取数据的时候,它已经不是一个纯粹的订阅者了,或许客户端的称谓会更合适些。
模型图:
服务器:
客户端:
重新发布更新
上面的模型中,数据都集中在一点,或许会有服务器崩溃而导致数据丢失的顾虑,那么,把数据放到客户端呢?
模型图:
服务器:
客户端:
克隆子树
事实上,并不是所有的消费者都愿意消费发布者所提供的所有信息,那么,针对特别的群体,只需提供一个子集就可以了。
服务器:
客户端:
注意:这里的kev-value并非目前红火的nosql(虽然有些类似),可以理解成发布者的数据仓库(应该可以这么理解吧)。
为了简单明了,这里将会对整个机制做一个拆解。
更新数据的存储
模型图:
服务器:
- //
- // Clone server Model One
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- int main (void)
- {
- // Prepare our context and publisher socket
- zctx_t *ctx = zctx_new ();
- void *publisher = zsocket_new (ctx, ZMQ_PUB);
- zsocket_bind (publisher, "tcp://*:5556");
- zclock_sleep (200);
- zhash_t *kvmap = zhash_new ();
- int64_t sequence = 0;
- srandom ((unsigned) time (NULL));
- while (!zctx_interrupted) {
- // Distribute as key-value message
- kvmsg_t *kvmsg = kvmsg_new (++sequence);
- kvmsg_fmt_key (kvmsg, "%d", randof (10000));
- kvmsg_fmt_body (kvmsg, "%d", randof (1000000));
- kvmsg_send (kvmsg, publisher);
- kvmsg_store (&kvmsg, kvmap);
- }
- printf (" Interrupted\n%d messages out\n", (int) sequence);
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- return 0;
- }
//// Clone server Model One//// Lets us build this source without creating a library#include "kvsimple.c"int main (void){ // Prepare our context and publisher socket zctx_t *ctx = zctx_new (); void *publisher = zsocket_new (ctx, ZMQ_PUB); zsocket_bind (publisher, "tcp://*:5556"); zclock_sleep (200); zhash_t *kvmap = zhash_new (); int64_t sequence = 0; srandom ((unsigned) time (NULL)); while (!zctx_interrupted) { // Distribute as key-value message kvmsg_t *kvmsg = kvmsg_new (++sequence); kvmsg_fmt_key (kvmsg, "%d", randof (10000)); kvmsg_fmt_body (kvmsg, "%d", randof (1000000)); kvmsg_send (kvmsg, publisher); kvmsg_store (&kvmsg, kvmap); } printf (" Interrupted\n%d messages out\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0;}
客户端:
- //
- // Clone client Model One
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- int main (void)
- {
- // Prepare our context and updates socket
- zctx_t *ctx = zctx_new ();
- void *updates = zsocket_new (ctx, ZMQ_SUB);
- zsocket_connect (updates, "tcp://localhost:5556");
- zhash_t *kvmap = zhash_new ();
- int64_t sequence = 0;
- while (TRUE) {
- kvmsg_t *kvmsg = kvmsg_recv (updates);
- if (!kvmsg)
- break; // Interrupted
- kvmsg_store (&kvmsg, kvmap);
- sequence++;
- }
- printf (" Interrupted\n%d messages in\n", (int) sequence);
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- return 0;
- }
//// Clone client Model One//// Lets us build this source without creating a library#include "kvsimple.c"int main (void){ // Prepare our context and updates socket zctx_t *ctx = zctx_new (); void *updates = zsocket_new (ctx, ZMQ_SUB); zsocket_connect (updates, "tcp://localhost:5556"); zhash_t *kvmap = zhash_new (); int64_t sequence = 0; while (TRUE) { kvmsg_t *kvmsg = kvmsg_recv (updates); if (!kvmsg) break; // Interrupted kvmsg_store (&kvmsg, kvmap); sequence++; } printf (" Interrupted\n%d messages in\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0;}
key-value库:
- /* =====================================================================
- kvsimple - simple key-value message class for example applications
- ---------------------------------------------------------------------
- Copyright (c) 1991-2011 iMatix Corporation <www.imatix.com>
- Copyright other contributors as noted in the AUTHORS file.
- This file is part of the ZeroMQ Guide: http://zguide.zeromq.org
- This is free software; you can redistribute it and/or modify it under
- the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 3 of the License, or (at
- your option) any later version.
- This software is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this program. If not, see
- <http://www.gnu.org/licenses/>.
- =====================================================================
- */
- #include "kvsimple.h"
- #include "zlist.h"
- // Keys are short strings
- #define KVMSG_KEY_MAX 255
- // Message is formatted on wire as 4 frames:
- // frame 0: key (0MQ string)
- // frame 1: sequence (8 bytes, network order)
- // frame 2: body (blob)
- #define FRAME_KEY 0
- #define FRAME_SEQ 1
- #define FRAME_BODY 2
- #define KVMSG_FRAMES 3
- // Structure of our class
- struct _kvmsg {
- // Presence indicators for each frame
- int present [KVMSG_FRAMES];
- // Corresponding 0MQ message frames, if any
- zmq_msg_t frame [KVMSG_FRAMES];
- // Key, copied into safe C string
- char key [KVMSG_KEY_MAX + 1];
- };
- // ---------------------------------------------------------------------
- // Constructor, sets sequence as provided
- kvmsg_t *
- kvmsg_new (int64_t sequence)
- {
- kvmsg_t
- *self;
- self = (kvmsg_t *) zmalloc (sizeof (kvmsg_t));
- kvmsg_set_sequence (self, sequence);
- return self;
- }
- // ---------------------------------------------------------------------
- // Destructor
- // Free shim, compatible with zhash_free_fn
- void
- kvmsg_free (void *ptr)
- {
- if (ptr) {
- kvmsg_t *self = (kvmsg_t *) ptr;
- // Destroy message frames if any
- int frame_nbr;
- for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++)
- if (self->present [frame_nbr])
- zmq_msg_close (&self->frame [frame_nbr]);
- // Free object itself
- free (self);
- }
- }
- void
- kvmsg_destroy (kvmsg_t **self_p)
- {
- assert (self_p);
- if (*self_p) {
- kvmsg_free (*self_p);
- *self_p = NULL;
- }
- }
- // ---------------------------------------------------------------------
- // Reads key-value message from socket, returns new kvmsg instance.
- kvmsg_t *
- kvmsg_recv (void *socket)
- {
- assert (socket);
- kvmsg_t *self = kvmsg_new (0);
- // Read all frames off the wire, reject if bogus
- int frame_nbr;
- for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {
- if (self->present [frame_nbr])
- zmq_msg_close (&self->frame [frame_nbr]);
- zmq_msg_init (&self->frame [frame_nbr]);
- self->present [frame_nbr] = 1;
- if (zmq_recvmsg (socket, &self->frame [frame_nbr], 0) == -1) {
- kvmsg_destroy (&self);
- break;
- }
- // Verify multipart framing
- int rcvmore = (frame_nbr < KVMSG_FRAMES - 1)? 1: 0;
- if (zsockopt_rcvmore (socket) != rcvmore) {
- kvmsg_destroy (&self);
- break;
- }
- }
- return self;
- }
- // ---------------------------------------------------------------------
- // Send key-value message to socket; any empty frames are sent as such.
- void
- kvmsg_send (kvmsg_t *self, void *socket)
- {
- assert (self);
- assert (socket);
- int frame_nbr;
- for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {
- zmq_msg_t copy;
- zmq_msg_init (©);
- if (self->present [frame_nbr])
- zmq_msg_copy (©, &self->frame [frame_nbr]);
- zmq_sendmsg (socket, ©,
- (frame_nbr < KVMSG_FRAMES - 1)? ZMQ_SNDMORE: 0);
- zmq_msg_close (©);
- }
- }
- // ---------------------------------------------------------------------
- // Return key from last read message, if any, else NULL
- char *
- kvmsg_key (kvmsg_t *self)
- {
- assert (self);
- if (self->present [FRAME_KEY]) {
- if (!*self->key) {
- size_t size = zmq_msg_size (&self->frame [FRAME_KEY]);
- if (size > KVMSG_KEY_MAX)
- size = KVMSG_KEY_MAX;
- memcpy (self->key,
- zmq_msg_data (&self->frame [FRAME_KEY]), size);
- self->key [size] = 0;
- }
- return self->key;
- }
- else
- return NULL;
- }
- // ---------------------------------------------------------------------
- // Return sequence nbr from last read message, if any
- int64_t
- kvmsg_sequence (kvmsg_t *self)
- {
- assert (self);
- if (self->present [FRAME_SEQ]) {
- assert (zmq_msg_size (&self->frame [FRAME_SEQ]) == 8);
- byte *source = zmq_msg_data (&self->frame [FRAME_SEQ]);
- int64_t sequence = ((int64_t) (source [0]) << 56)
- + ((int64_t) (source [1]) << 48)
- + ((int64_t) (source [2]) << 40)
- + ((int64_t) (source [3]) << 32)
- + ((int64_t) (source [4]) << 24)
- + ((int64_t) (source [5]) << 16)
- + ((int64_t) (source [6]) << 8)
- + (int64_t) (source [7]);
- return sequence;
- }
- else
- return 0;
- }
- // ---------------------------------------------------------------------
- // Return body from last read message, if any, else NULL
- byte *
- kvmsg_body (kvmsg_t *self)
- {
- assert (self);
- if (self->present [FRAME_BODY])
- return (byte *) zmq_msg_data (&self->frame [FRAME_BODY]);
- else
- return NULL;
- }
- // ---------------------------------------------------------------------
- // Return body size from last read message, if any, else zero
- size_t
- kvmsg_size (kvmsg_t *self)
- {
- assert (self);
- if (self->present [FRAME_BODY])
- return zmq_msg_size (&self->frame [FRAME_BODY]);
- else
- return 0;
- }
- // ---------------------------------------------------------------------
- // Set message key as provided
- void
- kvmsg_set_key (kvmsg_t *self, char *key)
- {
- assert (self);
- zmq_msg_t *msg = &self->frame [FRAME_KEY];
- if (self->present [FRAME_KEY])
- zmq_msg_close (msg);
- zmq_msg_init_size (msg, strlen (key));
- memcpy (zmq_msg_data (msg), key, strlen (key));
- self->present [FRAME_KEY] = 1;
- }
- // ---------------------------------------------------------------------
- // Set message sequence number
- void
- kvmsg_set_sequence (kvmsg_t *self, int64_t sequence)
- {
- assert (self);
- zmq_msg_t *msg = &self->frame [FRAME_SEQ];
- if (self->present [FRAME_SEQ])
- zmq_msg_close (msg);
- zmq_msg_init_size (msg, 8);
- byte *source = zmq_msg_data (msg);
- source [0] = (byte) ((sequence >> 56) & 255);
- source [1] = (byte) ((sequence >> 48) & 255);
- source [2] = (byte) ((sequence >> 40) & 255);
- source [3] = (byte) ((sequence >> 32) & 255);
- source [4] = (byte) ((sequence >> 24) & 255);
- source [5] = (byte) ((sequence >> 16) & 255);
- source [6] = (byte) ((sequence >> 8) & 255);
- source [7] = (byte) ((sequence) & 255);
- self->present [FRAME_SEQ] = 1;
- }
- // ---------------------------------------------------------------------
- // Set message body
- void
- kvmsg_set_body (kvmsg_t *self, byte *body, size_t size)
- {
- assert (self);
- zmq_msg_t *msg = &self->frame [FRAME_BODY];
- if (self->present [FRAME_BODY])
- zmq_msg_close (msg);
- self->present [FRAME_BODY] = 1;
- zmq_msg_init_size (msg, size);
- memcpy (zmq_msg_data (msg), body, size);
- }
- // ---------------------------------------------------------------------
- // Set message key using printf format
- void
- kvmsg_fmt_key (kvmsg_t *self, char *format, …)
- {
- char value [KVMSG_KEY_MAX + 1];
- va_list args;
- assert (self);
- va_start (args, format);
- vsnprintf (value, KVMSG_KEY_MAX, format, args);
- va_end (args);
- kvmsg_set_key (self, value);
- }
- // ---------------------------------------------------------------------
- // Set message body using printf format
- void
- kvmsg_fmt_body (kvmsg_t *self, char *format, …)
- {
- char value [255 + 1];
- va_list args;
- assert (self);
- va_start (args, format);
- vsnprintf (value, 255, format, args);
- va_end (args);
- kvmsg_set_body (self, (byte *) value, strlen (value));
- }
- // ---------------------------------------------------------------------
- // Store entire kvmsg into hash map, if key/value are set
- // Nullifies kvmsg reference, and destroys automatically when no longer
- // needed.
- void
- kvmsg_store (kvmsg_t **self_p, zhash_t *hash)
- {
- assert (self_p);
- if (*self_p) {
- kvmsg_t *self = *self_p;
- assert (self);
- if (self->present [FRAME_KEY]
- && self->present [FRAME_BODY]) {
- zhash_update (hash, kvmsg_key (self), self);
- zhash_freefn (hash, kvmsg_key (self), kvmsg_free);
- }
- *self_p = NULL;
- }
- }
- // ---------------------------------------------------------------------
- // Dump message to stderr, for debugging and tracing
- void
- kvmsg_dump (kvmsg_t *self)
- {
- if (self) {
- if (!self) {
- fprintf (stderr, "NULL");
- return;
- }
- size_t size = kvmsg_size (self);
- byte *body = kvmsg_body (self);
- fprintf (stderr, "[seq:%" PRId64 "]", kvmsg_sequence (self));
- fprintf (stderr, "[key:%s]", kvmsg_key (self));
- fprintf (stderr, "[size:%zd] ", size);
- int char_nbr;
- for (char_nbr = 0; char_nbr < size; char_nbr++)
- fprintf (stderr, "%02X", body [char_nbr]);
- fprintf (stderr, "\n");
- }
- else
- fprintf (stderr, "NULL message\n");
- }
- // ---------------------------------------------------------------------
- // Runs self test of class
- int
- kvmsg_test (int verbose)
- {
- kvmsg_t
- *kvmsg;
- printf (" * kvmsg: ");
- // Prepare our context and sockets
- zctx_t *ctx = zctx_new ();
- void *output = zsocket_new (ctx, ZMQ_DEALER);
- int rc = zmq_bind (output, "ipc://kvmsg_selftest.ipc");
- assert (rc == 0);
- void *input = zsocket_new (ctx, ZMQ_DEALER);
- rc = zmq_connect (input, "ipc://kvmsg_selftest.ipc");
- assert (rc == 0);
- zhash_t *kvmap = zhash_new ();
- // Test send and receive of simple message
- kvmsg = kvmsg_new (1);
- kvmsg_set_key (kvmsg, "key");
- kvmsg_set_body (kvmsg, (byte *) "body", 4);
- if (verbose)
- kvmsg_dump (kvmsg);
- kvmsg_send (kvmsg, output);
- kvmsg_store (&kvmsg, kvmap);
- kvmsg = kvmsg_recv (input);
- if (verbose)
- kvmsg_dump (kvmsg);
- assert (streq (kvmsg_key (kvmsg), "key"));
- kvmsg_store (&kvmsg, kvmap);
- // Shutdown and destroy all objects
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- printf ("OK\n");
- return 0;
- }
/* ===================================================================== kvsimple - simple key-value message class for example applications --------------------------------------------------------------------- Copyright (c) 1991-2011 iMatix Corporation <www.imatix.com> Copyright other contributors as noted in the AUTHORS file. This file is part of the ZeroMQ Guide: http://zguide.zeromq.org This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. =====================================================================*/#include "kvsimple.h"#include "zlist.h"// Keys are short strings#define KVMSG_KEY_MAX 255// Message is formatted on wire as 4 frames:// frame 0: key (0MQ string)// frame 1: sequence (8 bytes, network order)// frame 2: body (blob)#define FRAME_KEY 0#define FRAME_SEQ 1#define FRAME_BODY 2#define KVMSG_FRAMES 3// Structure of our classstruct _kvmsg { // Presence indicators for each frame int present [KVMSG_FRAMES]; // Corresponding 0MQ message frames, if any zmq_msg_t frame [KVMSG_FRAMES]; // Key, copied into safe C string char key [KVMSG_KEY_MAX + 1];};// ---------------------------------------------------------------------// Constructor, sets sequence as providedkvmsg_t *kvmsg_new (int64_t sequence){ kvmsg_t *self; self = (kvmsg_t *) zmalloc (sizeof (kvmsg_t)); kvmsg_set_sequence (self, sequence); return self;}// ---------------------------------------------------------------------// Destructor// Free shim, compatible with zhash_free_fnvoidkvmsg_free (void *ptr){ if (ptr) { kvmsg_t *self = (kvmsg_t *) ptr; // Destroy message frames if any int frame_nbr; for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) if (self->present [frame_nbr]) zmq_msg_close (&self->frame [frame_nbr]); // Free object itself free (self); }}voidkvmsg_destroy (kvmsg_t **self_p){ assert (self_p); if (*self_p) { kvmsg_free (*self_p); *self_p = NULL; }}// ---------------------------------------------------------------------// Reads key-value message from socket, returns new kvmsg instance.kvmsg_t *kvmsg_recv (void *socket){ assert (socket); kvmsg_t *self = kvmsg_new (0); // Read all frames off the wire, reject if bogus int frame_nbr; for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) { if (self->present [frame_nbr]) zmq_msg_close (&self->frame [frame_nbr]); zmq_msg_init (&self->frame [frame_nbr]); self->present [frame_nbr] = 1; if (zmq_recvmsg (socket, &self->frame [frame_nbr], 0) == -1) { kvmsg_destroy (&self); break; } // Verify multipart framing int rcvmore = (frame_nbr < KVMSG_FRAMES - 1)? 1: 0; if (zsockopt_rcvmore (socket) != rcvmore) { kvmsg_destroy (&self); break; } } return self;}// ---------------------------------------------------------------------// Send key-value message to socket; any empty frames are sent as such.voidkvmsg_send (kvmsg_t *self, void *socket){ assert (self); assert (socket); int frame_nbr; for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) { zmq_msg_t copy; zmq_msg_init (©); if (self->present [frame_nbr]) zmq_msg_copy (©, &self->frame [frame_nbr]); zmq_sendmsg (socket, ©, (frame_nbr < KVMSG_FRAMES - 1)? ZMQ_SNDMORE: 0); zmq_msg_close (©); }}// ---------------------------------------------------------------------// Return key from last read message, if any, else NULLchar *kvmsg_key (kvmsg_t *self){ assert (self); if (self->present [FRAME_KEY]) { if (!*self->key) { size_t size = zmq_msg_size (&self->frame [FRAME_KEY]); if (size > KVMSG_KEY_MAX) size = KVMSG_KEY_MAX; memcpy (self->key, zmq_msg_data (&self->frame [FRAME_KEY]), size); self->key [size] = 0; } return self->key; } else return NULL;}// ---------------------------------------------------------------------// Return sequence nbr from last read message, if anyint64_tkvmsg_sequence (kvmsg_t *self){ assert (self); if (self->present [FRAME_SEQ]) { assert (zmq_msg_size (&self->frame [FRAME_SEQ]) == 8); byte *source = zmq_msg_data (&self->frame [FRAME_SEQ]); int64_t sequence = ((int64_t) (source [0]) << 56) + ((int64_t) (source [1]) << 48) + ((int64_t) (source [2]) << 40) + ((int64_t) (source [3]) << 32) + ((int64_t) (source [4]) << 24) + ((int64_t) (source [5]) << 16) + ((int64_t) (source [6]) << 8) + (int64_t) (source [7]); return sequence; } else return 0;}// ---------------------------------------------------------------------// Return body from last read message, if any, else NULLbyte *kvmsg_body (kvmsg_t *self){ assert (self); if (self->present [FRAME_BODY]) return (byte *) zmq_msg_data (&self->frame [FRAME_BODY]); else return NULL;}// ---------------------------------------------------------------------// Return body size from last read message, if any, else zerosize_tkvmsg_size (kvmsg_t *self){ assert (self); if (self->present [FRAME_BODY]) return zmq_msg_size (&self->frame [FRAME_BODY]); else return 0;}// ---------------------------------------------------------------------// Set message key as providedvoidkvmsg_set_key (kvmsg_t *self, char *key){ assert (self); zmq_msg_t *msg = &self->frame [FRAME_KEY]; if (self->present [FRAME_KEY]) zmq_msg_close (msg); zmq_msg_init_size (msg, strlen (key)); memcpy (zmq_msg_data (msg), key, strlen (key)); self->present [FRAME_KEY] = 1;}// ---------------------------------------------------------------------// Set message sequence numbervoidkvmsg_set_sequence (kvmsg_t *self, int64_t sequence){ assert (self); zmq_msg_t *msg = &self->frame [FRAME_SEQ]; if (self->present [FRAME_SEQ]) zmq_msg_close (msg); zmq_msg_init_size (msg, 8); byte *source = zmq_msg_data (msg); source [0] = (byte) ((sequence >> 56) & 255); source [1] = (byte) ((sequence >> 48) & 255); source [2] = (byte) ((sequence >> 40) & 255); source [3] = (byte) ((sequence >> 32) & 255); source [4] = (byte) ((sequence >> 24) & 255); source [5] = (byte) ((sequence >> 16) & 255); source [6] = (byte) ((sequence >> 8) & 255); source [7] = (byte) ((sequence) & 255); self->present [FRAME_SEQ] = 1;}// ---------------------------------------------------------------------// Set message bodyvoidkvmsg_set_body (kvmsg_t *self, byte *body, size_t size){ assert (self); zmq_msg_t *msg = &self->frame [FRAME_BODY]; if (self->present [FRAME_BODY]) zmq_msg_close (msg); self->present [FRAME_BODY] = 1; zmq_msg_init_size (msg, size); memcpy (zmq_msg_data (msg), body, size);}// ---------------------------------------------------------------------// Set message key using printf formatvoidkvmsg_fmt_key (kvmsg_t *self, char *format, …){ char value [KVMSG_KEY_MAX + 1]; va_list args; assert (self); va_start (args, format); vsnprintf (value, KVMSG_KEY_MAX, format, args); va_end (args); kvmsg_set_key (self, value);}// ---------------------------------------------------------------------// Set message body using printf formatvoidkvmsg_fmt_body (kvmsg_t *self, char *format, …){ char value [255 + 1]; va_list args; assert (self); va_start (args, format); vsnprintf (value, 255, format, args); va_end (args); kvmsg_set_body (self, (byte *) value, strlen (value));}// ---------------------------------------------------------------------// Store entire kvmsg into hash map, if key/value are set// Nullifies kvmsg reference, and destroys automatically when no longer// needed.voidkvmsg_store (kvmsg_t **self_p, zhash_t *hash){ assert (self_p); if (*self_p) { kvmsg_t *self = *self_p; assert (self); if (self->present [FRAME_KEY] && self->present [FRAME_BODY]) { zhash_update (hash, kvmsg_key (self), self); zhash_freefn (hash, kvmsg_key (self), kvmsg_free); } *self_p = NULL; }}// ---------------------------------------------------------------------// Dump message to stderr, for debugging and tracingvoidkvmsg_dump (kvmsg_t *self){ if (self) { if (!self) { fprintf (stderr, "NULL"); return; } size_t size = kvmsg_size (self); byte *body = kvmsg_body (self); fprintf (stderr, "[seq:%" PRId64 "]", kvmsg_sequence (self)); fprintf (stderr, "[key:%s]", kvmsg_key (self)); fprintf (stderr, "[size:%zd] ", size); int char_nbr; for (char_nbr = 0; char_nbr < size; char_nbr++) fprintf (stderr, "%02X", body [char_nbr]); fprintf (stderr, "\n"); } else fprintf (stderr, "NULL message\n");}// ---------------------------------------------------------------------// Runs self test of classintkvmsg_test (int verbose){ kvmsg_t *kvmsg; printf (" * kvmsg: "); // Prepare our context and sockets zctx_t *ctx = zctx_new (); void *output = zsocket_new (ctx, ZMQ_DEALER); int rc = zmq_bind (output, "ipc://kvmsg_selftest.ipc"); assert (rc == 0); void *input = zsocket_new (ctx, ZMQ_DEALER); rc = zmq_connect (input, "ipc://kvmsg_selftest.ipc"); assert (rc == 0); zhash_t *kvmap = zhash_new (); // Test send and receive of simple message kvmsg = kvmsg_new (1); kvmsg_set_key (kvmsg, "key"); kvmsg_set_body (kvmsg, (byte *) "body", 4); if (verbose) kvmsg_dump (kvmsg); kvmsg_send (kvmsg, output); kvmsg_store (&kvmsg, kvmap); kvmsg = kvmsg_recv (input); if (verbose) kvmsg_dump (kvmsg); assert (streq (kvmsg_key (kvmsg), "key")); kvmsg_store (&kvmsg, kvmap); // Shutdown and destroy all objects zhash_destroy (&kvmap); zctx_destroy (&ctx); printf ("OK\n"); return 0;}
根据key获取数据
其实,当订阅者可以发出key来获取数据的时候,它已经不是一个纯粹的订阅者了,或许客户端的称谓会更合适些。
模型图:
服务器:
- //
- // Clone server Model Two
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- static int s_send_single (char *key, void *data, void *args);
- static void state_manager (void *args, zctx_t *ctx, void *pipe);
- int main (void)
- {
- // Prepare our context and sockets
- zctx_t *ctx = zctx_new ();
- void *publisher = zsocket_new (ctx, ZMQ_PUB);
- zsocket_bind (publisher, "tcp://*:5557");
- int64_t sequence = 0;
- srandom ((unsigned) time (NULL));
- // Start state manager and wait for synchronization signal
- void *updates = zthread_fork (ctx, state_manager, NULL);
- free (zstr_recv (updates));
- while (!zctx_interrupted) {
- // Distribute as key-value message
- kvmsg_t *kvmsg = kvmsg_new (++sequence);
- kvmsg_fmt_key (kvmsg, "%d", randof (10000));
- kvmsg_fmt_body (kvmsg, "%d", randof (1000000));
- kvmsg_send (kvmsg, publisher);
- kvmsg_send (kvmsg, updates);
- kvmsg_destroy (&kvmsg);
- }
- printf (" Interrupted\n%d messages out\n", (int) sequence);
- zctx_destroy (&ctx);
- return 0;
- }
- // Routing information for a key-value snapshot
- typedef struct {
- void *socket; // ROUTER socket to send to
- zframe_t *identity; // Identity of peer who requested state
- } kvroute_t;
- // Send one state snapshot key-value pair to a socket
- // Hash item data is our kvmsg object, ready to send
- static int
- s_send_single (char *key, void *data, void *args)
- {
- kvroute_t *kvroute = (kvroute_t *) args;
- // Send identity of recipient first
- zframe_send (&kvroute->identity,
- kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);
- kvmsg_t *kvmsg = (kvmsg_t *) data;
- kvmsg_send (kvmsg, kvroute->socket);
- return 0;
- }
- // This thread maintains the state and handles requests from
- // clients for snapshots.
- //
- static void
- state_manager (void *args, zctx_t *ctx, void *pipe)
- {
- zhash_t *kvmap = zhash_new ();
- zstr_send (pipe, "READY");
- void *snapshot = zsocket_new (ctx, ZMQ_ROUTER);
- zsocket_bind (snapshot, "tcp://*:5556");
- zmq_pollitem_t items [] = {
- { pipe, 0, ZMQ_POLLIN, 0 },
- { snapshot, 0, ZMQ_POLLIN, 0 }
- };
- int64_t sequence = 0; // Current snapshot version number
- while (!zctx_interrupted) {
- int rc = zmq_poll (items, 2, -1);
- if (rc == -1 && errno == ETERM)
- break; // Context has been shut down
- // Apply state update from main thread
- if (items [0].revents & ZMQ_POLLIN) {
- kvmsg_t *kvmsg = kvmsg_recv (pipe);
- if (!kvmsg)
- break; // Interrupted
- sequence = kvmsg_sequence (kvmsg);
- kvmsg_store (&kvmsg, kvmap);
- }
- // Execute state snapshot request
- if (items [1].revents & ZMQ_POLLIN) {
- zframe_t *identity = zframe_recv (snapshot);
- if (!identity)
- break; // Interrupted
- // Request is in second frame of message
- char *request = zstr_recv (snapshot);
- if (streq (request, "ICANHAZ?"))
- free (request);
- else {
- printf ("E: bad request, aborting\n");
- break;
- }
- // Send state snapshot to client
- kvroute_t routing = { snapshot, identity };
- // For each entry in kvmap, send kvmsg to client
- zhash_foreach (kvmap, s_send_single, &routing);
- // Now send END message with sequence number
- printf ("Sending state shapshot=%d\n", (int) sequence);
- zframe_send (&identity, snapshot, ZFRAME_MORE);
- kvmsg_t *kvmsg = kvmsg_new (sequence);
- kvmsg_set_key (kvmsg, "KTHXBAI");
- kvmsg_set_body (kvmsg, (byte *) "", 0);
- kvmsg_send (kvmsg, snapshot);
- kvmsg_destroy (&kvmsg);
- }
- }
- zhash_destroy (&kvmap);
- }
//// Clone server Model Two//// Lets us build this source without creating a library#include "kvsimple.c"static int s_send_single (char *key, void *data, void *args);static void state_manager (void *args, zctx_t *ctx, void *pipe);int main (void){ // Prepare our context and sockets zctx_t *ctx = zctx_new (); void *publisher = zsocket_new (ctx, ZMQ_PUB); zsocket_bind (publisher, "tcp://*:5557"); int64_t sequence = 0; srandom ((unsigned) time (NULL)); // Start state manager and wait for synchronization signal void *updates = zthread_fork (ctx, state_manager, NULL); free (zstr_recv (updates)); while (!zctx_interrupted) { // Distribute as key-value message kvmsg_t *kvmsg = kvmsg_new (++sequence); kvmsg_fmt_key (kvmsg, "%d", randof (10000)); kvmsg_fmt_body (kvmsg, "%d", randof (1000000)); kvmsg_send (kvmsg, publisher); kvmsg_send (kvmsg, updates); kvmsg_destroy (&kvmsg); } printf (" Interrupted\n%d messages out\n", (int) sequence); zctx_destroy (&ctx); return 0;}// Routing information for a key-value snapshottypedef struct { void *socket; // ROUTER socket to send to zframe_t *identity; // Identity of peer who requested state} kvroute_t;// Send one state snapshot key-value pair to a socket// Hash item data is our kvmsg object, ready to sendstatic ints_send_single (char *key, void *data, void *args){ kvroute_t *kvroute = (kvroute_t *) args; // Send identity of recipient first zframe_send (&kvroute->identity, kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE); kvmsg_t *kvmsg = (kvmsg_t *) data; kvmsg_send (kvmsg, kvroute->socket); return 0;}// This thread maintains the state and handles requests from// clients for snapshots.//static voidstate_manager (void *args, zctx_t *ctx, void *pipe){ zhash_t *kvmap = zhash_new (); zstr_send (pipe, "READY"); void *snapshot = zsocket_new (ctx, ZMQ_ROUTER); zsocket_bind (snapshot, "tcp://*:5556"); zmq_pollitem_t items [] = { { pipe, 0, ZMQ_POLLIN, 0 }, { snapshot, 0, ZMQ_POLLIN, 0 } }; int64_t sequence = 0; // Current snapshot version number while (!zctx_interrupted) { int rc = zmq_poll (items, 2, -1); if (rc == -1 && errno == ETERM) break; // Context has been shut down // Apply state update from main thread if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (pipe); if (!kvmsg) break; // Interrupted sequence = kvmsg_sequence (kvmsg); kvmsg_store (&kvmsg, kvmap); } // Execute state snapshot request if (items [1].revents & ZMQ_POLLIN) { zframe_t *identity = zframe_recv (snapshot); if (!identity) break; // Interrupted // Request is in second frame of message char *request = zstr_recv (snapshot); if (streq (request, "ICANHAZ?")) free (request); else { printf ("E: bad request, aborting\n"); break; } // Send state snapshot to client kvroute_t routing = { snapshot, identity }; // For each entry in kvmap, send kvmsg to client zhash_foreach (kvmap, s_send_single, &routing); // Now send END message with sequence number printf ("Sending state shapshot=%d\n", (int) sequence); zframe_send (&identity, snapshot, ZFRAME_MORE); kvmsg_t *kvmsg = kvmsg_new (sequence); kvmsg_set_key (kvmsg, "KTHXBAI"); kvmsg_set_body (kvmsg, (byte *) "", 0); kvmsg_send (kvmsg, snapshot); kvmsg_destroy (&kvmsg); } } zhash_destroy (&kvmap);}
客户端:
- //
- // Clone client Model Two
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- int main (void)
- {
- // Prepare our context and subscriber
- zctx_t *ctx = zctx_new ();
- void *snapshot = zsocket_new (ctx, ZMQ_DEALER);
- zsocket_connect (snapshot, "tcp://localhost:5556");
- void *subscriber = zsocket_new (ctx, ZMQ_SUB);
- zsocket_connect (subscriber, "tcp://localhost:5557");
- zhash_t *kvmap = zhash_new ();
- // Get state snapshot
- int64_t sequence = 0;
- zstr_send (snapshot, "ICANHAZ?");
- while (TRUE) {
- kvmsg_t *kvmsg = kvmsg_recv (snapshot);
- if (!kvmsg)
- break; // Interrupted
- if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {
- sequence = kvmsg_sequence (kvmsg);
- printf ("Received snapshot=%d\n", (int) sequence);
- kvmsg_destroy (&kvmsg);
- break; // Done
- }
- kvmsg_store (&kvmsg, kvmap);
- }
- // Now apply pending updates, discard out-of-sequence messages
- while (!zctx_interrupted) {
- kvmsg_t *kvmsg = kvmsg_recv (subscriber);
- if (!kvmsg)
- break; // Interrupted
- if (kvmsg_sequence (kvmsg) > sequence) {
- sequence = kvmsg_sequence (kvmsg);
- kvmsg_store (&kvmsg, kvmap);
- }
- else
- kvmsg_destroy (&kvmsg);
- }
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- return 0;
- }
//// Clone client Model Two//// Lets us build this source without creating a library#include "kvsimple.c"int main (void){ // Prepare our context and subscriber zctx_t *ctx = zctx_new (); void *snapshot = zsocket_new (ctx, ZMQ_DEALER); zsocket_connect (snapshot, "tcp://localhost:5556"); void *subscriber = zsocket_new (ctx, ZMQ_SUB); zsocket_connect (subscriber, "tcp://localhost:5557"); zhash_t *kvmap = zhash_new (); // Get state snapshot int64_t sequence = 0; zstr_send (snapshot, "ICANHAZ?"); while (TRUE) { kvmsg_t *kvmsg = kvmsg_recv (snapshot); if (!kvmsg) break; // Interrupted if (streq (kvmsg_key (kvmsg), "KTHXBAI")) { sequence = kvmsg_sequence (kvmsg); printf ("Received snapshot=%d\n", (int) sequence); kvmsg_destroy (&kvmsg); break; // Done } kvmsg_store (&kvmsg, kvmap); } // Now apply pending updates, discard out-of-sequence messages while (!zctx_interrupted) { kvmsg_t *kvmsg = kvmsg_recv (subscriber); if (!kvmsg) break; // Interrupted if (kvmsg_sequence (kvmsg) > sequence) { sequence = kvmsg_sequence (kvmsg); kvmsg_store (&kvmsg, kvmap); } else kvmsg_destroy (&kvmsg); } zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0;}
重新发布更新
上面的模型中,数据都集中在一点,或许会有服务器崩溃而导致数据丢失的顾虑,那么,把数据放到客户端呢?
模型图:
服务器:
- //
- // Clone server Model Three
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- static int s_send_single (char *key, void *data, void *args);
- // Routing information for a key-value snapshot
- typedef struct {
- void *socket; // ROUTER socket to send to
- zframe_t *identity; // Identity of peer who requested state
- } kvroute_t;
- int main (void)
- {
- // Prepare our context and sockets
- zctx_t *ctx = zctx_new ();
- void *snapshot = zsocket_new (ctx, ZMQ_ROUTER);
- zsocket_bind (snapshot, "tcp://*:5556");
- void *publisher = zsocket_new (ctx, ZMQ_PUB);
- zsocket_bind (publisher, "tcp://*:5557");
- void *collector = zsocket_new (ctx, ZMQ_PULL);
- zsocket_bind (collector, "tcp://*:5558");
- int64_t sequence = 0;
- zhash_t *kvmap = zhash_new ();
- zmq_pollitem_t items [] = {
- { collector, 0, ZMQ_POLLIN, 0 },
- { snapshot, 0, ZMQ_POLLIN, 0 }
- };
- while (!zctx_interrupted) {
- int rc = zmq_poll (items, 2, 1000 * ZMQ_POLL_MSEC);
- // Apply state update sent from client
- if (items [0].revents & ZMQ_POLLIN) {
- kvmsg_t *kvmsg = kvmsg_recv (collector);
- if (!kvmsg)
- break; // Interrupted
- kvmsg_set_sequence (kvmsg, ++sequence);
- kvmsg_send (kvmsg, publisher);
- kvmsg_store (&kvmsg, kvmap);
- printf ("I: publishing update %5d\n", (int) sequence);
- }
- // Execute state snapshot request
- if (items [1].revents & ZMQ_POLLIN) {
- zframe_t *identity = zframe_recv (snapshot);
- if (!identity)
- break; // Interrupted
- // Request is in second frame of message
- char *request = zstr_recv (snapshot);
- if (streq (request, "ICANHAZ?"))
- free (request);
- else {
- printf ("E: bad request, aborting\n");
- break;
- }
- // Send state snapshot to client
- kvroute_t routing = { snapshot, identity };
- // For each entry in kvmap, send kvmsg to client
- zhash_foreach (kvmap, s_send_single, &routing);
- // Now send END message with sequence number
- printf ("I: sending shapshot=%d\n", (int) sequence);
- zframe_send (&identity, snapshot, ZFRAME_MORE);
- kvmsg_t *kvmsg = kvmsg_new (sequence);
- kvmsg_set_key (kvmsg, "KTHXBAI");
- kvmsg_set_body (kvmsg, (byte *) "", 0);
- kvmsg_send (kvmsg, snapshot);
- kvmsg_destroy (&kvmsg);
- }
- }
- printf (" Interrupted\n%d messages handled\n", (int) sequence);
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- return 0;
- }
- // Send one state snapshot key-value pair to a socket
- // Hash item data is our kvmsg object, ready to send
- static int
- s_send_single (char *key, void *data, void *args)
- {
- kvroute_t *kvroute = (kvroute_t *) args;
- // Send identity of recipient first
- zframe_send (&kvroute->identity,
- kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);
- kvmsg_t *kvmsg = (kvmsg_t *) data;
- kvmsg_send (kvmsg, kvroute->socket);
- return 0;
- }
//// Clone server Model Three//// Lets us build this source without creating a library#include "kvsimple.c"static int s_send_single (char *key, void *data, void *args);// Routing information for a key-value snapshottypedef struct { void *socket; // ROUTER socket to send to zframe_t *identity; // Identity of peer who requested state} kvroute_t;int main (void){ // Prepare our context and sockets zctx_t *ctx = zctx_new (); void *snapshot = zsocket_new (ctx, ZMQ_ROUTER); zsocket_bind (snapshot, "tcp://*:5556"); void *publisher = zsocket_new (ctx, ZMQ_PUB); zsocket_bind (publisher, "tcp://*:5557"); void *collector = zsocket_new (ctx, ZMQ_PULL); zsocket_bind (collector, "tcp://*:5558"); int64_t sequence = 0; zhash_t *kvmap = zhash_new (); zmq_pollitem_t items [] = { { collector, 0, ZMQ_POLLIN, 0 }, { snapshot, 0, ZMQ_POLLIN, 0 } }; while (!zctx_interrupted) { int rc = zmq_poll (items, 2, 1000 * ZMQ_POLL_MSEC); // Apply state update sent from client if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (collector); if (!kvmsg) break; // Interrupted kvmsg_set_sequence (kvmsg, ++sequence); kvmsg_send (kvmsg, publisher); kvmsg_store (&kvmsg, kvmap); printf ("I: publishing update %5d\n", (int) sequence); } // Execute state snapshot request if (items [1].revents & ZMQ_POLLIN) { zframe_t *identity = zframe_recv (snapshot); if (!identity) break; // Interrupted // Request is in second frame of message char *request = zstr_recv (snapshot); if (streq (request, "ICANHAZ?")) free (request); else { printf ("E: bad request, aborting\n"); break; } // Send state snapshot to client kvroute_t routing = { snapshot, identity }; // For each entry in kvmap, send kvmsg to client zhash_foreach (kvmap, s_send_single, &routing); // Now send END message with sequence number printf ("I: sending shapshot=%d\n", (int) sequence); zframe_send (&identity, snapshot, ZFRAME_MORE); kvmsg_t *kvmsg = kvmsg_new (sequence); kvmsg_set_key (kvmsg, "KTHXBAI"); kvmsg_set_body (kvmsg, (byte *) "", 0); kvmsg_send (kvmsg, snapshot); kvmsg_destroy (&kvmsg); } } printf (" Interrupted\n%d messages handled\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0;}// Send one state snapshot key-value pair to a socket// Hash item data is our kvmsg object, ready to sendstatic ints_send_single (char *key, void *data, void *args){ kvroute_t *kvroute = (kvroute_t *) args; // Send identity of recipient first zframe_send (&kvroute->identity, kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE); kvmsg_t *kvmsg = (kvmsg_t *) data; kvmsg_send (kvmsg, kvroute->socket); return 0;}
客户端:
- //
- // Clone client Model Three
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- int main (void)
- {
- // Prepare our context and subscriber
- zctx_t *ctx = zctx_new ();
- void *snapshot = zsocket_new (ctx, ZMQ_DEALER);
- zsocket_connect (snapshot, "tcp://localhost:5556");
- void *subscriber = zsocket_new (ctx, ZMQ_SUB);
- zsocket_connect (subscriber, "tcp://localhost:5557");
- void *publisher = zsocket_new (ctx, ZMQ_PUSH);
- zsocket_connect (publisher, "tcp://localhost:5558");
- zhash_t *kvmap = zhash_new ();
- srandom ((unsigned) time (NULL));
- // Get state snapshot
- int64_t sequence = 0;
- zstr_send (snapshot, "ICANHAZ?");
- while (TRUE) {
- kvmsg_t *kvmsg = kvmsg_recv (snapshot);
- if (!kvmsg)
- break; // Interrupted
- if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {
- sequence = kvmsg_sequence (kvmsg);
- printf ("I: received snapshot=%d\n", (int) sequence);
- kvmsg_destroy (&kvmsg);
- break; // Done
- }
- kvmsg_store (&kvmsg, kvmap);
- }
- int64_t alarm = zclock_time () + 1000;
- while (!zctx_interrupted) {
- zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } };
- int tickless = (int) ((alarm - zclock_time ()));
- if (tickless < 0)
- tickless = 0;
- int rc = zmq_poll (items, 1, tickless * ZMQ_POLL_MSEC);
- if (rc == -1)
- break; // Context has been shut down
- if (items [0].revents & ZMQ_POLLIN) {
- kvmsg_t *kvmsg = kvmsg_recv (subscriber);
- if (!kvmsg)
- break; // Interrupted
- // Discard out-of-sequence kvmsgs, incl. heartbeats
- if (kvmsg_sequence (kvmsg) > sequence) {
- sequence = kvmsg_sequence (kvmsg);
- kvmsg_store (&kvmsg, kvmap);
- printf ("I: received update=%d\n", (int) sequence);
- }
- else
- kvmsg_destroy (&kvmsg);
- }
- // If we timed-out, generate a random kvmsg
- if (zclock_time () >= alarm) {
- kvmsg_t *kvmsg = kvmsg_new (0);
- kvmsg_fmt_key (kvmsg, "%d", randof (10000));
- kvmsg_fmt_body (kvmsg, "%d", randof (1000000));
- kvmsg_send (kvmsg, publisher);
- kvmsg_destroy (&kvmsg);
- alarm = zclock_time () + 1000;
- }
- }
- printf (" Interrupted\n%d messages in\n", (int) sequence);
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- return 0;
- }
//// Clone client Model Three//// Lets us build this source without creating a library#include "kvsimple.c"int main (void){ // Prepare our context and subscriber zctx_t *ctx = zctx_new (); void *snapshot = zsocket_new (ctx, ZMQ_DEALER); zsocket_connect (snapshot, "tcp://localhost:5556"); void *subscriber = zsocket_new (ctx, ZMQ_SUB); zsocket_connect (subscriber, "tcp://localhost:5557"); void *publisher = zsocket_new (ctx, ZMQ_PUSH); zsocket_connect (publisher, "tcp://localhost:5558"); zhash_t *kvmap = zhash_new (); srandom ((unsigned) time (NULL)); // Get state snapshot int64_t sequence = 0; zstr_send (snapshot, "ICANHAZ?"); while (TRUE) { kvmsg_t *kvmsg = kvmsg_recv (snapshot); if (!kvmsg) break; // Interrupted if (streq (kvmsg_key (kvmsg), "KTHXBAI")) { sequence = kvmsg_sequence (kvmsg); printf ("I: received snapshot=%d\n", (int) sequence); kvmsg_destroy (&kvmsg); break; // Done } kvmsg_store (&kvmsg, kvmap); } int64_t alarm = zclock_time () + 1000; while (!zctx_interrupted) { zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } }; int tickless = (int) ((alarm - zclock_time ())); if (tickless < 0) tickless = 0; int rc = zmq_poll (items, 1, tickless * ZMQ_POLL_MSEC); if (rc == -1) break; // Context has been shut down if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (subscriber); if (!kvmsg) break; // Interrupted // Discard out-of-sequence kvmsgs, incl. heartbeats if (kvmsg_sequence (kvmsg) > sequence) { sequence = kvmsg_sequence (kvmsg); kvmsg_store (&kvmsg, kvmap); printf ("I: received update=%d\n", (int) sequence); } else kvmsg_destroy (&kvmsg); } // If we timed-out, generate a random kvmsg if (zclock_time () >= alarm) { kvmsg_t *kvmsg = kvmsg_new (0); kvmsg_fmt_key (kvmsg, "%d", randof (10000)); kvmsg_fmt_body (kvmsg, "%d", randof (1000000)); kvmsg_send (kvmsg, publisher); kvmsg_destroy (&kvmsg); alarm = zclock_time () + 1000; } } printf (" Interrupted\n%d messages in\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0;}
克隆子树
事实上,并不是所有的消费者都愿意消费发布者所提供的所有信息,那么,针对特别的群体,只需提供一个子集就可以了。
服务器:
- //
- // Clone server Model Four
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- static int s_send_single (char *key, void *data, void *args);
- // Routing information for a key-value snapshot
- typedef struct {
- void *socket; // ROUTER socket to send to
- zframe_t *identity; // Identity of peer who requested state
- char *subtree; // Client subtree specification
- } kvroute_t;
- int main (void)
- {
- // Prepare our context and sockets
- zctx_t *ctx = zctx_new ();
- void *snapshot = zsocket_new (ctx, ZMQ_ROUTER);
- zsocket_bind (snapshot, "tcp://*:5556");
- void *publisher = zsocket_new (ctx, ZMQ_PUB);
- zsocket_bind (publisher, "tcp://*:5557");
- void *collector = zsocket_new (ctx, ZMQ_PULL);
- zsocket_bind (collector, "tcp://*:5558");
- int64_t sequence = 0;
- zhash_t *kvmap = zhash_new ();
- zmq_pollitem_t items [] = {
- { collector, 0, ZMQ_POLLIN, 0 },
- { snapshot, 0, ZMQ_POLLIN, 0 }
- };
- while (!zctx_interrupted) {
- int rc = zmq_poll (items, 2, 1000 * ZMQ_POLL_MSEC);
- // Apply state update sent from client
- if (items [0].revents & ZMQ_POLLIN) {
- kvmsg_t *kvmsg = kvmsg_recv (collector);
- if (!kvmsg)
- break; // Interrupted
- kvmsg_set_sequence (kvmsg, ++sequence);
- kvmsg_send (kvmsg, publisher);
- kvmsg_store (&kvmsg, kvmap);
- printf ("I: publishing update %5d\n", (int) sequence);
- }
- // Execute state snapshot request
- if (items [1].revents & ZMQ_POLLIN) {
- zframe_t *identity = zframe_recv (snapshot);
- if (!identity)
- break; // Interrupted
- // Request is in second frame of message
- char *request = zstr_recv (snapshot);
- char *subtree = NULL;
- if (streq (request, "ICANHAZ?")) {
- free (request);
- subtree = zstr_recv (snapshot);
- }
- else {
- printf ("E: bad request, aborting\n");
- break;
- }
- // Send state snapshot to client
- kvroute_t routing = { snapshot, identity, subtree };
- // For each entry in kvmap, send kvmsg to client
- zhash_foreach (kvmap, s_send_single, &routing);
- // Now send END message with sequence number
- printf ("I: sending shapshot=%d\n", (int) sequence);
- zframe_send (&identity, snapshot, ZFRAME_MORE);
- kvmsg_t *kvmsg = kvmsg_new (sequence);
- kvmsg_set_key (kvmsg, "KTHXBAI");
- kvmsg_set_body (kvmsg, (byte *) subtree, 0);
- kvmsg_send (kvmsg, snapshot);
- kvmsg_destroy (&kvmsg);
- free (subtree);
- }
- }
- printf (" Interrupted\n%d messages handled\n", (int) sequence);
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- return 0;
- }
- // Send one state snapshot key-value pair to a socket
- // Hash item data is our kvmsg object, ready to send
- static int
- s_send_single (char *key, void *data, void *args)
- {
- kvroute_t *kvroute = (kvroute_t *) args;
- kvmsg_t *kvmsg = (kvmsg_t *) data;
- if (strlen (kvroute->subtree) <= strlen (kvmsg_key (kvmsg))
- && memcmp (kvroute->subtree,
- kvmsg_key (kvmsg), strlen (kvroute->subtree)) == 0) {
- // Send identity of recipient first
- zframe_send (&kvroute->identity,
- kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);
- kvmsg_send (kvmsg, kvroute->socket);
- }
- return 0;
- }
//// Clone server Model Four//// Lets us build this source without creating a library#include "kvsimple.c"static int s_send_single (char *key, void *data, void *args);// Routing information for a key-value snapshottypedef struct { void *socket; // ROUTER socket to send to zframe_t *identity; // Identity of peer who requested state char *subtree; // Client subtree specification} kvroute_t;int main (void){ // Prepare our context and sockets zctx_t *ctx = zctx_new (); void *snapshot = zsocket_new (ctx, ZMQ_ROUTER); zsocket_bind (snapshot, "tcp://*:5556"); void *publisher = zsocket_new (ctx, ZMQ_PUB); zsocket_bind (publisher, "tcp://*:5557"); void *collector = zsocket_new (ctx, ZMQ_PULL); zsocket_bind (collector, "tcp://*:5558"); int64_t sequence = 0; zhash_t *kvmap = zhash_new (); zmq_pollitem_t items [] = { { collector, 0, ZMQ_POLLIN, 0 }, { snapshot, 0, ZMQ_POLLIN, 0 } }; while (!zctx_interrupted) { int rc = zmq_poll (items, 2, 1000 * ZMQ_POLL_MSEC); // Apply state update sent from client if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (collector); if (!kvmsg) break; // Interrupted kvmsg_set_sequence (kvmsg, ++sequence); kvmsg_send (kvmsg, publisher); kvmsg_store (&kvmsg, kvmap); printf ("I: publishing update %5d\n", (int) sequence); } // Execute state snapshot request if (items [1].revents & ZMQ_POLLIN) { zframe_t *identity = zframe_recv (snapshot); if (!identity) break; // Interrupted // Request is in second frame of message char *request = zstr_recv (snapshot); char *subtree = NULL; if (streq (request, "ICANHAZ?")) { free (request); subtree = zstr_recv (snapshot); } else { printf ("E: bad request, aborting\n"); break; } // Send state snapshot to client kvroute_t routing = { snapshot, identity, subtree }; // For each entry in kvmap, send kvmsg to client zhash_foreach (kvmap, s_send_single, &routing); // Now send END message with sequence number printf ("I: sending shapshot=%d\n", (int) sequence); zframe_send (&identity, snapshot, ZFRAME_MORE); kvmsg_t *kvmsg = kvmsg_new (sequence); kvmsg_set_key (kvmsg, "KTHXBAI"); kvmsg_set_body (kvmsg, (byte *) subtree, 0); kvmsg_send (kvmsg, snapshot); kvmsg_destroy (&kvmsg); free (subtree); } } printf (" Interrupted\n%d messages handled\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0;}// Send one state snapshot key-value pair to a socket// Hash item data is our kvmsg object, ready to sendstatic ints_send_single (char *key, void *data, void *args){ kvroute_t *kvroute = (kvroute_t *) args; kvmsg_t *kvmsg = (kvmsg_t *) data; if (strlen (kvroute->subtree) <= strlen (kvmsg_key (kvmsg)) && memcmp (kvroute->subtree, kvmsg_key (kvmsg), strlen (kvroute->subtree)) == 0) { // Send identity of recipient first zframe_send (&kvroute->identity, kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE); kvmsg_send (kvmsg, kvroute->socket); } return 0;}
客户端:
- //
- // Clone client Model Four
- //
- // Lets us build this source without creating a library
- #include "kvsimple.c"
- #define SUBTREE "/client/"
- int main (void)
- {
- // Prepare our context and subscriber
- zctx_t *ctx = zctx_new ();
- void *snapshot = zsocket_new (ctx, ZMQ_DEALER);
- zsocket_connect (snapshot, "tcp://localhost:5556");
- void *subscriber = zsocket_new (ctx, ZMQ_SUB);
- zsocket_connect (subscriber, "tcp://localhost:5557");
- zsockopt_set_subscribe (subscriber, SUBTREE);
- void *publisher = zsocket_new (ctx, ZMQ_PUSH);
- zsocket_connect (publisher, "tcp://localhost:5558");
- zhash_t *kvmap = zhash_new ();
- srandom ((unsigned) time (NULL));
- // Get state snapshot
- int64_t sequence = 0;
- zstr_sendm (snapshot, "ICANHAZ?");
- zstr_send (snapshot, SUBTREE);
- while (TRUE) {
- kvmsg_t *kvmsg = kvmsg_recv (snapshot);
- if (!kvmsg)
- break; // Interrupted
- if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {
- sequence = kvmsg_sequence (kvmsg);
- printf ("I: received snapshot=%d\n", (int) sequence);
- kvmsg_destroy (&kvmsg);
- break; // Done
- }
- kvmsg_store (&kvmsg, kvmap);
- }
- int64_t alarm = zclock_time () + 1000;
- while (!zctx_interrupted) {
- zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } };
- int tickless = (int) ((alarm - zclock_time ()));
- if (tickless < 0)
- tickless = 0;
- int rc = zmq_poll (items, 1, tickless * ZMQ_POLL_MSEC);
- if (rc == -1)
- break; // Context has been shut down
- if (items [0].revents & ZMQ_POLLIN) {
- kvmsg_t *kvmsg = kvmsg_recv (subscriber);
- if (!kvmsg)
- break; // Interrupted
- // Discard out-of-sequence kvmsgs, incl. heartbeats
- if (kvmsg_sequence (kvmsg) > sequence) {
- sequence = kvmsg_sequence (kvmsg);
- kvmsg_store (&kvmsg, kvmap);
- printf ("I: received update=%d\n", (int) sequence);
- }
- else
- kvmsg_destroy (&kvmsg);
- }
- // If we timed-out, generate a random kvmsg
- if (zclock_time () >= alarm) {
- kvmsg_t *kvmsg = kvmsg_new (0);
- kvmsg_fmt_key (kvmsg, "%s%d", SUBTREE, randof (10000));
- kvmsg_fmt_body (kvmsg, "%d", randof (1000000));
- kvmsg_send (kvmsg, publisher);
- kvmsg_destroy (&kvmsg);
- alarm = zclock_time () + 1000;
- }
- }
- printf (" Interrupted\n%d messages in\n", (int) sequence);
- zhash_destroy (&kvmap);
- zctx_destroy (&ctx);
- return 0;
- }
- zeroMQ初体验-32.发布/订阅模式进阶-克隆模式-上
- zeroMQ初体验-33.发布/订阅模式进阶-克隆模式-中
- zeroMQ初体验-34.发布/订阅模式进阶-克隆模式-下,结言
- zeroMQ初体验-13.发布/订阅模式 进阶
- zeroMQ初体验-30.发布/订阅模式进阶-自裁的蜗牛订阅者
- zeroMQ初体验-31.发布/订阅模式进阶-黑盒的高速订阅者
- zeroMQ初体验-2.发布订阅模式(pub/sub)
- zeromq 的发布 订阅模式
- zeroMQ初体验-21.应答模式进阶(七)-云计算
- 初探ZeroMQ(三) 发布-订阅模式中套结字总结
- ZeroMQ:订阅-发布模式的java程序示例
- zeroMQ初体验-20.应答模式进阶(六)-多对多路由模式
- zeroMQ初体验-26.可靠性-管家模式
- zeroMQ初体验-27.可靠性-硬盘模式
- zeroMQ初体验-28.可靠性-主从模式
- zeroMQ初体验-29.可靠性-自由模式
- zeroMQ初体验-15.应答模式进阶(一)-数据的封装
- zeroMQ初体验-16.应答模式进阶(二)-定制路由1
- Javascript 面向对象编程(一):封装
- zeroMQ初体验-30.发布/订阅模式进阶-自裁的蜗牛订阅者
- zeroMQ初体验-31.发布/订阅模式进阶-黑盒的高速订阅者
- ListView含固定列,左右滑动列
- Apache Sqoop
- zeroMQ初体验-32.发布/订阅模式进阶-克隆模式-上
- properties属性文件配置常量技巧
- SQL计算中分母为0
- Symbian屏幕双缓冲和DSA
- zeroMQ初体验-33.发布/订阅模式进阶-克隆模式-中
- 什么是Windows Azure
- oracle10g 学习笔记一
- zeroMQ初体验-34.发布/订阅模式进阶-克隆模式-下,结言
- 理解Python的双下划线命名