因为tcp是一种字节流类型的协议,没有边界,所以把该消息边界的制定留给了应用层。
通常有两种方式实现:
1. 在传统的数据中添加分隔符
2. 在每条消息中添加size字段。
而zeromq采用第2种方案。
zmq_msg_t基本的数据结构
class msg_t
{
public:
// Mesage flags. // 表示一些flags
enum
{
more = 1, // 初始值就是00000001
identity = 64, // 初始值:01000000
shared = 128 // 初始值:10000000
};
bool check ();
int init ();
int init_size (size_t size_);
int init_data (void *data_, size_t size_, msg_free_fn *ffn_,
void *hint_);
int init_delimiter ();
int close ();
int move (msg_t &src_);
int copy (msg_t &src_);
void *data ();
size_t size ();
unsigned char flags ();
void set_flags (unsigned char flags_);
void reset_flags (unsigned char flags_);
bool is_identity () const;
bool is_delimiter ();
bool is_vsm ();
// After calling this function you can copy the message in POD-style
// refs_ times. No need to call copy.
void add_refs (int refs_);
// Removes references previously added by add_refs. If the number of
// references drops to 0, the message is closed and false is returned.
bool rm_refs (int refs_);
private:
// Size in bytes of the largest message that is still copied around
// rather than being reference-counted.
enum {max_vsm_size = 29}; // 最大的very small message消息的字节大小,小消息拷贝,非引用计数
// Shared message buffer. Message data are either allocated in one
// continuous block along with this structure - thus avoiding one
// malloc/free pair or they are stored in used-supplied memory.
// In the latter case, ffn member stores pointer to the function to be
// used to deallocate the data. If the buffer is actually shared (there
// are at least 2 references to it) refcount member contains number of
// references.
// 共享的消息buffer。
struct content_t
{
void *data; // 指向真正的消息数据
size_t size; // 消息数据的字节大小
msg_free_fn *ffn; // 指向释放函数
void *hint; // 传递到回到功能的一个提示值
zmq::atomic_counter_t refcnt;// 消息的引用计数
};
// Different message types. // 不同的消息类型
enum type_t
{
type_min = 101,
type_vsm = 101,
type_lmsg = 102,
type_delimiter = 103,
type_max = 103
};
// Note that fields shared between different message types are not
// moved to tha parent class (msg_t). This way we ger tighter packing
// of the data. Shared fields can be accessed via 'base' member of
// the union.
union {
// base
struct {
unsigned char unused [max_vsm_size + 1];
unsigned char type;
unsigned char flags;
} base;
// 针对very small message的小消息做的一些优化,直
接在stack上分配内存了,可以看后面的消息函数的具体操作
struct {
unsigned char data [max_vsm_size]; // 小消息的内存区域
unsigned char size; // 小消息的大小
unsigned char type;
unsigned char flags;
} vsm;
// 针对大消息
struct {
content_t *content; // 指向content_t的结构
unsigned char unused [max_vsm_size + 1 - sizeof (content_t*)];
unsigned char type;
unsigned char flags;
} lmsg;
// 定界符
struct {
unsigned char unused [max_vsm_size + 1];
unsigned char type;
unsigned char flags;
} delimiter;
} u;
};
delimiter类型的消息,类似于终结者的意思,主要在收发的管道中使用。
因为zeromq会将消息先发送到管道中,
然后poller运行在另一个线程,将管道中的数据读出来,发往socket的缓冲区,
所以,可以发送一个delimiter类型的消息去终结管道,并销毁它。