发现有童鞋不是很清楚ZMQ中的“请求-回复”模式中的ROUTER怎么用,所以简单介绍一下“请求-回复”模式的使用(最后付代码)。

一、讲一讲

1、要使用zmq 通过一个router进行通信,你首先需要知道ZMQ中的“请求-回复”模式,不清楚的话可以先看一下下面这篇文章,连接如下:

http://www.cnblogs.com/fengbohello/p/4354989.html

在“请求-回复”模式中,router是一个比较特殊的 socket类型,它会把它接收到的第一个消息作为消息来源的标志,也就是消息源的identity;而在使用ZMQ_ROUTER类型的socket发送消息的时候呢,会把这个socket发送的第一个消息作为目的地址,及消息的目的identity。示意图如下

1、identity 为 aaa 的 socket 发送了一个消息,这个消息由两部分组成,一个是目的 socket的identity,名字为bbb,另一个是真正的消息,就是"hello"。

2、当aaa 发送的消息被其连接的router接收到之后呢,就不仅仅是刚刚的消息了,ZMQ的底层会偷偷的增加一个消息,那就是 aaa 的identity,所以在 router 看来呢,它接收到的其实是三部分的消息,第一个是消息的来源,第二个是目的地址(bbb 的 identity),第三部分就是真正要传达的信息。

3、当router接收到这么一个消息的时候,会发现,这个消息来源于aaa,并且是发向bbb的,所以router就会发送如下消息:首先发送一个 bbb,表示要发给的目的地址的identity是bbb,然后发送aaa,最后是信息hello。

4、identity 为 bbb的dealer 接收到消息之后,就只有aaa和hello了。router发送的时候不是首先发送了一个bbb吗,去哪里了呢?这次被ZMQ偷偷的拿走了。这就是router的神奇之处,它会看到ZMQ_DEALER和ZMQ_REQ/ZMQ_REP不能看到的东西。

现在再把“请求-回复”模式的规则说一下:就是,ZMQ_ROUTER能够看到消息的来源,以及消息的去向,并且ZMQ_ROUTER会把接收到的第一个消息作为消息来源的identity,把发送的第一个消息作为消息目的地址的identity。

二、下面是代码,代码由五个文件组成,还有一个makefile。

  我相信在你使用ZMQ的时候已经安装好了ZMQ的链接库,如果确实还没有安装好的话,按照下面这篇文章安装就可以了。http://www.cnblogs.com/fengbohello/p/4046686.html

  注:代码在CentOS下编译并运行通过,其它机器没有测试。

在本页复制或者到我的百度网盘进行下载:dlr2rtr2dlr.rar  http://pan.baidu.com/s/1pJIICpt

comm.h

//comm.h
#ifndef _ZMQCOMM_H_
#define _ZMQCOMM_H_
#include <zmq.h> #define NAME_LEN 256
#define MSG_LEN 1024 typedef struct {
char szSrc[NAME_LEN];
char szDst[NAME_LEN];
char szMsg[MSG_LEN];
}Zmqmsg; typedef struct {
void * sock;
int iType;
}ZmqSock; void lockSocket();
void unlockSocket(); int s_recv(ZmqSock * sock, Zmqmsg * zMsg);
int s_send(ZmqSock * sock, Zmqmsg * zMsg); #endif

comm.c

