不久之前,我写过一篇博客:ZeroMQ消息信封,介绍了REQ、REP、ROUTER、DEALER几种消息信封的格式。前两天我又回头看了该文章,试图回忆起相关的知识。才发现真是写得一团糟。为了重新理清几种socket的信封,于是有了这篇blog。
我决定还是通过ROUTER套接字的几种组合入手,对比几种消息信封。毕竟ROUTER是比较纯结的,收到数据加地址帧,发出的数据拆掉地址帧。
与ROUTER搭配的组合如下,其中的ID帧可以通过 zmq_setsockopt (sck, ZMQ_IDENTITY, "X", 1);函数指定,若不指定,则会自动分配一个。
ROUTER《=》REQ 在应用层表现为
REQ端发送 DATA帧,ROUTER收到对应的REQ的ID帧+空帧+DATA帧
ROUTER端发送 ID帧+空帧+DATA帧, 对应的REQ端收到DATA帧
当然REQ套接字必须先发送请求,再接收消息。顺序不可乱。
ROUTER《=》REP 在应用层表现为
ROUTER端发送 ID帧+空帧+DATA帧, 对应的REP 端收到DATA帧
REP 端发送 DATA帧,ROUTER收到对应的REP 的ID帧+空帧+DATA帧
REP套接字必须先接受请求,再回应消息
ROUTER《=》DEALER 在应用层表现为
DEALER端发送 DATA帧,ROUTER收到对应的DEALER的ID帧+DATA帧
ROUTER端发送ID帧 + DATA帧,DEALER收到DATA帧
DEALER套接字比较自由,不用严格遵循请求-应答顺序。
ROUTER《=》ROUTER 在应用层表现为
这种模式下我将其分为ROUTER监听端与ROUTER连接端。
ROUTER监听端发送ID帧+DATA帧,ROUTER连接端收到ID帧+DATA帧。
为了加深理解以上的各个组合,我用代码演示也许比文字更加深刻。
说明:代码使用了zguide提供的zhelpers.h文件,在vs2010下编译并运行
//Router_Req之间的通讯演示
void TestRouter_Req(void *context, void *router,char* link)
{
void *identified0 = zmq_socket (context, ZMQ_REQ);
zmq_setsockopt (identified0, ZMQ_IDENTITY, "A0", 2);
zmq_connect (identified0, link);
s_send (identified0, "ROUTER-REQ");
char* address = s_recv(router);
char* empty = s_recv(router);
free(empty);
char* content = s_recv(router);
s_console("Router端收到来自:[%s]的数据: [%s] ", address, content);
free(content);
// Router发送回复信息
s_sendmore(router, address);
s_sendmore(router, "");
s_send(router, "Server Reply");
char* reqRec = s_recv(identified0);
s_console("Req端收到数据:[%s]", reqRec);
free(reqRec);
free(address);
zmq_close (identified0);
}
//Router_Dealer之间的通讯演示
void TestRouter_Dealer(void *context, void *router,char* link)
{
void *identified1 = zmq_socket (context, ZMQ_DEALER);
zmq_setsockopt (identified1, ZMQ_IDENTITY, "A1", 2);
zmq_connect (identified1, link);
s_send (identified1, "ROUTER-DEALER");
char* address = s_recv(router);
char* content = s_recv(router);
s_console("Router端收到来自:[%s]的数据:[%s] ", address, content);
free(content);
s_sendmore (router, address);
s_send (router, "Server Reply");
char* reqRec = s_recv(identified1);
s_console("DEALER端收到数据:[%s]", reqRec);
free(reqRec);
zmq_close (identified1);
}
//Router_Rep之间的通讯演示
void TestRouter_Rep(void *context, void *router,char* link)
{
void *identified2 = zmq_socket (context, ZMQ_REP);
zmq_setsockopt (identified2, ZMQ_IDENTITY, "A2", 2);
zmq_connect (identified2, link);
Sleep(500);
//rep必须先收到数据才能响应
s_sendmore (router, "A2");
s_sendmore (router, "");
s_send (router, "Router Send");
char* rec = s_recv(identified2);
s_console("rep 端收到数据[%s]", rec);
free(rec);
// rep 回复
s_send (identified2, "Rep Reply");
//router 接收
char* address = s_recv(router);
char* empty = s_recv(router);
free(empty);
char* content = s_recv(router);
s_console("Router端收到来自:[%s]的数据: [%s] ", address, content);
free(content);
free(address);
zmq_close (identified2);
}
//Router_Router之间的通讯演示
void TestRouter_Router(void *context, void *router,char* link)
{
void *identified3 = zmq_socket (context, ZMQ_ROUTER);
zmq_setsockopt (identified3, ZMQ_IDENTITY, "A3", 2);
zmq_connect (identified3, link);
Sleep(500);
s_sendmore(identified3, "Server");
s_send(identified3, "ROUTER-ROUTER");
char* address = s_recv(router);
char* content = s_recv(router);
s_console("Router监听端收到来自[%s]的数据:[%s] ", address, content);
free(address);
free(content);
s_sendmore (router, "A3");
s_send (router, "Server Reply");
address = s_recv(identified3);
content = s_recv(identified3);
s_console("Router连接端收到来自[%s]的数据:[%s] ", address, content);
free(address);
free(content);
zmq_close (identified3);
}
void RouterUse()
{
void *context = zmq_ctx_new ();
char* link = "tcp://127.0.0.1:5005";
void *router = zmq_socket (context, ZMQ_ROUTER);
int iRet = -1;
//指定Server的名称
zmq_setsockopt (router, ZMQ_IDENTITY, "Server", 6);
zmq_bind (router, link);
s_console("开始Router_Req之间的通讯演示");
TestRouter_Req(context, router, link);
s_console("\n");
s_console("开始Router_Dealer之间的通讯演示");
TestRouter_Dealer(context, router, link);
s_console("\n");
s_console("开始Router_Rep之间的通讯演示");
TestRouter_Rep(context, router, link);
s_console("\n");
s_console("开始Router_Router之间的通讯演示");
TestRouter_Router(context, router, link);
zmq_close (router);
zmq_ctx_destroy (context);
return;
}
int _tmain(int argc, _TCHAR* argv[])
{
RouterUse();
getchar();
return 0;
}
执行结果
16-11-07 07:07:58 开始Router_Req之间的通讯演示
16-11-07 07:07:58 Router端收到来自:[A0]的数据: [ROUTER-REQ]
16-11-07 07:07:58 Req端收到数据:[Server Reply]
16-11-07 07:07:5816-11-07 07:07:58 开始Router_Dealer之间的通讯演示
16-11-07 07:07:59 Router端收到来自:[A1]的数据:[ROUTER-DEALER]
16-11-07 07:07:59 DEALER端收到数据:[Server Reply]
16-11-07 07:07:5916-11-07 07:07:59 开始Router_Rep之间的通讯演示
16-11-07 07:07:59 rep 端收到数据[Router Send]
16-11-07 07:07:59 Router端收到来自:[A2]的数据: [Rep Reply]
16-11-07 07:07:5916-11-07 07:07:59 开始Router_Router之间的通讯演示
16-11-07 07:08:00 Router监听端收到来自[A3]的数据:[ROUTER-ROUTER]
16-11-07 07:08:00 Router连接端收到来自[Server]的数据:[Server Reply]
前一篇博客写的时候觉得很清晰,没过过久才发现基本看不懂,比自己以前的代码还烂。也许是当时咩有留下演示代码,也许是当时没有遇到实际的应用,理解也不够深入。所有的工具都是如此吧?实用之后才发现以前的学习只是皮毛而已。
另外刚刚发现一个坏消息:ZeroMQ作者已于10月4日宣布安乐死
希望各位奋战在IT一线的同行们一定要保持身体健康。