前言
ZMQ是一种性能极高的通信框架,吞吐量大延迟低,使用简便。本文手把手讲解如何用c++实现zmq的订阅和发布,编译环境我们选择了cmake
环境准备
zmq
可以参考我写的这篇:
https://blog.csdn.net/TU_Dresden/article/details/122240469?spm=1001.2014.3001.5502
cmake
可以参考这篇:
https://blog.csdn.net/TU_Dresden/article/details/122373789?spm=1001.2014.3001.5502
新建工程
我们需要配置一个工程,本文把zmq库拷贝到工程目录了,小伙伴们不这样拷贝也可以,但是需要在后面的CMakeList里修改库的目录,改成自己的zmq相关文件的位置。
我们包括一个cmake工程里的基本内容,包括存放源文件的src,存放头文件的include,编译文件夹build,以及包含第三方库的third。
这样的目的是便于文件的管理,在大型项目中,这样的目录配置可以很清晰地管理文件,而且third文件夹里存放了所有的第三方库,使得这个工程不依赖与机器本身的环境,这个工程拿到别的电脑上无需配置相关环境直接就可以运行。题外话,扯远了,哈哈。
数据帧定义
实际应用中,我们几乎不会只发简单的int,float 等基本类型,发送的内容都是以结构体的形式存在的,我们管这种结构体叫做数据帧。
这里我们定义一个自己的数据帧struct_header.h,代码如下:
typedef struct frame_test
{
int status;
float radius;
float area;
int frameid;
};
麻雀虽小,五脏俱全,你可以在结构体里面放任何你想要收发的东西,甚至以char[]数组的形式把图片放进去,发图片涉及opencv,我今后再更新进去。
发送端
这里写一个zmq发送端,send.cpp,也就是zmq的发布者publisher:
#include "struc_header.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include "zmq.h"
int main()
{
void* context = zmq_ctx_new();
assert(context != NULL);
void* publisher = zmq_socket(context, ZMQ_PUB);
assert(publisher != NULL);
int ret = zmq_bind(publisher, "tcp://*:5555");
assert(ret == 0);
int i = 0;
frame_test frame;
while(1)
{
printf("pub ctx: server i = %d\n",i);
frame.frameid = i;
frame.status = 1;
frame.radius = 10*i;
frame.area = frame.radius*frame.radius*3.14159;
ret = zmq_send(publisher, &frame, sizeof(frame_test), 0);
i++;
sleep(1);
}
zmq_close (publisher);
zmq_ctx_destroy (context);
return 0;
}
接收端
接收端就是zmq的订阅者,代码如下:
#include "struc_header.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include "zmq.h"
int main()
{
frame_test frame;
printf("Hello sub!\n");
void* context = zmq_ctx_new();
assert(context != NULL);
void* subscriber = zmq_socket(context, ZMQ_SUB);
assert(subscriber != NULL);
int ret = zmq_connect(subscriber, "tcp://localhost:5555");
assert(ret == 0);
ret = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
assert(ret == 0);
while(1)
{
printf("enter while to sub ctx\n");
ret = zmq_recv(subscriber, &frame, sizeof(frame_test), 0);
if (ret > 0)
{
printf("id: %d\n", frame.frameid);
printf("status: %d\n", frame.status);
printf("radius: %f\n", frame.radius);
printf("area: %f\n", frame.area);
printf("\n");
printf("\n");
}
}
zmq_close(subscriber);
zmq_ctx_destroy(context);
return 0;
}
CMakeLists.txt
编译文件 CMakeLists.txt 也是很重要的一部分,如下所示,注意把里面的目录改成自己的,如果一会编译运行出现问题,多半就是这里或者上面代码里include的有问题,小伙伴们可以自己改一下,想一想这里的每个部分对应自己机器上的那个文件,动手调通之后,你会对整个cmake以及c++的编译由一个新的理解。
cmake_minimum_required(VERSION 3.0.2)
project(zmq_test)
add_compile_options(-std=c++11)
include_directories(
include
third/zmq-4.3.4/include
${CMAKE_CURRENT_SOURCE_DIR}
)
link_directories(
third/zmq-4.3.4/lib
)
add_executable(sender src/send.cpp)
add_executable(recver src/recv.cpp)
link_libraries(third/zmq-4.3.4/lib/libzmq.a)
target_link_libraries(sender zmq)
target_link_libraries(recver zmq)
编译运行
最后,我们编译运行就ok了,成功实现zmq收发和自定义结构体的解析。
cd build
cmake ..
make
./sender
./recver