不知道函数怎么用的看这篇函数说明
首先了解一下nanomsg的PUBSUB模式的原理
这个只能单方向从server发消息给client。
但是如果想要实现 进程与进程之间、进程与线程之间、线程与线程之间消息的互相传递,也是可以的,我个人进行如下的设计。
就像上面这样,每个 线程/进程 都新建两个线程,一个用来订阅接收,另一个用来发布。当然如果只需要接收不需要发布也可以不创建多个线程。
下面来写一个demo,demo功能如下
进程一 开三个线程 A B C
A线程开两个子线程,发布线程绑定一个本地地址和一个进程地址,并且会发布 05 10 的内容,订阅线程订阅 05 10 03 内容。
B线程开两个子线程,发布线程绑定一个自己的地址,发布 03 的内容,订阅线程订阅 05 的内容。
C线程只是订阅 10 的内容。
进程二 连接进程一中线程A绑定的进程地址,并且订阅 10 内容。
说明:
–> 05 和 10 的内容为线程一的A进程发布的消息,消息格式为当前时间,
–> 05 的消息是当前时间为5s的倍数且不为10s的倍数时发送消息
–> 10 的消息是当前时间为10s的倍数时发送消息
–> 03 的消息是当前时间为3s的倍数并且不为6的倍数时发送消息
代码步骤和说明都直接写在代码注释里
直接上代码:
进程一
//进程一 文件pubsub.c
#include <assert.h>
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#define SOCKET_ADDRESS_A "inproc://A" //线程A的消息队列的地址
#define SOCKET_ADDRESS_B "inproc://B" //线程B的消息队列的地址
#define SOCKET_ADDRESS_IPC_A "ipc:///tmp/a.ipc" //用于进程间通讯的消息队列的地址
#define SOCKET_ADDRESS_C "inproc://c" //线程C的消息队列的地址,这里没有用到
//线程A用于发布消息的线程
void* A_pub_thread(void* arg){
time_t now; //获取本地时间(描数)
int flag = 0;
struct tm* p;
char msg[100]; //发送消息的长度
int rc = 0; //
int ret = 0;
int sock_pub = nn_socket(AF_SP, NN_PUB); //创建一个套接字模式为发布套接字
assert(sock_pub >= 0); //确保创建成功
//绑定本地地址
assert(nn_bind(sock_pub, SOCKET_ADDRESS_A) >= 0);//绑定本地消息队列的地址
assert(nn_bind(sock_pub, SOCKET_ADDRESS_IPC_A) >= 0);//绑定用于进程间消息接收的消息队列的地址
//pub使用来发送的
while (1) {
now = time(NULL); //获取本地时间
rc = 0;
ret = 0;
//如果满足 10 的发送条件
if ((now % 10 == 0) && (flag == 0)) {
flag = 1;
p = gmtime(&now);
memset(&msg, 0, sizeof(msg)); //清空发送缓存
sprintf(msg, "10|%04d-%02d-%02d %02d:%02d:%02d from A", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
//将发送字符串写入缓存,注意格式必须是 类型|内容 这里的类型就是10 内容就是当前时间 +from A
ret = nn_send(sock_pub, msg, sizeof(msg), NN_DONTWAIT);//发送消息
//判断消息是否发送成功
if (ret < 0) {
printf("A pub send msg failed\n");
}
}
//如果满足 05 的发送条件
if ((now % 5 == 0) && (now % 10 != 0) && (flag == 1)) {
//和上面一样,注释就不写了
flag = 0;
p = gmtime(&now);
memset(&msg, 0, sizeof(msg));
sprintf(msg, "05|%04d-%02d-%02d %02d:%02d:%02d from A", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
ret = nn_send(sock_pub, msg, sizeof(msg), NN_DONTWAIT);
if (ret < 0) {
printf("A pub send msg failed\n");
}
}
//一秒循环一次
sleep(1);
}
}
//线程A用于订阅消息的线程
void* A_sub_thread(void* arg){
time_t now; //用于获取当前时间
int flag = 0;
struct tm* p; //时间结构体
char rcvmsg[100]; //用于接收消息
int rc = 0; //判断接收长度
int sock_sub = nn_socket(AF_SP, NN_SUB); //创建用于接收消息的套接字
assert(sock_sub >= 0);//确保创建套接字成功
//绑定本地地址
assert(nn_connect(sock_sub, SOCKET_ADDRESS_A) >= 0);//连接要接收消息的地址
assert(nn_connect(sock_sub, SOCKET_ADDRESS_B) >= 0);//可以同时连接多个
//sub是用来订阅的
nn_setsockopt(sock_sub, NN_SUB, NN_SUB_SUBSCRIBE, "05", 2);//订阅 05 的消息(包括两上面连接的容器的消息)
nn_setsockopt(sock_sub, NN_SUB, NN_SUB_SUBSCRIBE, "10", 2);//订阅 10 的消息(包括两上面连接的容器的消息)
nn_setsockopt(sock_sub, NN_SUB, NN_SUB_SUBSCRIBE, "03", 2);//订阅 03 的消息(包括两上面连接的容器的消息)
//pub使用来发送的
while (1) {
// 清空缓存
memset(&rcvmsg, 0, sizeof(rcvmsg));
//接收消息 第四个参数为0时表示租售接收
rc = nn_recv(sock_sub, &rcvmsg, sizeof(rcvmsg), 0);
if (rc > 0) {
printf("A sub rcv: %s\n", rcvmsg);
rc = 0;
memset(&rcvmsg, 0, sizeof(rcvmsg));
rc = nn_recv(sock_sub, &rcvmsg, NN_MSG, NN_DONTWAIT);
}
}
}
//线程A
void* A_thread(void* arg){
pthread_t thread_A_1, thread_A_2;
pthread_create(&thread_A_1, NULL, A_pub_thread, NULL);
pthread_create(&thread_A_2, NULL, A_sub_thread, NULL);
pthread_join(thread_A_1, NULL);
pthread_join(thread_A_2, NULL);
}
void* B_pub_thread(void* arg){
time_t now;
int flag = 0;
struct tm* p;
char msg[100];
int rc = 0;
int ret = 0;
int sock_pub = nn_socket(AF_SP, NN_PUB);
assert(sock_pub >= 0);
//绑定本地地址
assert(nn_bind(sock_pub, SOCKET_ADDRESS_B) >= 0);
//pub使用来发送的
while (1) {
now = time(NULL);
rc = 0;
ret = 0;
if ((now % 3 == 0) && (now % 2 != 0) && (flag == 0)) {
flag = 1;
p = gmtime(&now);
memset(&msg, 0, sizeof(msg));
sprintf(msg, "03|%04d-%02d-%02d %02d:%02d:%02d from B", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
ret = nn_send(sock_pub, msg, sizeof(msg), NN_DONTWAIT);
if (ret < 0) {
printf("A pub send msg failed\n");
}
}
if ((now % 2 == 0) && (flag == 1)){
flag = 0;
}
sleep(1);
}
}
void* B_sub_thread(void* arg){
time_t now;
int flag = 0;
struct tm* p;
char msg[100];
char rcvmsg[100];
int rc = 0;
int ret = 0;
int sock_sub = nn_socket(AF_SP, NN_SUB);
assert(sock_sub >= 0);
//绑定本地地址
assert(nn_connect(sock_sub, SOCKET_ADDRESS_A) >= 0);
assert(nn_connect(sock_sub, SOCKET_ADDRESS_B) >= 0);
//sub是用来订阅的
nn_setsockopt(sock_sub, NN_SUB, NN_SUB_SUBSCRIBE, "03", 2);
while (1) {
memset(&rcvmsg, 0, sizeof(rcvmsg));
rc = nn_recv(sock_sub, &rcvmsg, sizeof(rcvmsg), 0);
if (rc > 0) {
printf("B sub rcv: %s\n", rcvmsg);
rc = 0;
memset(&rcvmsg, 0, sizeof(rcvmsg));
rc = nn_recv(sock_sub, &rcvmsg, NN_MSG, NN_DONTWAIT);
}
}
}
void* B_thread(void* arg){
pthread_t thread_B_1, thread_B_2;
pthread_create(&thread_B_1, NULL, B_pub_thread, NULL);
pthread_create(&thread_B_2, NULL, B_sub_thread, NULL);
pthread_join(thread_B_1, NULL);
pthread_join(thread_B_2, NULL);
}
void* C_thread(void* arg){
int flag = 0;
struct tm* p;
char rcvmsg[100];
int rc = 0;
int ret = 0;
int sock_sub = nn_socket(AF_SP, NN_SUB);
assert(sock_sub >= 0);
//绑定本地地址
assert(nn_connect(sock_sub, SOCKET_ADDRESS_A) >= 0);
nn_setsockopt(sock_sub, NN_SUB, NN_SUB_SUBSCRIBE, "10", 2);
while (1) {
memset(&rcvmsg, 0, sizeof(rcvmsg));
rc = nn_recv(sock_sub, &rcvmsg, sizeof(rcvmsg), 0);
while (rc > 0) {
printf("C sub rcv: %s\n", rcvmsg);
rc = 0;
memset(&rcvmsg, 0, sizeof(rcvmsg));
rc = nn_recv(sock_sub, &rcvmsg, sizeof(rcvmsg), NN_DONTWAIT);
}
}
}
int main(int argc, char** argv)
{
pthread_t thread_A, thread_B, thread_C;
pthread_create(&thread_A, NULL, A_thread, NULL);
pthread_create(&thread_B, NULL, B_thread, NULL);
pthread_create(&thread_C, NULL, C_thread, NULL);
pthread_join(thread_A, NULL);
pthread_join(thread_B, NULL);
pthread_join(thread_C, NULL);
exit(EXIT_SUCCESS);
}
进程二代码
//进程二
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <assert.h>
#include <unistd.h>
#define SOCKET_ADDRESS_IPC_A "ipc:///tmp/a.ipc"
int main(){
time_t now;
int flag = 0;
struct tm* p;
char rcvmsg[100];
int rc = 0;
int sock_sub = nn_socket(AF_SP, NN_SUB);
assert(sock_sub >= 0);
//绑定本地地址
assert(nn_connect(sock_sub, SOCKET_ADDRESS_IPC_DASS) >= 0);
//sub是用来订阅和接收的
nn_setsockopt(sock_sub, NN_SUB, NN_SUB_SUBSCRIBE, "10", 2);
while (1) {
memset(&rcvmsg, 0, sizeof(rcvmsg));
rc = nn_recv(sock_sub, &rcvmsg, sizeof(rcvmsg), 0);
while (rc > 0) {
printf("2 sub rcv: %s\n", rcvmsg);
rc = 0;
memset(&rcvmsg, 0, sizeof(rcvmsg));
rc = nn_recv(sock_sub, &rcvmsg, sizeof(rcvmsg), NN_DONTWAIT);
}
}
return 0;
}
编译
gcc pubsub.c -o pubsub_1 -lnanomsg -lpthread
gcc pubsub_2.c -o pubsub_2 -lnanomsg