亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1857 | 回復: 0
打印 上一主題 下一主題

libevent跨平臺事件驅動庫簡介 [復制鏈接]

論壇徽章:
0
跳轉到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-10-24 22:54 |只看該作者 |倒序瀏覽

最近因為工作的原因,后臺服務器的壓力越來越大,需要對項目后臺的服務器進行重構,對已有的服務器的通訊模塊進行重構,增加其性能.
libevent產(chǎn)生的背景
通常我們在建立服務器的處理模型的時候,主要是下面集中模型;
(1)    a new Connection 進來,用 fork() 產(chǎn)生一個 Process 處理。
  (2)   a new Connection 進來,用 pthread_create() 產(chǎn)生一個 Thread 處理。
  (3)   a new Connection 進來,丟入 Event-based Array,由 Main Process 以 Nonblocking 的方式處理所有的 I/O。
這三種方法當然也都有各自的缺點:
用 fork() 的問題在于每一個 Connection 進來時的成本太高,如果同時接入的并發(fā)連接數(shù)太多容易進程數(shù)量很多,進程之間的切換開銷會很大,同時對于老的內核(Linux)會產(chǎn)生雪崩效應。
用 Multi-thread 的問題在于 Thread-safe 與 Deadlock 問題難以解決,另外有 Memory-leak 的問題要處理,這個問題對于很多程序員來說無異于惡夢,尤其是對于連續(xù)服務器的服務器程序更是不可以接受。 如果才用 Event-based 的方式在于實做上不好寫,尤其是要注意到事件產(chǎn)生時必須 Nonblocking,于是會需要實做 Buffering 的問題,而 Multi-thread 所會遇到的 Memory-leak 問題在這邊會更嚴重。而在多 CPU 的系統(tǒng)上沒有辦法使用到所有的 CPU resource。
     針對上面存在的問題,通常采用的方法有: 以 Poll 的方式解決:當一個 Process 處理完一個 Connection 后,不直接死掉,而繼續(xù)回到 accept() 的狀態(tài)繼續(xù)處理,但這樣會遇到 Memory-leak 的問題,于是采用這種方式的人通常會再加上「處理過 N 個 Connection 后死掉,由 Parent Process 再 fork() 一只新的」。最有名的例子是 Apache 1.3服務器,大家可以參考其源代碼的實現(xiàn)。 hread-safe 的問題可以尋找其他 Thread-safe Library 直接使用。Memory-leak 的問題可以試著透過 Garbage Collection Library 分析出來。Apache 2.0 的 Thread MPM 就是使用這個模式。
     然而,目前高效率的 Server 都偏好采用 Event-based,一方面是沒有 Create Process/Thread 所造成的 Overhead,另外一方面是不需要透過 Shared Memory 或是 Mutex 在不同的 Process/Thread 之間交換資料。然而,Event-based 在實做上的幾個復雜的地方在于:
select() 與 poll() 的效率過慢,造成每次要判斷「有哪些 Event 發(fā)生」這件事情的成本很高,這在 BSD 支援 kqueue()、Linux 支援 epoll()、Solaris 支援 /dev/poll 后就解決了,在Windows平臺上通過完成端口的方式解決了.但這兩組 Function 都不是 Standard,于是在不同的平臺上就必須再改一次。
對于非阻塞的IO模型, 因為 Nonblocking,所以在 write() 或是 send() 時滿了需要自己 Buffering。  因為 Nonblocking,所以不能使用 fgets() 或是其他類似的 function,于是需要自己刻一個 Nonblocking 的 fgets()。但是使用者所丟過來的資料又不能保證在一次 read() 或 recv() 就有一行,于是要自己做 Buffering。實際上這三件事情在 libevent 都有 Library 處理掉了.
   libevent 是一個事件觸發(fā)的網(wǎng)絡庫,適用于windows、linux、bsd等多種平臺,內部使用select、epoll、kqueue等系統(tǒng)調用管理事件機制。著名的用于apache的php緩存庫memcached據(jù)說也是libevent based,而且libevent在使用上可以做到跨平臺,如果你將要開發(fā)的應用程序需要支持以上所列出的平臺中的兩個以上,那么強烈建議你采用這個庫,即使你的應用程序只需要支持一個平臺,選擇libevent也是有好處的,因為它可以根據(jù)編譯/運行環(huán)境切換底層的事件驅動機制,這既能充分發(fā)揮系統(tǒng)的性能,又增加了軟件的可移植性。它封裝并且隔離了事件驅動的底層機制,除了一般的文件描述符讀寫操作外,它還提供有讀寫超時、定時器和信號回調,另外,它還允許為事件設定不同的優(yōu)先級,當前版本的libevent還提供dns和http協(xié)議的異步封裝,這一切都讓這個庫尤其適合于事件驅動應用程序的開發(fā)。
   下面介紹libevent實現(xiàn)的框架
