libevent简介

一、参考资料

      1. Libevent深入浅出

  1、ubuntu下安装libevent

  2. 官网:

  2、libevent实现TCP server 服务端

  3、libevent学习篇之一:libevent快速入门

  4、网络编程(三):从libevent到事件通知机制

  5、libevent深入浅出

  6、Libevent 的多线程操作

  7、libevent源码学习(12):超时管理之common_timeout

  8、libevent源码分析二--timeout事件响应

    9、C++ - 解除epoll_wait的阻塞状态

  10. 基于libevent实现定时器

  11. libevent实现TCP 客户端

  12. libevent源码学习(16):通知唤醒主线程、条件变量的等待与唤醒

  13.  libevent——bufferevent的使用与实现

  14. Libevent 学习

  15. bufferevent_write以及bufferevent工作流程探究

  16. libevent使用的简单案例

  17. libevent编程疑难解答 

  18. Libevent使用例子,从简单到复杂

  19. Libevent源码分析

  20. Libevent 编程指南

二、安装过程

  1. 下载

    libevent-2.1.12-stable.tar.gz阿里镜像:

  2. 解压:

tar -xvf libevent-2.1.12-stable.tar.gz 

  3. ./configure 

  4.  cmake

cmake .

    遇到错误提示:

    

 

   5. 安装OpenSSL 

    参考文档:https://blog.csdn.net/weixin_42255281/article/details/110820736

sudo apt-get install libssl-dev

    然后重新cmake,目录下会生成Makefile文件

  6.  make

make

  7. make install

sudo make install

  默认安装目录是:/usr/local

  8. 查看结果:

 

 

   9. 运行tcp_client程序报错

   其tcp_client程序需要加载libevent库,但编译正常,运行报错提示如下:

  

 

   解决办法参考:error while loading shared libraries: libevent-2.1.so.7: cannot open shared object file,步骤如下:

1)用vim或gedit打开/etc/ld.so.conf文件,在该文件末尾加上/usr/local/lib
2sudo ldconfig

 

三. 使用经验

  1、创建一个event_base, 即:event_base_new(), 如下:

//创建一个event_base
struct event_base *base = event_base_new();

    event_base_new()函数原型及简介:

/**
 * Create and return a new event_base to use with the rest of Libevent.
 *
 * @return a new event_base on success, or NULL on failure.
 *
 * @see event_base_free(), event_base_new_with_config()
 */
EVENT2_EXPORT_SYMBOL
struct event_base *event_base_new(void);

    参考文档:  libevent学习篇之一:libevent快速入门

    libevent默认情况下是单线程的,可以配置成多线程,每个线程有且只有一个event_base,对应一个struct event_base结构体以及附于其上的事件管理器,用来调度托管给它的一系列event,可以和操作系统的进程管理类比。当一个事件发生后,event_base会在合适的时间,不一定是立即去调用绑定在这个事件上的函数,直到这个函数执行完,再去调度其他的事件.
    event_base内部有一个循环,循环阻塞在epoll等系统调用上,直到有一个/一些时间发生,然后去处理这些事件。当然,这些事件要被绑定在这个event_base上,每个事件对应一个struct event,可以是监听一个fd或者信号量之类的,struct event使用event_new来创建和绑定,使用event_add来将event绑定到event_base中。

  2、创建一个event: 即event_new()

     示例: 
// 创建并绑定一个event
struct event* listen_event;

//参数:event_base,监听的对象,需要监听的事件,事件发生后的回调函数,传给回调函数的参数
listen_event = event_new(base, listener, EV_READ | EV_PERSIST, callback_func, (void*)base);
//参数:event,超时时间,NULL表示无超时设置
event_add(listen_event, NULL);
     函数原型及简介:
