ZeroMQ 服务端与客户端通信案例[转]
- 客户端发送“Hello”,服务器用“World” 应答
- 参考:https://github.com/booksbyus/zguide/tree/master/examples/C
客户端:
#include <stdio.h> #include <string.h> #include <assert.h> #include "zmq.hpp" #include <Windows.h> #pragma comment(lib,"unity.lib") #pragma comment(lib,"testutil-static.lib") #pragma comment(lib,"testutil.lib") #pragma comment(lib,"libzmq-v140-mt-gd-4_3_5.lib") #pragma comment(lib,"libzmq-v140-mt-sgd-4_3_5.lib") int main(void) { printf("Connecting to hello world server...\n"); //创建上下文 void *context = zmq_ctx_new(); //创建套接字 void *requester = zmq_socket(context, ZMQ_REQ); //连接服务器 zmq_connect(requester, "tcp://localhost:5555"); int request_nbr; for (request_nbr = 0; request_nbr != 10; request_nbr++) { //发送Hello char buffer[10]; printf("Sending Hello %d...\n", request_nbr); zmq_send(requester, "Hello", 5, 0); //接收 World zmq_recv(requester, buffer, 10, 0); printf("Received World %d\n", request_nbr); } //关闭套接字 zmq_close(requester); //释放上下文 zmq_ctx_destroy(context); return 0; }
服务端:
#include <stdio.h> #include <string.h> #include <assert.h> #include "zmq.h" #include <Windows.h> #pragma comment(lib,"unity.lib") #pragma comment(lib,"testutil-static.lib") #pragma comment(lib,"testutil.lib") #pragma comment(lib,"libzmq-v140-mt-gd-4_3_5.lib") #pragma comment(lib,"libzmq-v140-mt-sgd-4_3_5.lib") int main(void) { //创建上下文 void *context = zmq_ctx_new(); //创建套接字 void *responder = zmq_socket(context, ZMQ_REP); //绑定端口 int rc = zmq_bind(responder, "tcp://*:5555"); assert(rc == 0); while (1) { //接收信息 char buffer[10]; zmq_recv(responder, buffer, 10, 0); printf("Received Hello\n"); Sleep(100); // Do some 'work' //发送World信息 zmq_send(responder, "World", 5, 0); } return 0; }
- 输出:
ZeroMQ 字符串规则
- ZeroMQ字符串是指定长度的,并且在线路上发送时不含结尾空字符。
- 最简单情况下,一个ZeroMQ字符串整齐的映射到一个ZeroMQ消息帧。
- 示例(从套接字接收ZeroMQ字符串并转为C字符串),更多参考“zhelpers.h”
static char *s_recv(void* socket) { zmq_msg_t message; zmq_msg_init(&message); int size = zmq_msg_recv(&message, socket, 0); if(size == -1) return NULL; char *string = (char*)malloc(size + 1); memcpy(string, zmq_msg_data(&message), size); zmq_msg_close(&message); string[size] = 0; return (string); }
- 发布-订阅案例
- 服务端:
#include <stdio.h> #include <string.h> #include <assert.h> #include "zmq.hpp" #include <Windows.h> #ifdef DEBUG_0MQ #pragma comment(lib,"unity.lib") #pragma comment(lib,"testutil-static.lib") #pragma comment(lib,"testutil.lib") #pragma comment(lib,"libzmq-v140-mt-gd-4_3_5.lib") #pragma comment(lib,"libzmq-v140-mt-sgd-4_3_5.lib") #else #pragma comment(lib,"unity.lib") #pragma comment(lib,"testutil-static.lib") #pragma comment(lib,"testutil.lib") #pragma comment(lib,"libzmq-v140-mt-4_3_5.lib") #pragma comment(lib,"libzmq-v140-mt-s-4_3_5.lib") #endif #if (defined (WIN32)) # define srandom srand # define random rand #endif // 生成随机数 从0到(num - 1) #define randof(num) (int) ((float) (num) * random () / (RAND_MAX + 1.0)) //发送数据 static int s_send(void *socket, char *string); int main(void) { //创建上下文 void *context = zmq_ctx_new(); //创建套接字,并设置为发布 void *publisher = zmq_socket(context, ZMQ_PUB); //绑定IP端口 int rc = zmq_bind(publisher, "tcp://*:5556"); assert(rc == 0); rc = zmq_bind(publisher, "ipc://weather.ipc"); assert(rc == 0); //生成随机值 srandom((unsigned)time(NULL)); while (1) { //生成信息 int zipcode, temperature, relhumidity; zipcode = randof(100000); temperature = randof(215) - 80; relhumidity = randof(50) + 10; //发布消息给订阅者 char update[20]; sprintf(update, "%05d %d %d\n", zipcode, temperature, relhumidity); //Sleep(1000); //printf("%05d %d %d\n", zipcode, temperature, relhumidity); s_send(publisher, update); } //关闭、释放资源 zmq_close(publisher); zmq_ctx_destroy(context); return 0; } static int s_send(void *socket, char *string) { zmq_msg_t msg; zmq_msg_init_size(&msg, strlen(string)); memcpy(zmq_msg_data(&msg), string, strlen(string)); //发送数据 int rc = zmq_msg_send(&msg, socket, 0); // 关闭zmq_msg_t对象 zmq_msg_close(&msg); return rc; }
- 客户端:
#include <stdio.h> #include <string.h> #include <assert.h> #include "zmq.h" #include <Windows.h> //#define DEBUG_0MQ #ifdef DEBUG_0MQ #pragma comment(lib,"unity.lib") #pragma comment(lib,"testutil-static.lib") #pragma comment(lib,"testutil.lib") #pragma comment(lib,"libzmq-v140-mt-gd-4_3_5.lib") #pragma comment(lib,"libzmq-v140-mt-sgd-4_3_5.lib") #else #pragma comment(lib,"unity.lib") #pragma comment(lib,"testutil-static.lib") #pragma comment(lib,"testutil.lib") #pragma comment(lib,"libzmq-v140-mt-4_3_5.lib") #pragma comment(lib,"libzmq-v140-mt-s-4_3_5.lib") #endif #if (defined (WIN32)) # define srandom srand # define random rand #endif // 生成随机数 从0到(num - 1) #define randof(num) (int) ((float) (num) * random () / (RAND_MAX + 1.0)) //接收消息 static char *s_recv(void* socket); int main(int argc, char *argv[]) { printf("Collecting updates from weather server...\n"); //创建上下文 void *context = zmq_ctx_new(); //创建套接字,设置Wie订阅 void *subscriber = zmq_socket(context, ZMQ_SUB); //连接服务器 int rc = zmq_connect(subscriber, "tcp://localhost:5556"); assert(rc == 0); //订阅邮政编码,默认NYC 10001 const char *filter = (argc > 1) ? argv[1] : "10001 "; rc = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, filter, strlen(filter)); assert(rc == 0); //更新100条 int update_nbr; long total_temp = 0; for (update_nbr = 0; update_nbr < 10; update_nbr++) { printf("开始接收第 %d 信息\n", update_nbr); char *string = s_recv(subscriber); printf("%s\n", string); int zipcode, temperature, relhumidity; sscanf(string, "%d %d %d", &zipcode, &temperature, &relhumidity); total_temp += temperature; free(string); } printf("Average temperature for zipcode '%s' was %dF\n", filter, (int)(total_temp / update_nbr)); //关闭、释放资源 zmq_close(subscriber); zmq_ctx_destroy(context); return 0; } //接收消息 static char *s_recv(void* socket) { zmq_msg_t message; zmq_msg_init(&message); int size = zmq_msg_recv(&message, socket, 0); if (size == -1) return NULL; char *string = (char*)malloc(size + 1); memcpy(string, zmq_msg_data(&message), size); zmq_msg_close(&message); string[size] = 0; return string; }