//comm.c
#include <string.h>
#include "comm.h" void lockSocket()
{
// lock
}
void unlockSocket()
{
// unlock
} int s_recv(ZmqSock * zmqsock, Zmqmsg * zMsg)
{
if(NULL == zmqsock || NULL == zMsg)
{
return -;
}
int iRet = -;
lockSocket();
int iType = ;
int len = sizeof(iType);
void * sock = zmqsock->sock;
do{
iType = zmqsock->iType;
if(ZMQ_ROUTER == iType)
{
printf("router:\n");
errno = ;
if(zmq_recv(sock, zMsg->szSrc, sizeof(zMsg->szSrc), ) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("recv : [%s]\n", zMsg->szSrc);
if(zmq_recv(sock, NULL, , ) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("recv : []\n");
}
else if (ZMQ_DEALER == iType)
{
printf("dealer:\n");
if(zmq_recv(sock, NULL, , ) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("recv : []\n");
}
else if (ZMQ_REQ == iType)
{
printf("req:\n");
}
else if (ZMQ_REP == iType)
{
printf("rep:\n");
} if(zmq_recv(sock, zMsg->szDst, sizeof(zMsg->szDst), ) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("recv : [%s]\n", zMsg->szDst);
if(zmq_recv(sock, NULL, , ) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("recv : []\n");
if(zmq_recv(sock, zMsg->szMsg, sizeof(zMsg->szMsg), ) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("recv : [%s]\n", zMsg->szMsg);
iRet = ;
}while();
unlockSocket(); return iRet;
} int s_send(ZmqSock * zmqsock, Zmqmsg * zMsg)
{
if(NULL == zmqsock || NULL == zMsg)
{
return -;
}
int iRet = -;
lockSocket();
int iType = zmqsock->iType;
int len = sizeof(iType);
void * sock = zmqsock->sock;
do{
if(ZMQ_ROUTER == iType)
{
printf("router:\n");
if(zmq_send(sock, zMsg->szDst, strlen(zMsg->szDst), ZMQ_SNDMORE) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : [%s]\n", zMsg->szDst);
if(zmq_send(sock, "", , ZMQ_SNDMORE) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : []\n");
if(zmq_send(sock, zMsg->szSrc, strlen(zMsg->szSrc), ZMQ_SNDMORE) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : [%s]\n", zMsg->szSrc);
}
else if (ZMQ_DEALER == iType)
{
printf("dealer:\n");
if(zmq_send(sock, "", , ZMQ_SNDMORE) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : []\n");
if(zmq_send(sock, zMsg->szDst, strlen(zMsg->szDst), ZMQ_SNDMORE) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : [%s]\n", zMsg->szDst);
}
else if (ZMQ_REQ == iType || ZMQ_REP == iType)
{
printf("rex:\n");
if(zmq_send(sock, zMsg->szDst, strlen(zMsg->szDst), ZMQ_SNDMORE) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : [%s]\n", zMsg->szDst);
} if(zmq_send(sock, "", , ZMQ_SNDMORE) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : []\n");
if(zmq_send(sock, zMsg->szMsg, strlen(zMsg->szMsg), ) < )
{
printf("send msg faild : [%s]\n", zmq_strerror(errno));
break;
}
printf("send : [%s]\n", zMsg->szMsg);
iRet = ;
}while();
unlockSocket(); return iRet;
}

recv.c

//recv.c
//包含zmq的头文件
#include <zmq.h>
#include <stdio.h>
#include <string.h>
#include "comm.h" int main(int argc, char * argv[])
{
void * pCtx = NULL;
void * pSock = NULL;
const char * pAddr = "ipc://drd.ipc"; //创建context,zmq的socket 需要在context上进行创建
if((pCtx = zmq_ctx_new()) == NULL)
{
return ;
}
//创建zmq socket ,socket目前有6中属性 ,这里使用dealer方式
//具体使用方式请参考zmq官方文档(zmq手册)
if((pSock = zmq_socket(pCtx, ZMQ_DEALER)) == NULL)
{
zmq_ctx_destroy(pCtx);
return ;
}
int iRcvTimeout = ;// millsecond
//设置zmq的接收超时时间为5秒
if(zmq_setsockopt(pSock, ZMQ_RCVTIMEO, &iRcvTimeout, sizeof(iRcvTimeout)) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
char * pName = "recv";
if(zmq_setsockopt(pSock, ZMQ_IDENTITY, pName, strlen(pName)) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
//绑定地址 ipc://drd.ipc
//也就是使用ipc协议进行通信,地址为当前目录下的drd.ipc
if(zmq_connect(pSock, pAddr) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
printf("bind at : %s\n", pAddr);
ZmqSock zmqsock;
zmqsock.iType = ZMQ_DEALER;
zmqsock.sock = pSock;
while()
{
printf("waitting...\n");
errno = ;
//循环等待接收到来的消息,当超过5秒没有接到消息时,
//recv函数返回错误信息 ,并使用zmq_strerror函数进行错误定位
Zmqmsg zmsg;
memset(&zmsg, , sizeof(zmsg));
if(s_recv(&zmqsock, &zmsg) < )
{
printf("error = %s\n", zmq_strerror(errno));
continue;
}
printf("------------------------\n");
} zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}

router.c

//router.c
//包含zmq的头文件
#include <zmq.h>
#include <stdio.h>
#include <string.h>
#include "comm.h" int main(int argc, char * argv[])
{
void * pCtx = NULL;
void * pSock = NULL;
const char * pAddr = "ipc://drd.ipc"; //创建context,zmq的socket 需要在context上进行创建
if((pCtx = zmq_ctx_new()) == NULL)
{
return ;
}
//创建zmq socket ,socket目前有6中属性 ,这里使用dealer方式
//具体使用方式请参考zmq官方文档(zmq手册)
if((pSock = zmq_socket(pCtx, ZMQ_ROUTER)) == NULL)
{
zmq_ctx_destroy(pCtx);
return ;
}
int iRcvTimeout = -;// millsecond
//设置zmq的接收超时时间为5秒
if(zmq_setsockopt(pSock, ZMQ_RCVTIMEO, &iRcvTimeout, sizeof(iRcvTimeout)) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
char * pName = "router";
if(zmq_setsockopt(pSock, ZMQ_IDENTITY, pName, strlen(pName)) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
//绑定地址 ipc://drd.ipc
//也就是使用ipc协议进行通信,地址为当前目录下的drd.ipc
if(zmq_bind(pSock, pAddr) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
printf("bind at : %s\n", pAddr);
ZmqSock zmqsock;
zmqsock.iType = ZMQ_ROUTER;
zmqsock.sock = pSock;
while()
{
printf("waitting...\n");
errno = ;
//循环等待接收到来的消息,当超过5秒没有接到消息时,
//recv函数返回错误信息 ,并使用zmq_strerror函数进行错误定位
Zmqmsg zmsg;
memset(&zmsg, , sizeof(zmsg));
if(s_recv(&zmqsock, &zmsg) < )
{
printf("error = %s\n", zmq_strerror(errno));
continue;
}
if(s_send(&zmqsock, &zmsg) < )
{
printf("error = %s\n", zmq_strerror(errno));
continue;
}
} zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}

send.c

//send.c
//包含zmq的头文件
#include <zmq.h>
#include <stdio.h>
#include <string.h>
#include "comm.h" int main(int argc, char * argv[])
{
void * pCtx = NULL;
void * pSock = NULL;
//使用ipc协议进行通信,需要连接的目标机器IP地址为drd.ipc
const char * pAddr = "ipc://drd.ipc"; //创建context
if((pCtx = zmq_ctx_new()) == NULL)
{
return ;
}
//创建socket
if((pSock = zmq_socket(pCtx, ZMQ_DEALER)) == NULL)
{
zmq_ctx_destroy(pCtx);
return ;
}
int iSndTimeout = ;// millsecond
//设置接收超时
if(zmq_setsockopt(pSock, ZMQ_RCVTIMEO, &iSndTimeout, sizeof(iSndTimeout)) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
char * pName = "send";
if(zmq_setsockopt(pSock, ZMQ_IDENTITY, pName, strlen(pName)) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
if(zmq_connect(pSock, pAddr) < )
{
zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}
printf("connect to [%s]\n", pAddr);
ZmqSock zmqsock;
zmqsock.iType = ZMQ_DEALER;
zmqsock.sock = pSock;
//循环发送消息
while()
{
static int i = ;
Zmqmsg zmsg;
memset(&zmsg, , sizeof(zmsg));
snprintf(zmsg.szDst, sizeof(zmsg.szDst), "recv");
snprintf(zmsg.szMsg, sizeof(zmsg.szMsg), "hello world : %3d", i++);
printf("Enter to send...\n");
if(s_send(&zmqsock, &zmsg) < )
{
fprintf(stderr, "send message faild\n");
}
printf("------------------------\n");
getchar();
} zmq_close(pSock);
zmq_ctx_destroy(pCtx);
return ;
}

Makefile

.PHONY : dummy clean

CFLAGS    = -Wall
LDFLAGS = -lzmq -lpthread CC = gcc -g
CXX = g++ -g
MAKEF = make -f Makefile
CPA = cp -a
MAKE = $(CC) subdir-list = $(patsubst %,_subdir_%,$(SUB_DIRS))
subdir-clean-list = $(patsubst %,_subdir_clean_%,$(SUB_DIRS)) %.o: %.c
$(MAKE) -o $@ -c $< $(CFLAGS) %.o: %.cpp
$(MAKE) -o $@ -c $< $(CFLAGS) %.os: %.c
$(MAKE) -fPIC -c $< -o $@ $(CFLAGS) %.os: %.cpp
$(MAKE) -fPIC -c $< -o $@ $(CFLAGS) ALL_FILES = recv send router all : $(ALL_FILES) recv : recv.o comm.o
$(MAKE) -o $@ $(LDFLAGS) $^ send : send.o comm.o
$(MAKE) -o $@ $(LDFLAGS) $^ router : router.o comm.o
$(MAKE) -o $@ $(LDFLAGS) $^ clean :
rm -rf *.o
rm -rf $(ALL_FILES)

作者 :风波

mail : fengbohello@qq.com

zeromq中两个dealer 通过一个router进行通信的更多相关文章

  1. 【转】 c#中两个DateTimePicker,一个时间设置为0:0:0,另一个设置为23:59:59

    [转] c#中两个DateTimePicker,一个时间设置为0:0:0,另一个设置为23:59:59 stp1为第一个DateTimePicker this.dtp1.Value=this.dtp1 ...

  2. (转)C#中两个问号和一个问号 ??

    小问题难倒很多人.今天发现了这个问题,搜了很长时间才看到记录下. 实例:dt.Columns.Add(firstRow.GetCell(i).StringCellValue ?? string.For ...

  3. 一个页面两个div(一个柱状图或者折线图一个饼图)

    需求是一个页面中两个图,一个饼图一个折线图,接口用的是一个接口,柱状图的图例要隐藏掉,X轴为月份,每月份都有两个数据,也就是图例是两个(进口和出口)的意思饼图需要显示最新月份数据,并且有一个下拉框可以 ...

  4. sql一个表中两个字段合并求和

    sql一个表中两个字段,合并求和 SELECT SUM(字段a+'.'+字段b) as total  from TABLE

  5. C/C++ 中##(两个井号)和#(一个井号)用法

    ##(两个井号)和#(一个井号)都是什么意思 连接符 ##(两个井号) 不知道什么符 #(一个井号) ## 连接符号由两个井号组成,其功能是在带参数的宏定义中将两个子串(token)联接起来,从而形成 ...

  6. C++中##(两个井号)和#(一个井号)用法

    C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结.关 于#和##在C语言的宏中,#的功能是将其后面的宏参数进行字符串化 ...

  7. 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组

    题目描述: 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明:初始化 nums1 和 nums2 的元素数量分别为 m ...

  8. C语言(C++语言)中##(两个井号)和#(一个井号)用法[转]

    文章来源:http://blog.csdn.net/starboybenben/article/details/49803315 C语言(C++语言)中的宏(Macro)属于编译器预处理的范畴,属于编 ...

  9. C#中两个Form窗口之间的传值(父->子)(子->父)

    //首先定义两个Form,一个为Form1,一个为Form2,其中Form1作为父窗口,Form2作为子窗口 //1.父窗口传值给子窗口 //Form1中代码: public Form1() { In ...

随机推荐

  1. 浅谈 jQuery 事件源码定位问题

    该方法已过期,chrome 48还是49开始,自带各种流行框架的事件绑定解析. 勾上这个选项即可. 昨天群里有人问了个事件源码定位的问题,简单描述下是这样的. 在一个不是自己写的页面上,如何快速定位到 ...

  2. javascript数据结构与算法--链表

    链表与数组的区别?  1. 定义: 数组又叫做顺序表,顺序表是在内存中开辟一段连续的空间来存储数据,数组可以处理一组数据类型相同的数据,但不允许动态定义数组的大小,即在使用数组之前必须确定数组的大小. ...

  3. 如何删除PHP数组中的元素,并且索引重排(unset,array_splice)?

    如果要在某个数组中删除一个元素,可以直接用的unset,但是数组的索引不会重排: <?php $arr = array('a','b','c','d'); unset($arr[1]); pri ...

  4. PHP Object 转 Array,Json 转 Array

    object 转 array /** * object 转 array */ function object_to_array($obj){ $_arr = is_object($obj)? get_ ...

  5. BZOJ1565——[NOI2009]植物大战僵尸

    1.题意:有一些点,点与点之间有保护关系,每个点都有一个权值,求能获得的最大值 2.分析:裸的最大权闭合图,用网络流进行求解,然后我们发现点与点之间的保护关系可能构成环,这样网络流是无法处理的,然后我 ...

  6. 【GoLang】golang 中 defer 参数的蹊跷

    参考资料: http://studygolang.com/articles/7994--Defer函数调用参数的求值 golang的闭包和普通函数调用区别:http://studygolang.com ...

  7. POJ推荐50题

    此文来自北京邮电大学ACM-ICPC集训队 此50题在本博客均有代码,可以在左侧的搜索框中搜索题号查看代码. 以下是原文: POJ推荐50题1.标记“难”和“稍难”的题目可以看看,思考一下,不做要求, ...

  8. mysql创建定时任务

    一.前言 自 MySQL5.1.6起,增加了一个非常有特色的功能–事件调度器(Event Scheduler),可以用做定时执行某些特定任务(例如:删除记录.对数据进行汇总等等),来取代原先只能由操作 ...

  9. JAVA学习笔记之与C#对比

    最近在学习java,刚学完入门课程...下面说一下入门课程中相对印象深刻的知识点 JAVA-C#差异 1. for循环 C# string [] strarr=new string[5]; forea ...

  10. Odoo中最小库存规则和按订单生成规则的区别

    ---恢复内容开始--- 最小库存规则(Minimum stock rule)用来保证你的库存产品数量总是不会低于设定的最小库存数量.用来保证产品生产和回到客户的需求.当库存产品低于这个最小库存数量时 ...