深入浅出libevent的使用(一)

来源:互联网 发布:sql with as 用法 编辑:程序博客网 时间:2024/05/07 20:46

导语:
对libevent源码分析的文章已经很多,在此不在重述原理,但从另外一个角度讲,知晓原理就是为了更好的使用libevent,本文通过介绍libevent中的mini-heap,socketpair以及对evbuffer的使用,展示libevent所依赖的几个基本数据结构

1. min-heap的使用

理解小根堆的原理和使用,对超时事件的理解比较有帮助,min-heap俗称小根堆,就是一个完全二叉树,根结点的数据比左节点大,比右节点也大,类似
这里写图片描述
在libevent中作为对超时事件的时间进行排序,根结点的时间最先超时这么个原理

  • min-heap根结点的初始化:min_heap_ctor
  • 删除根节点: min_heap_dtor
  • min-heap的插入: min_heap_push
  • min-heap的删除: min_heap_pop

示例如下:

    min_heap_ctor(&heap);    for(i = 0;i < 9; ++i) {        inserted[i] = mm_malloc(sizeof(struct event));        set_random_timeout(inserted[i]);        min_heap_push(&heap,inserted[i]);    }    min_heap_print(&heap);    printf("heap size :%d\n",min_heap_size(&heap));     while(1) {        e = min_heap_pop(&heap);        if(!e)            break;        mm_free(e);    }    min_heap_dtor(&heap);

2. socketpair的使用

socketpair的使用场景,主要是在进程间的通信,或者线程间的通信,其原理在源码分析中已经分析的相当透彻,在libevent中的使用,主要是用来在子线程中有可读事件,可写事件,通知主线程,在使用场景中的其他用途,你完全可以发挥想象,socketpair实际上就是两个本地的套接字,在一个进程中监听读,在另外一个进程中写

  • 创建socketpair的方法: evutil_socketpair

示例如下:

 ret = evutil_socketpair(LOCAL_SOCKETPAIR_AF,SOCK_STREAM,0,fds);    if( ret < 0 ) {        printf("evutil_socketpair falt %d!",ret);        return -1;    }    if( fork() ) {        //parent process        int count = 0;        int val;        close(fds[1]);        while(1){            ++count;            write(fds[0],&count,sizeof count);            read(fds[0],&val,sizeof val);            printf("recv data :%d\n",val);        }    }else{        //child process        int val;        close(fds[0]);        while(1){            sleep(1);            read(fds[1],&val,sizeof(val));            printf("recv data :%d\n",val);            val = -val;            write(fds[1],&val,sizeof val);        }    }

3. evbuffer的使用

evbuffer的作用顾名思义就是读写的缓冲区,这部分实现的好坏,实际上关乎一个网络组件的效率高低,所以evbuffer的实现,还是需要花时间去理解,不过使用起来还是蛮简单的,大部分的接口,可以参考event2/buffer.h,这里需要注意的是,当evbuffer在多线程环境下使用时首先要显式调用evthread_use_pthreads函数,并且要调用 evbuffer_enable_locking来初始化evbuffer中的锁,另外需要注意evbuffer是用链表形式实现的,一个节点写入数据会有空闲块,这个空闲块小于一定的阈值时,将创建写节点来写入数据,当节点数据很小时,会创建一个新节点,来容纳这个节点数据和新写入的数据

  • evbuffer_new 创建evbuffer
  • evbuffer_add 往evbuffer中添加数据
  • evbuffer_remove 从evbuffer中拷贝数据并删除
  • evbuffer_drain 直接删除数据

示例代码:

    //写进程    while(1) {        sprintf(message,message_s,++count);        message_len = strlen(message);        //写入数据 \n结尾         evbuffer_add(buf,message,message_len);        length = evbuffer_get_length(buf);        printf("thread write :%d\n",length);        total += message_len;        sleep(1);    }    //读进程    read_message = evbuffer_readln(buf,&read_message_len,EVBUFFER_EOL_CRLF);    if (NULL != read_message) {         printf("thread read :%s\n",read_message);         length += read_message_len;    }

完整参考:https://github.com/dengwenyi88/test_libevent/

结论:读者也可以在示例中使用更多的接口,加深使用libevent的理解,同时对源码实现的基本原理的理解有帮助,bufferevent的工作流程是依赖于,对event和event_base的进一步封装,在对套接字的读超时和写超时处理,就用到事件的超时处理,同时对socket的读监听事件和写监听事件,都涉及到event_base的基本原理,以及evbuffer中事件的回调处理

参考:

  • 小根堆 http://blog.csdn.net/ganggexiongqi/article/details/7449970

  • libevent源码分析: http://blog.csdn.net/column/details/libevent-src.html

0 0