ZeroMQ中的消息信封之二

3 篇文章 0 订阅

目的

不久之前,我写过一篇博客:ZeroMQ消息信封,介绍了REQ、REP、ROUTER、DEALER几种消息信封的格式。前两天我又回头看了该文章,试图回忆起相关的知识。才发现真是写得一团糟。为了重新理清几种socket的信封,于是有了这篇blog。

几种常用形式

我决定还是通过ROUTER套接字的几种组合入手,对比几种消息信封。毕竟ROUTER是比较纯结的,收到数据加地址帧,发出的数据拆掉地址帧。
与ROUTER搭配的组合如下,其中的ID帧可以通过 zmq_setsockopt (sck, ZMQ_IDENTITY, "X", 1);函数指定,若不指定,则会自动分配一个。
  1. ROUTER《=》REQ 在应用层表现为
    REQ端发送 DATA帧,ROUTER收到对应的REQ的ID帧+空帧+DATA帧
    ROUTER端发送 ID帧+空帧+DATA帧, 对应的REQ端收到DATA帧
    当然REQ套接字必须先发送请求,再接收消息。顺序不可乱。

  2. ROUTER《=》REP 在应用层表现为
    ROUTER端发送 ID帧+空帧+DATA帧, 对应的REP 端收到DATA帧
    REP 端发送 DATA帧,ROUTER收到对应的REP 的ID帧+空帧+DATA帧
    REP套接字必须先接受请求,再回应消息

  3. ROUTER《=》DEALER 在应用层表现为
    DEALER端发送 DATA帧,ROUTER收到对应的DEALER的ID帧+DATA帧
    ROUTER端发送ID帧 + DATA帧,DEALER收到DATA帧
    DEALER套接字比较自由,不用严格遵循请求-应答顺序。

  4. 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:58

16-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:59

16-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:59

16-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一线的同行们一定要保持身体健康。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值