/**
  Allocate and asssign a new event structure, ready to be added.

  The function event_new() returns a new event that can be used in
  future calls to event_add() and event_del().  The fd and events
  arguments determine which conditions will trigger the event; the
  callback and callback_arg arguments tell Libevent what to do when the
  event becomes active.

  If events contains one of EV_READ, EV_WRITE, or EV_READ|EV_WRITE, then
  fd is a file descriptor or socket that should get monitored for
  readiness to read, readiness to write, or readiness for either operation
  (respectively).  If events contains EV_SIGNAL, then fd is a signal
  number to wait for.  If events contains none of those flags, then the
  event can be triggered only by a timeout or by manual activation with
  event_active(): In this case, fd must be -1.

  The EV_PERSIST flag can also be passed in the events argument: it makes
  event_add() persistent until event_del() is called.

  The EV_ET flag is compatible with EV_READ and EV_WRITE, and supported
  only by certain backends.  It tells Libevent to use edge-triggered
  events.

  The EV_TIMEOUT flag has no effect here.

  It is okay to have multiple events all listening on the same fds; but
  they must either all be edge-triggered, or all not be edge triggerd.

  When the event becomes active, the event loop will run the provided
  callbuck function, with three arguments.  The first will be the provided
  fd value.  The second will be a bitfield of the events that triggered:
  EV_READ, EV_WRITE, or EV_SIGNAL.  Here the EV_TIMEOUT flag indicates
  that a timeout occurred, and EV_ET indicates that an edge-triggered
  event occurred.  The third event will be the callback_arg pointer that
  you provide.

  @param base the event base to which the event should be attached.
  @param fd the file descriptor or signal to be monitored, or -1.
  @param events desired events to monitor: bitfield of EV_READ, EV_WRITE,
      EV_SIGNAL, EV_PERSIST, EV_ET.
  @param callback callback function to be invoked when the event occurs
  @param callback_arg an argument to be passed to the callback function

  @return a newly allocated struct event that must later be freed with
    event_free().
  @see event_free(), event_add(), event_del(), event_assign()
 */
EVENT2_EXPORT_SYMBOL
struct event *event_new(struct event_base *, evutil_socket_t, short, event_callback_fn, void *);

  3、把event绑定到event_base中, 即event_add()

    函数原型及简介:
/**
  Add an event to the set of pending events.

  The function event_add() schedules the execution of the event 'ev' when the
  condition specified by event_assign() or event_new() occurs, or when the time
  specified in timeout has elapesed.  If atimeout is NULL, no timeout
  occurs and the function will only be
  called if a matching event occurs.  The event in the
  ev argument must be already initialized by event_assign() or event_new()
  and may not be used
  in calls to event_assign() until it is no longer pending.

  If the event in the ev argument already has a scheduled timeout, calling
  event_add() replaces the old timeout with the new one if tv is non-NULL.

  @param ev an event struct initialized via event_assign() or event_new()
  @param timeout the maximum amount of time to wait for the event, or NULL
         to wait forever
  @return 0 if successful, or -1 if an error occurred
  @see event_del(), event_assign(), event_new()
  */
EVENT2_EXPORT_SYMBOL
int event_add(struct event *ev, const struct timeval *timeout);

  4、定义回调函数

    原型及简介如下:

/**
   A callback function for an event.

   It receives three arguments:

   @param fd An fd or signal
   @param events One or more EV_* flags
   @param arg A user-supplied argument.

   @see event_new()
 */
typedef void (*event_callback_fn)(evutil_socket_t, short, void *);

    示例如下:

//tcp客户端读socket数据
struct event *ev_sockfd = event_new(base, sockfd,  
                                        EV_READ | EV_PERSIST,  
                                        socket_read_cb, NULL); 

void socket_read_cb(int fd, short events, void *arg)  
{  
    char msg[1024];  
  
    //为了简单起见,不考虑读一半数据的情况  
    int len = read(fd, msg, sizeof(msg)-1);  
    if( len <= 0 )  
    {  
        perror("read fail ");  
        exit(1);  
    }  
  
    msg[len] = '\0';  
  
    printf("recv %s from server\n", msg);  
}

  5、启动event_base的循环,开始处理事件:event_base_dispatch()

  原型及简介如下:

