libev事件庫

以Nginx爲表明,IO事件+定時器組成的事件驅動構成了如今高性能網絡處理的基礎,libev庫是繼​​libevent以後又一個事件庫,爲編寫事件驅動程序提供底層的封裝,相比libevent更加精簡,沒有附加額外的複雜功能。編程

下面是一個簡單的例子。網絡

#include<stdio.h>
#include<ev.h>

void timer_action(struct ev_loop *loop, ev_timer *w, int e)
{
    printf("Hello World!\n");
}

int main(int argc, char *argv[])
{
    struct ev_loop *loop = ev_default_loop(0);

    ev_timer    w;
    ev_timer_init(&w, timer_action, 5, 2);
    ev_timer_start(loop, &w);

    ev_run(loop, 0);

    return 0;
}

程序啓動時設置定時器,5秒後定時器啓動輸出「Hello World!」,以後每隔2秒輸出一次。框架

對每一個事件都要有一個結構體,儲存事件相關的信息,對於定時器事件,結構體爲ev_timer, 啓動一個定時器至關簡單函數

  1. 定義ev_timer結構體。
  2. 定時器設置,主要是回調函數,首次觸發時間和以後的出發間隔。
  3. 經過ev_timer_start將定時事件加入到事件循環中。
  4. 隨時能夠經過ev_timer_stop註銷事件。

下面的例子中,程序啓動1秒後輸出「Hello World!」,以後間隔每一個增長一秒,輸出4次後結束。oop

#include<stdio.h>
#include<ev.h>

int count = 0;
int timeout = 1;

void timer_action(struct ev_loop *loop, ev_timer *w, int e)
{
    printf("Hello World!\n");

    count += 1;
    if (count > 3) {
        ev_timer_stop(loop, w);
        return;
    }

    timeout += 1;
    ev_timer_stop(loop, w);
    ev_timer_set(w, timeout, 0);
    ev_timer_start(loop, w);

}

int main(int argc, char *argv[])
{
    struct ev_loop *loop = ev_default_loop(0);

    ev_timer    w;
    ev_timer_init(&w, timer_action, 1, 0);
    ev_timer_start(loop, &w);

    ev_run(loop, 0);

    return 0;
}

 

事件驅動框架中最重要的仍是IO事件的處理,相關的API與定時器事件相似,不過IO事件會區分讀和寫。下面是一個簡單的例子。性能

#include<stdio.h>
#include<ev.h>

ev_io   stdin_watcher;
char    buf[4096];

void io_action(struct ev_loop *loop, ev_io *w, int revents)
{   
    if (revents & EV_READ) {
        fgets(buf, 4096, stdin);

        ev_io_stop(loop, w);
        ev_io_set(w, 0, EV_WRITE);
        ev_io_start(loop, w);

    } else if (revents & EV_WRITE) {
        printf("Input:%s\n", buf);
        ev_io_stop(loop, w);

    }
    return;
}

int main(void)
{
    struct ev_loop *loop = ev_default_loop(0);

    ev_io_init(&stdin_watcher, io_action, /* STDIN_FILENO */ 0, EV_READ);
    ev_io_start(loop, &stdin_watcher);

    ev_run(loop, 0);
    
    return 0;
}

這是一個IO事件的例子,程序啓動後等待用戶輸入,對於可讀事件(revents & EV_READ),fgets獲取用戶輸入,對於可寫事件(revents & EV_WRITE),進行輸出。指針

這裏爲了簡單使用是終端的輸入輸出操做,實際編程中libev庫更多的是用來處理網絡IO事件。code

程序處理中,大多數IO事件都會設置超時機制,避免無限期等待下去,尤爲是網絡IO中,創建鏈接,讀取數據,發送數據都要設置超時時間以避免已經破壞的鏈接一直佔用系統資源。對這種狀況須要將定時器事件與IO事件結合起來。IO事件超時後執行定時器事件,將IO事件撤銷,一樣IO事件執行成功要將定時器事件撤銷。爲此須要一個結構體存放IO事件和定時器事件的信息。事件

在ev_io和ev_timer等全部事件的結構體中都有一個void指針,能夠存儲相應的數據。資源

以下面的例子,5秒後若是終端沒有接受到任何輸入就會註銷IO事件。

#include<stdio.h>
#include<ev.h>


struct io_timer_struct {
    ev_io       io;
    ev_timer    timer;
    char        buf[4096];
};


void io_action(struct ev_loop *loop, ev_io *w, int revents)
{
    struct io_timer_struct  *s = (struct io_timer_struct *)w->data;
    if (revents & EV_READ) {
        fgets(s->buf, 4096, stdin);

        ev_io_stop(loop, w);
        ev_io_set(w, 0, EV_WRITE);
        ev_io_start(loop, w);

    } else if (revents & EV_WRITE) {
        printf("Input:%s\n", s->buf);
        ev_io_stop(loop, w);
    }

    ev_timer_stop(loop, &s->timer);

    return;
}

void timer_action(struct ev_loop *loop, ev_timer *w, int revents)
{
    struct io_timer_struct *s = (struct io_timer_struct *)w->data;

    ev_io_stop(loop, &s->io);
    return;
}


int main(void)
{
    struct ev_loop *loop = ev_default_loop(0);

    struct io_timer_struct s;
    memset(&s, 0, sizeof(s));

    s.io.data = &s;
    ev_io_init(&s.io, io_action, 0, EV_READ);
    ev_io_start(loop, &s.io);

    s.timer.data = &s;
    ev_timer_init(&s.timer, timer_action, 5, 0);
    ev_timer_start(loop, &s.timer);

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