nanomsg(4) :pub/sub 模式

pub/sub(订阅发布)模式
在这里插入图片描述
了解过mqtt的朋友们对这一套并不陌生。多个进程间通过订阅主题和发布主题,完成数据的交互。
需要注意的是,数据帧的格式:

${主题} | ${ 数据}


// sub.cpp

#include <iostream>
#include <assert.h>
#include <stdio.h>
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>
#include <nanomsg/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>

#ifdef WIN32 || WIN64
#include <windows.h>
#include <time.h>
#include <thread>
#else
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SOCKET_ADDRESS_IPC_A "ipc:///tmp/npi.ipc"


int main(){

    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_A) >= 0);

    assert(nn_setsockopt(sock_sub, NN_SUB, NN_SUB_SUBSCRIBE, "10", 2) >=0 );
    while (1) {
        memset(&rcvmsg, 0, sizeof(rcvmsg));
        rc = nn_recv(sock_sub, &rcvmsg, sizeof(rcvmsg), 0);
        printf("1 sub rc= %d  rcv: %s  \n", rc,rcvmsg);

        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);
            printf("2 sub rc= %d  rcv: %s  \n", rc,rcvmsg);
        }
    }
    return 0;
}

// pubsub.cpp

#include <iostream>
#include <assert.h>
#include <stdio.h>
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>
#include <nanomsg/ipc.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
//进程一 文件pubsub.c
#include <assert.h>
#include <nanomsg/nn.h>
#include <nanomsg/pubsub.h>

#ifdef WIN32 || WIN64
#include <windows.h>
#include <time.h>
#include <thread>
#else
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>



#define SOCKET_ADDRESS_A "inproc://A" //线程A的消息队列的地址
#define SOCKET_ADDRESS_B "inproc://B" //线程B的消息队列的地址
#define SOCKET_ADDRESS_IPC_A "ipc:///tmp/npi.ipc" //用于进程间通讯的消息队列的地址
#define SOCKET_ADDRESS_C "inproc://c" //线程C的消息队列的地址,这里没有用到

char sendMsg[100] = {0};

//线程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;

#if 1
        //如果满足 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");
            }
        }
#else

        //将发送字符串写入缓存,注意格式必须是 类型|内容 这里的类型就是10 内容就是当前时间 +from A
        if(strlen(sendMsg) > 0){
            ret = nn_send(sock_pub, sendMsg, sizeof(sendMsg), NN_DONTWAIT);//发送消息
            //判断消息是否发送成功
            if (ret < 0) {
                printf("A pub send msg failed\n");
            }else{
                memset(&sendMsg, 0, sizeof(sendMsg));
            }
        }

#endif
        //一秒循环一次
        Sleep(1000);
    }
}

//线程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){
#ifndef WIN32 || WIN64
    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);
#else
    std::thread thread_A_1(A_pub_thread,arg);
    std::thread thread_A_2(A_sub_thread,arg);

    thread_A_1.join();
    thread_A_2.join();

#endif
    return 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(1000);
    }
    return NULL;
}

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);
        }
    }
    return NULL;
}

void* B_thread(void* arg){

#ifndef WIN32 || WIN64
    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);
#else
    std::thread thread_B_1(B_pub_thread,arg);
    std::thread thread_B_2(B_sub_thread,arg);

    thread_B_1.join();
    thread_B_2.join();
#endif

    return 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);
        }
    }

    return NULL;
}

int main(int argc, char** argv)
{
#if 1
#ifndef WIN32 || WIN64
    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);
#else

    std::thread thread_A(A_thread,*argv);
    std::thread thread_B(B_thread,*argv);
    std::thread thread_C(C_thread,*argv);

    thread_A.join();
    thread_B.join();
    thread_C.join();
#endif
#else


    sprintf(sendMsg,"%s","10|this is a test A");

    std::thread thread_A(A_thread,*argv);
    thread_A.join();


#endif

    exit(EXIT_SUCCESS);
}


  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

键盘会跳舞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值