libevent (三) 事件註冊與循環監聽

事件註冊與循環監聽

在libevent中爲了監聽某種事件的發生,設置事件觸發後的回調函數,也就是說對該事件註冊到當前的IO模型中。socket

事件註冊

事件初始化

使用`event_new`函數來對事件進行初始化。函數

typedef void (*event_callback_fn)(evutil_socket_t, short, void *);/* 回調函數 */ struct event *event_new(struct event_base *base, evutil_socket_t fd,
    short what, event_callback_fn cb,
    void *arg);

void event_free(struct event *event);
/*
 * base:event_base類型,event_base_new的返回值
 * fd:監聽的fd,listen的fd
 * what:事件的類型及屬性
 * cb:綁定的回調函數
 * arg:給回調函數的參數
 */

其中,事件類型及屬性以下:oop

#define EV_TIMEOUT 0x01 /*定時事件*/
#define EV_READ 0x02 /*I/O事件*/
#define EV_WRITE 0x04 /*I/O事件*/
#define EV_SIGNAL 0x08 /*信號*/
#define EV_PERSIST 0x10 /*永久事件 */
#define EV_ET 0x20 /*邊沿觸發*/

此外,還有一個函數`event_assgin`,它多了一個event參數:spa

int event_assign(struct event *event, struct event_base *base,
    evutil_socket_t fd, short what,
    void (*callback)(evutil_socket_t, short, void *), void *arg);

註冊事件

雖然已經初始化了事件,可是該事件並不會被觸發,緣由在於咱們並無激活該事件。線程

`event_add`函數提供了激活事件的功能。debug

int event_add(struct event *ev, const struct timeval *tv);

若是是一個(non-pending)未註冊`ev`,調用`event_add`函數會註冊該事件(變爲pending狀態)。若是是一個(pending)註冊過的`ev`,調用該函數會在tv時間後從新註冊該事件。成功返回0,失敗返回-1。code

例子

#include <event2/event.h>

void cb_func(evutil_socket_t fd, short what, void *arg)
{
        const char *data = arg;
        printf("Got an event on socket %d:%s%s%s%s [%s]",
            (int) fd,
            (what&EV_TIMEOUT) ? " timeout" : "",
            (what&EV_READ)    ? " read" : "",
            (what&EV_WRITE)   ? " write" : "",
            (what&EV_SIGNAL)  ? " signal" : "",
            data);
}

void main_loop(evutil_socket_t fd1, evutil_socket_t fd2)
{
        struct event *ev1, *ev2;
        struct timeval five_seconds = {5,0};
        struct event_base *base = event_base_new();

        /* The caller has already set up fd1, fd2 somehow, and make them
           nonblocking. */
      /* 初始化事件 */
        ev1 = event_new(base, fd1, EV_TIMEOUT|EV_READ|EV_PERSIST, cb_func,(char*)"Reading event");
        ev2 = event_new(base, fd2, EV_WRITE|EV_PERSIST, cb_func,(char*)"Writing event");
        /* 註冊事件 */
        event_add(ev1, &five_seconds);
        event_add(ev2, NULL);
        /* 循環監聽 */
        event_base_dispatch(base);
}

查找正在運行的事件

struct event *event_base_get_running_event(struct event_base *base);

設置事件執行一次

該函數和`event_base`相似,可是不支持`EV_SIGNAL or EV_PERSIST`。
int event_base_once(struct event_base *, evutil_socket_t, short,void (*)(evutil_socket_t, short, void *), void *, const struct timeval *);

激活事件

若是想本身激活某個事件,那麼能夠執行下面的函數:
void event_active(struct event *ev, int what, short ncalls);
/*
 * 參數ev爲要激活的事件 
 * what能夠爲EV_READ, EV_WRITE, and EV_TIMEOUT
 * ncalls爲激活次數
 */

其餘函數

#define evtimer_new(base, callback, arg) \
    event_new((base), -1, 0, (callback), (arg))
#define evtimer_add(ev, tv) \
    event_add((ev),(tv))
#define evtimer_del(ev) \
    event_del(ev)
#define evtimer_pending(ev, tv_out) \
    event_pending((ev), EV_TIMEOUT, (tv_out))

循環監聽

當已經擁有註冊了IO複用方法的`event_base`後,能夠經過`event_loop`來監聽並接受IO事件。

打開event loop

//@param: flags
//等待IO事件
#define EVLOOP_ONCE 0x01
//非阻塞,直接返回
#define EVLOOP_NONBLOCK 0x02 
//其餘的線程中添加事件
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04

int event_base_loop(struct event_base *base, int flags);

`event_loop`會檢查全部IO複用方法的狀態,一旦啓動就會激活並使用這些IO複用方法。

若是不使用flag,能夠條用下面這個函數,功能等同於`event_base_loop`,調用該函數會一直阻塞在這裏,等待時間的觸發。
int event_base_dispatch(struct event_base *base);

關閉event loop

//延遲tv時間後,中止event loop
int event_base_loopexit(struct event_base *base, const struct timeval *tv);
//馬上中止,等同於tv = NULL
int event_base_loopbreak(struct event_base *base);

//獲取退出方式
int event_base_got_exit(struct event_base *base);
int event_base_got_break(struct event_base *base);

debug

這個函數能夠把`event_base`中信息和狀態寫入文件中。
void event_base_dump_events(struct event_base *base, FILE *f);

例子

#include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#endif
#include <time.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/util.h>


struct timeval lasttime;

int event_is_persistenet;

static void
timeout_cb(evutil_socket_t fd, short event, void *arg)
{
    struct timeval newtime, difference;
    struct event *timeout = arg;
    double elapsed;

    evutil_gettimeofday(&newtime, NULL);
    evutil_timersub(&newtime, &lasttime, &difference);
    elapsed = difference.tv_sec + (difference.tv_usec / 1.0e6);

    printf("timeout_cb called at %d: %.3f seconds elapsed.\n",
    (int)newtime.tv_sec, elapsed);
    lasttime = newtime;

    if (! event_is_persistent) {
        struct timeval tv;
        evutil_timerclear(&tv);
        tv.tv_sec = 2;
        event_add(timeout, &tv);
    }
}

int main(int argc, char **argv)
{
    struct event timeout;
    struct timeval tv;
    struct event_base *base;
    int flags;

    if (argc == 2 && !strcmp(argv[1], "-p")) {
        event_is_persistent = 1;
        flags = EV_PERSIST;
    } else {
        event_is_persistent = 0;
        flags = 0;
    }

    /* Initalize the event library */
    base = event_base_new();

    /* Initalize one event */
    event_assign(&timeout, base, -1, flags, timeout_cb, (void*)&timeout);

    evutil_timerclear(&tv);
    tv.tv_sec = 2;
    event_add(&timeout, &tv);

    evutil_gettimeofday(&lasttime, NULL);

    event_base_dispatch(base);

    return (0);
}    
相關文章
相關標籤/搜索