/**
   Event dispatching loop

  This loop will run the event base until either there are no more pending or
  active, or until something calls event_base_loopbreak() or
  event_base_loopexit().

  @param base the event_base structure returned by event_base_new() or
     event_base_new_with_config()
  @return 0 if successful, -1 if an error occurred, or 1 if we exited because
     no events were pending or active.
  @see event_base_loop()
 */
EVENT2_EXPORT_SYMBOL
int event_base_dispatch(struct event_base *);

  6、退出循环:event_base_loopbreak()

    原型及简介如下:
/**
  Abort the active event_base_loop() immediately.

  event_base_loop() will abort the loop after the next event is completed;
  event_base_loopbreak() is typically invoked from this event's callback.
  This behavior is analogous to the "break;" statement.

  Subsequent invocations of event_base_loop() will proceed normally.

  @param eb the event_base structure returned by event_init()
  @return 0 if successful, or -1 if an error occurred
  @see event_base_loopexit()
 */
EVENT2_EXPORT_SYMBOL
int event_base_loopbreak(struct event_base *);

  7、删除event及free和close

 示例如下:

if (ws->thread.ev) {
        event_fd = event_get_fd(ws->thread.ev); 
        if (event_fd > 0)
            close(event_fd);  //关闭文件描述符
        event_del(ws->thread.ev);  //从event_base中删除event
        event_free(ws->thread.ev);  //释放event
        ws->thread.ev = NULL;
    }

   8、查看libevent参数配置

    1)config.h

    2)config.log

 

四. 对bufferevent的封装示例

  1.  参照http.c中的evhttp_write_buffer函数

static void
evhttp_write_buffer(struct evhttp_connection *evcon,
    void (*cb)(struct evhttp_connection *, void *), void *arg)    //http.c
{
    event_debug(("%s: preparing to write buffer\n", __func__));

    /* Set call back */
    evcon->cb = cb;
    evcon->cb_arg = arg;

    /* Disable the read callback: we don't actually care about data;
     * we only care about close detection. (We don't disable reading --
     * EV_READ, since we *do* want to learn about any close events.) */
    bufferevent_setcb(evcon->bufev,        //bufferevent_setcb是bufferevent.c提供的接口函数
        NULL, /*read*/
        evhttp_write_cb,        //http.c
        evhttp_error_cb,        //http.c
        evcon);                    //evcon通过私有参数传递给回调函数

    bufferevent_enable(evcon->bufev, EV_READ|EV_WRITE);
}
            
static void
evhttp_write_cb(struct bufferevent *bufev, void *arg) //http.c,中间转换层函数
{
    struct evhttp_connection *evcon = arg;   //通过私有参数,获得其真实对象

    /* Activate our call back */
    if (evcon->cb != NULL)            //实际需要调用的cb
        (*evcon->cb)(evcon, evcon->cb_arg);
}

   2. write_cb被调用的反推过程

   1)回调函数注册

void
bufferevent_setcb(struct bufferevent *bufev,
    bufferevent_data_cb readcb, bufferevent_data_cb writecb,
    bufferevent_event_cb eventcb, void *cbarg)      //bufferevent.c
{
    BEV_LOCK(bufev);

    bufev->readcb = readcb;
    bufev->writecb = writecb;
    bufev->errorcb = eventcb;

    bufev->cbarg = cbarg;
    BEV_UNLOCK(bufev);
}

   2)写回调函数被调用的反推过程

main()                                        //https-client.c
    bufferevent_socket_new                    //bufferevent_sock.c
        bufferevent_writecb                    //bufferevent_sock.c
            bufferevent_trigger_nolock_        //bufferevent-internal.h
                bufferevent_run_writecb_       //bufferevent.c
                    bufev->writecb(bufev, bufev->cbarg);

 

posted @ 2020-02-25 09:42  shanyu20  阅读(342)  评论(0编辑  收藏  举报