zmq与libevent集成及丢包问题分析解决

来源:互联网 发布:东莞数据恢复 dgfix 编辑:程序博客网 时间:2024/06/04 22:43

libevent与socket使用事件方式进行编程的思路是:以zmq的订阅端为例子,订阅端与服务端的连接的fd(文件描述符)加入到libevent的监听队列中,并传入自己的回调函数。正常情况下,当有数据来的时候,libevent会调用用户传入的回调函数,在回调函数里面去将数据取出来即可。


下面需要解决二个问题:

1、如何取得zmq的socket值?

使用getsockopt函数获取。

zmq::socket_t subscribe;int sock_fd = 0;size_t len = sizeof(sock_fd);subscribe.getsockopt(ZMQ_FD, &sock_fd, &len);

2、丢包问题?

当获得之后,按每秒一个包的情况下,能工作得很好,没有问题。但当你发送频率变得很高,每秒几千之后,则出现丢包情况。

分析原因:在于zmq低层采用的是边缘触发机制。当多个数据到达的时候,触发器只会触发一次。

两种机制的区别,大家可以看这篇blog里面说明的:https://funcptr.net/2012/09/10/zeromq---edge-triggered-notification/

解决方案:

当触发回调的时候,需要一次性把数据全部读完。不要只读一次,否则可能存在你多次数据到来的时候,只通知一次的情况。这样情况下,则会导致数据好像“丢失”了。

int zevents = 0;size_t zevents_len = sizeof(zevents);zmq_socket.getsockopt(ZMQ_EVENTS, &zevents, &zevents_len);if (zevents & ZMQ_POLLIN) {    // We can read from the ZeroMQ socket}if (zevents & ZMQ_POLLOUT) {    // We can write to the ZeroMQ socket}


下面附上一个完整的不会丢包的代码:

#include <iostream>#include <sstream>#include <event.h>#include "log_time.h"#include <zmq.hpp>#include <signal.h>struct event_base* evbase; void OnEvent(zmq::socket_t* sock) {            uint32_t events;    size_t sz_events = sizeof(events);    sock->getsockopt(ZMQ_EVENTS, &events, &sz_events);    while(events & ZMQ_POLLIN) {        zmq::message_t msg;        bool ok = sock->recv(&msg, ZMQ_NOBLOCK);        if (!ok) {            perror("not ok here, return");                        }           else {            printf("size = %d, msg = %s\n", msg.size(), msg.data());        }           sock->getsockopt(ZMQ_EVENTS, &events, &sz_events);    }   }void pair_callback(int a, short b, void *point) {    if (NULL == point) {        perror("pair is null,  please check you code\n");        return;    }       zmq::socket_t *sock = (zmq::socket_t *)point;    OnEvent(sock);}int main (int argc, char *argv[]){    signal(SIGPIPE, SIG_IGN);    zmq::context_t context(1);    //  Socket to talk to server    zmq::socket_t sub_socket(context, ZMQ_SUB);    //  Subscribe to zipcode, default is NYC, 10001    sub_socket.setsockopt(ZMQ_SUBSCRIBE, "", 0);    //subscriber.connect("ipc://weather.ipc");    sub_socket.connect("tcp://localhost:6556");    int sock_fd= 0;    size_t len = sizeof(sock_fd);    sub_socket.getsockopt(ZMQ_FD, &sock_fd, &len);    printf("sock_fd = %d\n", sock_fd);    evbase = event_base_new();    printf("event_new\n");    printf("sub_socket = %p\n", &sub_socket);    struct event* ev = event_new(evbase, sock_fd, EV_READ|EV_PERSIST, pair_callback, (void*)&sub_socket);    event_add(ev, NULL);    event_base_dispatch(evbase);    return 0;}




原创粉丝点击