zmq 代理模式异步代码(czmq)

最近在做服务器,发现zmq的同步收发不是很适合项目需求,这里有一套异步模式的zmq demo分享给大家,仅供参考.
我这里使用的是 代理模式,
1.client 代码 这里使用的.hpp的zmq,发现并不好,建议使用.h的zmq.

#include <zmq.hpp>
#include <iostream>
#include <string>
#include "czmq.h"

using std::endl;
using std::cout;
using namespace std;

int main()
{
    zmq::context_t Context(1);
    zmq::socket_t ReqSock(Context, ZMQ_DEALER);
    char identity [10];
    sprintf (identity, "%04X-%04X", randof (0x10000), randof (0x10000));
    ReqSock.setsockopt(ZMQ_IDENTITY,"identity",10);
    ReqSock.connect("tcp://localhost:5559");

    zmq_pollitem_t items [] = { { ReqSock, 0, ZMQ_POLLIN, 0 } };
    int request_nbr = 0;

    while (true) {
        //  Tick once per second, pulling in arriving messages
        int centitick;
        for (centitick = 0; centitick < 100; centitick++) {
            zmq_poll (items, 1, 10 * ZMQ_POLL_MSEC);
            if (items [0].revents & ZMQ_POLLIN) {
                zmsg_t *msg = zmsg_recv (ReqSock);
                zframe_t *cont = zmsg_pop (msg);
                if(cont)
                {
                    char* p_cont2 = zframe_strdup(cont);
                    cout<<"p_cont2:"<<p_cont2<<endl;
                }

                zmsg_destroy (&msg);
            }
       }
        zstr_sendf (ReqSock, "request #%d", ++request_nbr);
    }

    while (true)
    {
        printf("press Enter to send message\n");
        getchar();
        string tmpstr;
        //发送消息
        zmq_msg_t msgOut; // 创建消息结构
        zmq_msg_init_size (&msgOut, tmpstr.size()+1); // 以字符串长度(不包括'\0')初始化成消息
        memcpy (zmq_msg_data (&msgOut), tmpstr.c_str(), tmpstr.size()+1); // 将字符串的内容(不包括'\0')拷贝给消息
        zmq_msg_send(&msgOut,ReqSock,0); // 发送消息
        zmq_msg_close (&msgOut); // 释放和销毁消息

        zmq_msg_t msgIn;
        zmq_msg_init(&msgIn);
        zmq_msg_recv(&msgIn, ReqSock, 0);
        cout << "recv:" << (char*)zmq_msg_data(&msgIn) << endl;
        zmq_msg_close(&msgIn);
    }
    ReqSock.close();
    Context.close();
    return 0;
}


2.server(也就是worker)

void main()
{
        void* rspSock = zmq_socket(context, ZMQ_DEALER);
        int r = zmq_connect(rspSock, cp->zmqAddr.c_str());
        if (r == -1) {
            LOG(ERROR) << "zmq_connect failure ";
            zmq_close(rspSock);
            return;
        }

        zmq_pollitem_t items[] = { {rspSock, 0, ZMQ_POLLIN, 0} };
        while (true) {
            int rc = zmq_poll(items, 1, 10 * ZMQ_POLL_MSEC );
            if (rc == -1) {
                printf ("Error zmq_poll return -1: %s\n", zmq_strerror (errno));
                break;
            }
            if (items [0].revents & ZMQ_POLLIN) {
                zmqSender->sendmtx.lock();
                zmsg_t *msg = zmsg_recv(rspSock);
                zmqSender->sendmtx.unlock();
                zframe_t *addr = zmsg_pop(msg);
                zframe_t *cont = zmsg_pop(msg);
                assert (cont);

                ///下面的代码段也可以使用zframe_strdup如果使用zframe_strdup()函数,一定要使用free()来释放内存
                assert (zframe_is (cont));
                size_t size = zframe_size (cont);
                char *contstr = (char *) malloc (size + 1);
                assert (contstr);
                memcpy (contstr, zframe_data (cont), size);
                contstr [size] = 0;

                //char* contstr = zframe_strdup(cont); //contstr就是解析出来的消息正文内容
                if (strlen(contstr) > 0)
                {
                    //处理消息
                }
                if(contstr)
                {
                    free(contstr);
                    contstr = nullptr;
                }
            }
        }
}

发送消息时使用收到消息时的addr和cont:
            zframe_send(&addr, rspSock, ZFRAME_REUSE + ZFRAME_MORE);
            zframe_reset(cont, response.c_str(), msg.response.size()+1);
            zframe_send(&cont, rspSock, ZFRAME_REUSE);
            sendmtx.unlock();
            zframe_destroy(&addr);
            zframe_destroy(&cont);
另外要注意的是:zmq socket是线程不安全的,收发适当加锁吧.

3.router代码

#include <cstdio>
#include <cassert>
#include <thread>
#include <chrono>
#include <memory>
#include <vector>
#include <zmq.h>
#include <string.h>
#include <iostream>

using namespace std;

static void create_broker(void* context, const char* front_addr, const char* back_addr);

int main(int argc, char* argv[])
{
    int major, minor, patch;
    zmq_version(&major, &minor, &patch);
    int version = ZMQ_MAKE_VERSION(major, minor, patch);
    if (version < ZMQ_VERSION)
    {
        printf("zmq library expect version %d but get %d.\n", ZMQ_VERSION, version);
        return 1;
    }

    void *context = zmq_ctx_new();
    const char* front_addr = "tcp://127.0.0.1:5559";
    const char* back_addr = "tcp://127.0.0.1:5560";

    // create broker
    auto broker = make_shared<thread>(create_broker, context, front_addr, back_addr);

    if (broker)
    {
        broker->join();
    }
    zmq_ctx_destroy(context);

    return 0;
}

void create_broker(void* context, const char* front_addr, const char* back_addr)
{
    assert(context && front_addr && back_addr);
    void* frontend = zmq_socket(context, ZMQ_ROUTER);
    void* backend = zmq_socket(context, ZMQ_DEALER);
    assert(frontend && backend);
    int r = zmq_bind(frontend, front_addr);
    if (r!=0)
        printf("error:bind failure ,port is used...\n");
    r = zmq_bind(backend, back_addr);
    if (r!=0)
        printf("error:bind failure ,port is used...\n");

    printf("broker started...\n");

    zmq_proxy(frontend, backend, NULL);
    zmq_close(frontend);
    zmq_close(backend);

    printf("broker[%d] closed...\n", pthread_self());
}

猜你喜欢

转载自blog.csdn.net/wushuangge/article/details/80776044
zmq