原文請參考:libevent官方網(wǎng)址:   
http://www.monkey.org/~provos/libevent/

比較好的文檔:
http://unx.ca/log/category/libevent/

http://tb.blog.csdn.net/TrackBack.aspx?PostId=1808095
libenvent庫的代碼結構可以大概分成幾個模塊:
    事件處理框架
   事件引擎模塊
   Buffer管理模塊
信號處理模塊
  1. 事件處理框架

1.1 event_init() 初始化
  首先要隆重介紹event_base對象:
struct event_base {
    const struct eventop *evsel;
    void *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 */
        
    /* active event management */
    struct event_list **activequeues;
    int nactivequeues;
    struct event_list eventqueue;
    struct timeval event_tv;
    RB_HEAD(event_tree, event) timetree;
};
   event_base對象整合了事件處理的一些全局變量,  角色是event對象的"總管家", 他包括了事件引擎函數(shù)對象(evsel, evbase), 當前入列事件列表(event_count, event_count_active, eventqueue), 全局終止信號(event_gotterm), 活躍事件列表(avtivequeues), 事件隊列樹(timetree)...初始化時創(chuàng)建event_base對象, 選擇 當前OS支持的事件引擎(epoll, poll, select...)并初始化, 創(chuàng)建全局信號隊列(signalqueue), 活躍隊列的內存分配( 根據(jù)設置的priority個數(shù),默認為1).
1.2 event_set() 事件定義
    event_set來設置event對象,包括所有者event_base對象, fd, 事件(EV_READ| EV_WRITE), 回掉函數(shù)和參數(shù),事件優(yōu)先級是當前event_base的中間級別(current_base->nactivequeues/2). event對象的定義見下:
struct event {
    TAILQ_ENTRY (event) ev_next;
    TAILQ_ENTRY (event) ev_active_next;
    TAILQ_ENTRY (event) ev_signal_next;
    RB_ENTRY (event) ev_timeout_node;
    struct event_base *ev_base;
    int ev_fd;
    short ev_events;
    short ev_ncalls;
    short *ev_pncalls;  /* Allows deletes in callback */
    struct timeval ev_timeout;
    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;
};
1.3 event_add() 事件添加:
   int event_add(struct event *ev, struct timeval *tv)
   這個接口有兩個參數(shù), 第一個是要添加的事件, 第二個參數(shù)作為事件的超時值(timer). 如果該值非NULL, 在添加本事件的同時添加超時事件(EV_TIMEOUT)到時間隊列樹(timetree), 根據(jù)事件類型處理如下:   
   EV_READ  =>  EVLIST_INSERTED  => eventqueue
   EV_WRITE  =>  EVLIST_INSERTED  => eventqueue
   EV_TIMEOUT => EVLIST_TIMEOUT => timetree
  EV_SIGNAL  => EVLIST_SIGNAL => signalqueue
1.4 event_base_loop() 事件處理主循環(huán)
   這里是事件的主循環(huán),只要flags不是設置為EVLOOP_NONBLOCK, 該函數(shù)就會一直循環(huán)監(jiān)聽事件/處理事件.
   每次循環(huán)過程中, 都會處理當前觸發(fā)(活躍)事件:
   (a). 檢測當前是否有信號處理(gotterm, gotsig), 這些都是全局參數(shù),不適合多線程
   (b). 時間更新,找到離當前最近的時間事件, 得到相對超時事件tv
   (c). 調用事件引擎的dispatch wait事件觸發(fā), 超時值為tv, 觸發(fā)事件添加到activequeues
   (d). 處理活躍事件, 調用caller的callbacks (event_process_acitve)
2. 事件引擎模塊 :

   Linux下有多種I/O復用機制, .來處理多路事件監(jiān)聽, 常見的有epoll, poll, select, 按照優(yōu)先級排下來為:
evport
kqueue
epoll
devpoll
rtsig
poll
select
   在event_init()選擇事件引擎時,按照優(yōu)先級從上向下檢測, 如果檢測成功,當前引擎被選中.每個引擎需要定義幾個處理函數(shù),以epoll為例:
struct eventop epollops = {
    "epoll",
    epoll_init,
    epoll_add,
    epoll_del,
    epoll_recalc,
    epoll_dispatch,
    epoll_dealloc
};
3. Buffer管理模塊:

   libevent定義了自己的buffer管理機制evbuffer, 支持多種類型數(shù)據(jù)的read/write功能, 包括不定長字符串,buffer中內存采用預分配/按需分配結合的方式, 可以比較方便的管理多個數(shù)據(jù)結構映射到內存buffer.
   需要拉出來介紹的是evbuffer_expand()函數(shù), 當內部內存不夠時,需要expand, 這里采用預分配的方式,如果需要長度libevent庫的具體使用方法
   直接寫一個很簡單的 Time Server 來當作例子:當你連上去以后 Server 端直接提供時間,然后結束連線。event_init() 表示初始化 libevent 所使用到的變數(shù)。event_set(&ev, s, EV_READ | EV_PERSIST, connection_accept, &ev) 把 s 這個 File Description 放入 ev (第一個參數(shù)與第二個參數(shù)),并且告知當事件 (第三個參數(shù)的 EV_READ) 發(fā)生時要呼叫 connection_accept() (第四個參數(shù)),呼叫時要把 ev 當作參數(shù)丟進去 (第五個參數(shù))。其中的 EV_PERSIST 表示當呼叫進去的時候不要把這個 event 拿掉 (繼續(xù)保留在 Event Queue 里面),這點可以跟 connection_accept() 內在注冊 connection_time() 的代碼做比較。而 event_add(&ev, NULL) 就是把 ev 注冊到 event queue 里面,第二個參數(shù)指定的是 Timeout 時間,設定成 NULL 表示忽略這項設定。
注:這段代碼來自于網(wǎng)絡,雖然很粗糙,但是對libevent的使用方法已經(jīng)說明的很清楚了.
附源碼:使用方法
#include
#include
#include
#include
#include
#include
void connection_time(int fd, short event, struct event *arg)
{
    char buf[32];
    struct tm t;
    time_t now;
    time(&now);
    localtime_r(&now, &t);
    asctime_r(&t, buf);
    write(fd, buf, strlen(buf));
    shutdown(fd, SHUT_RDWR);
    free(arg);
}
void connection_accept(int fd, short event, void *arg)
{
    /* for debugging */
    fprintf(stderr, "%s(): fd = %d, event = %d.\n", __func__, fd, event);
    /* Accept a new connection. */
    struct sockaddr_in s_in;
    socklen_t len = sizeof(s_in);
    int ns = accept(fd, (struct sockaddr *) &s_in, &len);
    if (ns
#include
#include
void printbuf(struct evbuffer *evbuf)
{
    for (;;) {
        char *buf = evbuffer_readline(evbuf);
        printf("* buf = %p, the string = \"\e[1;33m%s\e[m\"\n", buf, buf);
        if (buf == NULL)
            break;
        free(buf);
    }
}
int main(void)
{
    struct evbuffer *evbuf;
    evbuf = evbuffer_new();
    if (evbuf == NULL) {
        fprintf(stderr, "%s(): evbuffer_new() failed.\n", __func__);
        exit(1);
    }
    /* Add "gslin" into buffer. */
    u_char *buf1 = "gslin";
    printf("* Add \"\e[1;33m%s\e[m\".\n", buf1);
    evbuffer_add(evbuf, buf1, strlen(buf1));
    printbuf(evbuf);
    u_char *buf2 = " is reading.\nAnd he is at home.\nLast.";
    printf("* Add \"\e[1;33m%s\e[m\".\n", buf2);
    evbuffer_add(evbuf, buf2, strlen(buf2));
    printbuf(evbuf);
    evbuffer_free(evbuf);
}
最后的 event_dispatch() 表示進入 event loop,當 Queue 里面的任何一個 File Description 發(fā)生事件的時候就會進入 callback function 執(zhí)行。


本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u1/59571/showart_2077664.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉載本站內容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP