Linux中Libevent程式設計介紹

一隻青木呀發表於2020-10-24

Libevent開發

  • 依賴庫:基於Linux中libevent庫進行的事件響應
  • 基本介紹:
Libevent是一個基於事件觸發的網路庫 ,跨平臺的網路庫,使用了select epoll kqueue程式設計結構,擁有高效的處理效能 ,資料處理模組
  • 重點物件:
event_base 是event集合,儲存監聽的event 

struct event {
    TAILQ_ENTRY (event) ev_next;//用來連結IO時間
    TAILQ_ENTRY (event) ev_active_next;//用來連結就緒事件,實際插入對應的
    TAILQ_ENTRY (event) ev_signal_next;//用來連結訊號事件
    unsigned int min_heap_idx;  /* for managing timeouts事件在堆中的下標 */

    struct event_base *ev_base;

    int ev_fd;//對於I/O事件,是繫結的檔案描述符;對於signal事件,是繫結的訊號
    short ev_events;//event關注的事件型別
    /*
        包含三個事件:IO事件:EV_READ和EV_WRITE
                    訊號事件:EV_SIGNAL
                    定時器事件:EV_TIMEOUT    
    */
    short ev_ncalls;//事件就緒執行時,呼叫ev_callback的次數
    short *ev_pncalls;  /* Allows deletes in callback */

    struct timeval ev_timeout;//timout事件的超時值

    int ev_pri;     /* smaller numbers are higher priority 優先順序*/

    void (*ev_callback)(int, short, void *arg);//回撥函式
    void *ev_arg;//回撥函式的引數

    int ev_res;     /* result passed to event callback 傳遞給回撥函式 */
    int ev_flags;//表明事件當前處於何種狀態
    /*
        依據事件處於不同狀態將其加入不同的連結串列中。
    */
}

struct event_base {
    const struct eventop *evsel;//底層具體I/O demultiplex操作函式集
    void *evbase;//儲存IO複用返回的檔案描述符相關 evbase
    int event_count;        /* counts number of total events總的事件數量 */
    int event_count_active; /* counts number of active events 就緒事件數量*/

    int event_gotterm;      /* Set to terminate loop */
    int event_break;        /* Set to terminate loop immediately */

    /* active event management */
    struct event_list **activequeues;//指標陣列 ,就緒事件連結串列陣列,每個元素防止一個連結串列頭部
    int nactivequeues;//就緒事件佇列個數,指標陣列維度,也就是優先順序個數

    /* signal handling info */
    struct evsignal_info sig;//用於管理訊號

    struct event_list eventqueue;//註冊事件佇列
    struct timeval event_tv;

    struct min_heap timeheap;//管理定時器的小根堆

    struct timeval tv_cache;//記錄時間快取
}

    
  • 程式設計流程(物件導向的流程)
1. 建立物件 
struct event_base *event_base_new(void)
2. 銷燬物件
void event_base_free(struct event_base * base);
3. 獲取當前自動選擇的IO模型 
event_base_get_method 
4. 使用物件
基於事件迴圈的方法進行事件等待,event loop 
event_base_dispatch(struct *event_base * base)
在內部不斷迴圈監聽註冊上來的事件 返回0成功 
int event_base_loop(struct event_base*base ,flag);
1. EVLOOP_ONCE 0x01
  
引起迴圈退出的情況:
	1.event_base中沒有事件了 
	2.呼叫event_base_loopbreak 事件迴圈會停止 (立即停止)
	3.呼叫event_base_loopexit  (等待所有事件結束後停止)
	4. 程式錯誤 

特定頭+len 
固定長度包
特殊接收符包

關於libevent庫

Libevent 是一個輕量級的開源高效能網路庫,有幾個顯著的亮點:

  • 事件驅動(event-driven),高效能;
  • 輕量級,專注於網路,不如 ACE 那麼臃腫龐大;
  • 原始碼相當精煉、易讀;
  • 跨平臺,支援 Windows、 Linux、 *BSD 和 Mac Os;
  • 支援多種 I/O 多路複用技術, epoll、 poll、 dev/poll、 select 和 kqueue 等;
  • 支援 I/O,定時器和訊號等事件;
  • 註冊事件優先順序;

Libevent 已經被廣泛的應用,作為底層的網路庫;比如 memcached、Vomit、Nylon、Netchat等等。

關於libevent的安裝

下載安裝包

官網:http://www.monkey.org/~provos…
下載:http://www.monkey.org/~provos…

解壓

# tar zxvf libevent-2.0.10-stable.tar.gz

進入目錄

# cd libevent-2.0.10-stable

切換到root

# su

安裝gcc

# yum install gcc

設定安裝路徑
不加這句的話,預設安裝目錄在/usr/local/lib

# ./configure --prefix=/usr

編譯

# make

安裝

# make install

測試libevent是否安裝成功:

# ls -al /usr/lib | grep libevent

lrwxrwxrwx 1 root root 21 11?? 12 17:38 libevent-1.2.so.1 -> libevent-1.2.so.1.0.3
-rwxr-xr-x 1 root root 263546 11?? 12 17:38 libevent-1.2.so.1.0.3
-rw-r–r– 1 root root 454156 11?? 12 17:38 libevent.a
-rwxr-xr-x 1 root root 811 11?? 12 17:38 libevent.la
lrwxrwxrwx 1 root root 21 11?? 12 17:38 libevent.so -> libevent-1.2.so.1.0.3

$ wget http://monkey.org/~provos/libevent-1.4.14b-stable.tar.gz
$ tar xzf libevent-1.4.14b-stable.tar.gz
$ cd libevent-1.4.14b-stable
$ ./configure --prefix=/opt/libevent
# hopefully, you haven't encountered any errors so far
$ make
# make install
apt-get install libevent-dev 

gcc -g -o event_base event_base.c -levent

安裝問題

  1. 頻繁報了openssl問題

    • 首先先排查你究竟裝了libevent沒有,我在給朋友重新配置環境時候,怎麼都會報錯,該試的都試了,最後結果在/usr/local/lib/下面看到了一堆的libevent.so,這個真的是,太無語了。
      言歸正傳,如果你不是設定過./configure的話,預設安裝目錄在/usr/local/lib下面,裝前你先看一看嘛,又不吃虧,不行的話可以 find 一下嘛

    • 如果真的不行,那麼可能openssl的目錄不在系統的預設路徑置中,那麼可以加入一個軟連線

      # ln -sf /usr/local/ssl/include/openssl /usr/include/openssl
      
    • 如果還是有問題,那麼可能是你的openssl的版本太低,可以試試升級

      # yum update openssl -y
      

libevent的使用

第一個例子:

int main()
{
    int sockfd = create_socket();

    struct event_base * base = event_init();
    assert( base != NULL );

    struct event* ev_sock = event_new(base,sockfd,EV_READ|EV_PERSIST,accept_cb,(void*)base);
    assert( ev_sock != NULL );
    event_add(ev_sock,NULL);

    event_base_dispatch(base);
    event_free(ev_sock);
    event_base_free(base);
}

第二個例子:

int main()
{
    struct event_base *base = event_init();
    struct event *signal_event = evsignal_new(base,SIGINT,signal_cb,base);
    event_add(signal_event,NULL);

    struct timeval tv = {3,0};
    struct event *timeout_event = evtimer_new(base,timeout_cb,NULL);
    event_add(timeout_event,&tv);

    event_base_dispatch(base);

    event_free(timeout_event);
    event_free(signal_event);
    event_base_free(base);
}

這兩個簡單例子反映了event庫使用時的程式碼邏輯:

  1. 首先用event_init()來構建一個event_base物件

  2. 建立具體的事件event *用來表示具體事件,用evsignal_new,或者evtimer_new來註冊事件,兩個函式本質上來說都是對函式event_new()的封裝

    struct event* event_new(struct event_base *base, evutil_socket_t fd,
                            short event, void (*cb)(evutil_socket_t fd, 
                            short event, void *arg),void *arg);
    
    //short event所使用的巨集名
    #define EV_TIMEOUT 0x01 //定時時間
    #define EV_READ    0x01 //可讀時間
    #define EV_WRITE   0x01 //可寫時間
    #define EV_SIGNAL  0x01 //訊號時間
    #define EV_PERSIST 0x01 //永久時間
    #define EV_ET      0x20 //邊緣觸發,epoll下的ET模式
    
  3. 呼叫event_add()函式,將事件註冊到事件表中去

  4. 呼叫event_base_dispatch()執行事件迴圈

  5. 事件結束後,利用event_free()來釋放事件資源,利用event_base_free()來釋放event_free物件

    如果事件表中都是一次性事件,一次事件觸發後會結束事件從此不再監聽
    evtimer_new()預設的超時事件是一個一次性的事件,如果需要多次監聽,可以從event_new中進行詳細的設定
    event_new()中,訊號事件直接在fd處寫入訊號名稱,如果是超時事件,則用-1來表明

相關文章