青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

isware

[轉]libevent介紹

通常我們在建立服務器的處理模型的時候,主要是下面集中模型;

 (1)    a new Connection 進來,用 fork() 產生一個 Process 處理。 
  (2)   a new Connection 進來,用 pthread_create() 產生一個 Thread 處理。 
  (3)   a new Connection 進來,丟入 Event-based Array,由 Main Process 以 Nonblocking 的方式處理所有的 I/O。
這三種方法當然也都有各自的缺點:
 用 fork() 的問題在于每一個 Connection 進來時的成本太高,如果同時接入的并發連接數太多容易進程數量很多,進程之間的切換開銷會很大,同時對于老的內核(Linux)會產生雪崩效應。 
 用 Multi-thread 的問題在于 Thread-safe 與 Deadlock 問題難以解決,另外有 Memory-leak 的問題要處理,這個問題對于很多程序員來說無異于惡夢,尤其是對于連續服務器的服務器程序更是不可以接受。 如果才用 Event-based 的方式在于實做上不好寫,尤其是要注意到事件產生時必須 Nonblocking,于是會需要實做 Buffering 的問題,而 Multi-thread 所會遇到的 Memory-leak 問題在這邊會更嚴重。而在多 CPU 的系統上沒有辦法使用到所有的 CPU resource。 

     針對上面存在的問題,通常采用的方法有: 以 Poll 的方式解決:當一個 Process 處理完一個 Connection 后,不直接死掉,而繼續回到 accept() 的狀態繼續處理,但這樣會遇到 Memory-leak 的問題,于是采用這種方式的人通常會再加上「處理過 N 個 Connection 后死掉,由 Parent Process 再 fork() 一只新的」。最有名的例子是 Apache 1.3服務器,大家可以參考其源代碼的實現。 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 發生」這件事情的成本很高,這在 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 是一個事件觸發的網絡庫,適用于windows、linux、bsd等多種平臺,內部使用select、epoll、kqueue等系統調用管理事件機 制。著名的用于apache的php緩存庫memcached據說也是libevent based,而且libevent在使用上可以做到跨平臺,如果你將要開發的應用程序需要支持以上所列出的平臺中的兩個以上,那么強烈建議你采用這個庫, 即使你的應用程序只需要支持一個平臺,選擇libevent也是有好處的,因為它可以根據編譯/運行環境切換底層的事件驅動機制,這既能充分發揮系統的性 能,又增加了軟件的可移植性。它封裝并且隔離了事件驅動的底層機制,除了一般的文件描述符讀寫操作外,它還提供有讀寫超時、定時器和信號回調,另外,它還 允許為事件設定不同的優先級,當前版本的libevent還提供dns和http協議的異步封裝,這一切都讓這個庫尤其適合于事件驅動應用程序的開發。

   下面介紹libevent實現的框架

原文請參考:libevent官方網址:   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對象的"總管家", 他包括了事件引擎函數對象(evsel, evbase), 當前入列事件列表(event_count, event_count_active, eventqueue), 全局終止信號(event_gotterm), 活躍事件列表(avtivequeues), 事件隊列樹(timetree)...初始化時創建event_base對象, 選擇 當前OS支持的事件引擎(epoll, poll, select...)并初始化, 創建全局信號隊列(signalqueue), 活躍隊列的內存分配( 根據設置的priority個數,默認為1).
 1.2 event_set() 事件定義
    event_set來設置event對象,包括所有者event_base對象, fd, 事件(EV_READ| EV_WRITE), 回掉函數和參數,事件優先級是當前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)
   這個接口有兩個參數, 第一個是要添加的事件, 第二個參數作為事件的超時值(timer). 如果該值非NULL, 在添加本事件的同時添加超時事件(EV_TIMEOUT)到時間隊列樹(timetree), 根據事件類型處理如下:   
   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() 事件處理主循環 
   這里是事件的主循環,只要flags不是設置為EVLOOP_NONBLOCK, 該函數就會一直循環監聽事件/處理事件.
   每次循環過程中, 都會處理當前觸發(活躍)事件:
   (a). 檢測當前是否有信號處理(gotterm, gotsig), 這些都是全局參數,不適合多線程
   (b). 時間更新,找到離當前最近的時間事件, 得到相對超時事件tv
   (c). 調用事件引擎的dispatch wait事件觸發, 超時值為tv, 觸發事件添加到activequeues
   (d). 處理活躍事件, 調用caller的callbacks (event_process_acitve)
2. 事件引擎模塊 :
 
   Linux下有多種I/O復用機制, .來處理多路事件監聽, 常見的有epoll, poll, select, 按照優先級排下來為:
 evport
 kqueue
 epoll
 devpoll
 rtsig
 poll
 select
   在event_init()選擇事件引擎時,按照優先級從上向下檢測, 如果檢測成功,當前引擎被選中.每個引擎需要定義幾個處理函數,以epoll為例:

struct eventop epollops = {
    "epoll",
    epoll_init,
    epoll_add,
    epoll_del,
    epoll_recalc,
    epoll_dispatch,
    epoll_dealloc
};

3. Buffer管理模塊: 
 
   libevent定義了自己的buffer管理機制evbuffer, 支持多種類型數據的read/write功能, 包括不定長字符串,buffer中內存采用預分配/按需分配結合的方式, 可以比較方便的管理多個數據結構映射到內存buffer.
   需要拉出來介紹的是evbuffer_expand()函數, 當內部內存不夠時,需要expand, 這里采用預分配的方式,如果需要長度<256字節,預分配256字節, 同時內存成倍增長,一直到大于需要的長度.
4.  信號處理模塊
 
   信號處理單獨提出來,主要是libevent的信號處理比較輕巧, 從而很好融合到event機制.
   singal模塊初始化(evsignal_init)時, 創建了UNIX域socket ( pipe)作為內部消息傳遞橋梁:

    if (socketpair(AF_UNIX, SOCK_STREAM, 0, ev_signal_pair) == -1)
        event_err(1, "%s: socketpair", __func__);
    FD_CLOSEONEXEC(ev_signal_pair[0]);
    FD_CLOSEONEXEC(ev_signal_pair[1]);
    fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK);
    event_set(&ev_signal, ev_signal_pair[1], EV_READ,
        evsignal_cb, &ev_signal);
    ev_signal.ev_flags |= EVLIST_INTERNAL;

   evsignal_add(), 添加信號事件, 關聯信號處理方法(sigaction)
   實際運行過程中,如果某singal發生, 對應的信號處理方法被調用, write a character to pipe
   同時pipe的另一端被激活, 添加信號到singalqueue, 在事件循環中evsignal_process處理信號callbacks.

libevent庫的具體使用方法

   直接寫一個很簡單的 Time Server 來當作例子:當你連上去以后 Server 端直接提供時間,然后結束連線。event_init() 表示初始化 libevent 所使用到的變數。event_set(&ev, s, EV_READ | EV_PERSIST, connection_accept, &ev) 把 s 這個 File Description 放入 ev (第一個參數與第二個參數),并且告知當事件 (第三個參數的 EV_READ) 發生時要呼叫 connection_accept() (第四個參數),呼叫時要把 ev 當作參數丟進去 (第五個參數)。其中的 EV_PERSIST 表示當呼叫進去的時候不要把這個 event 拿掉 (繼續保留在 Event Queue 里面),這點可以跟 connection_accept() 內在注冊 connection_time() 的代碼做比較。而 event_add(&ev, NULL) 就是把 ev 注冊到 event queue 里面,第二個參數指定的是 Timeout 時間,設定成 NULL 表示忽略這項設定。

注:這段代碼來自于網絡,雖然很粗糙,但是對libevent的使用方法已經說明的很清楚了.

附源碼:使用方法

 #include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <event.h>
#include <stdio.h>
#include <time.h>

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 < 0) {
        perror("accept");
        return;
    }

    /* Install time server. */
    struct event *ev = malloc(sizeof(struct event));
    event_set(ev, ns, EV_WRITE, (void *) connection_time, ev);
    event_add(ev, NULL);
}

int main(void)
{
    /* Request socket. */
    int s = socket(PF_INET, SOCK_STREAM, 0);
    if (s < 0) {
        perror("socket");
        exit(1);
    }

    /* bind() */
    struct sockaddr_in s_in;
    bzero(&s_in, sizeof(s_in));
    s_in.sin_family = AF_INET;
    s_in.sin_port = htons(7000);
    s_in.sin_addr.s_addr = INADDR_ANY;
    if (bind(s, (struct sockaddr *) &s_in, sizeof(s_in)) < 0) {
        perror("bind");
        exit(1);
    }

    /* listen() */
    if (listen(s, 5) < 0) {
        perror("listen");
        exit(1);
    }

    /* Initial libevent. */
    event_init();

    /* Create event. */
    struct event ev;
    event_set(&ev, s, EV_READ | EV_PERSIST, connection_accept, &ev);

    /* Add event. */
    event_add(&ev, NULL);

    event_dispatch();

    return 0;
}

在寫 Nonblocking Network Program 通常要處理 Buffering 的問題,但并不好寫,主要是因為 read() 或 recv() 不保證可以一次讀到一行的份量進來。

在 libevent 里面提供相當不錯的 Buffer Library 可以用,完整的說明在 man event 的時候可以看到,最常用的應該就是以 evbuffer_add()、evbuffer_readline() 這兩個 Function,其他的知道存在就可以了,需要的時候再去看詳細的用法。

下面直接提供 libevent-buff.c 當作范例,編譯后看執行結果,再回頭來看 source code 應該就有感覺了:

#include <sys/time.h>
#include <event.h>
#include <stdio.h>

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 發生事件的時候就會進入 callback function 執行。

posted on 2011-07-19 15:07 艾斯維亞 閱讀(690) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久精品国产精品亚洲综合| 国产在线播精品第三| 欧美另类久久久品| 亚洲理伦在线| 亚洲女人av| 国内成+人亚洲| 男人天堂欧美日韩| 香蕉免费一区二区三区在线观看| 久久一日本道色综合久久| 亚洲视频在线二区| 久久一区国产| 欧美 日韩 国产一区二区在线视频| 香蕉亚洲视频| 久久aⅴ国产紧身牛仔裤| 久久精品盗摄| 亚洲第一精品夜夜躁人人爽| 欧美成人免费大片| 亚洲精品日韩在线观看| 亚洲精品一区久久久久久| 亚洲一品av免费观看| 久久riav二区三区| 欧美韩日一区| 国产精品夜夜夜| 亚洲国产精品黑人久久久| 一本一本久久| 久久久噜噜噜久久人人看| 亚洲福利视频网站| 久久久福利视频| 亚洲国产天堂久久综合网| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 欧美精品在线一区二区三区| 欧美日韩国产色视频| 国产精品永久免费在线| 亚洲国产精品va在线观看黑人| 亚洲视频观看| 欧美xxx成人| 亚洲欧美激情四射在线日 | 久久一区精品| 欧美一区二区三区四区高清| 久久国产视频网站| 亚洲激情一区| 国产日韩欧美综合精品| 欲香欲色天天天综合和网| 亚洲视频免费| 欧美怡红院视频| 亚洲无线一线二线三线区别av| 久久国产福利国产秒拍| 欧美激情a∨在线视频播放| 国产精品亚洲综合色区韩国| 亚洲第一在线综合在线| 欧美一区二区三区四区在线观看| 欧美成人中文| 欧美中文字幕视频在线观看| 欧美视频三区在线播放| 亚洲人成毛片在线播放| 久久国内精品自在自线400部| 亚洲国产欧美久久| 久久精品二区| 国产精品自拍小视频| 99视频+国产日韩欧美| 欧美国产日韩一区| 久久天堂精品| 亚洲第一在线| 午夜亚洲影视| 亚洲一区在线视频| 国产精品久久一区二区三区| 亚洲无人区一区| 一区二区三区精品视频在线观看| 欧美人与禽性xxxxx杂性| 亚洲精品午夜精品| 亚洲精品日产精品乱码不卡| 欧美成人四级电影| 国产日产欧美a一级在线| 亚洲尤物精选| 亚洲欧美日韩另类精品一区二区三区| 欧美亚一区二区| 欧美一区二区免费观在线| 亚洲欧美第一页| 国产午夜精品在线| 美日韩免费视频| 欧美大片免费| 亚洲一区999| 午夜精品久久久久久久久| 欧美激情视频在线播放| 夜夜嗨av一区二区三区四区| 亚洲免费播放| 国产日韩亚洲欧美| 欧美大片专区| 欧美三日本三级少妇三99| 欧美一区二区三区视频在线观看 | 亚洲精品欧美激情| 欧美视频在线观看一区二区| 性久久久久久久久久久久| 欧美一区二区在线免费观看| 亚洲第一区在线观看| 亚洲国产成人久久| 亚洲理伦电影| 国产一级一区二区| 亚洲国产成人精品久久| 欧美日韩亚洲一区二区三区在线观看| 亚洲欧美日韩综合国产aⅴ| 欧美尤物一区| 夜夜精品视频| 久久精品国产亚洲一区二区| 亚洲精品视频在线观看网站| 亚洲视频香蕉人妖| 亚洲二区在线观看| 久久高清免费观看| 欧美经典一区二区| 欧美在线播放视频| 欧美人交a欧美精品| 欧美主播一区二区三区| 猛男gaygay欧美视频| 午夜精品亚洲| 欧美精品激情| 蜜桃久久精品一区二区| 国产精品美女久久久久久久| 欧美福利视频在线观看| 国产美女精品视频| 亚洲三级网站| 亚洲国产另类精品专区| 亚洲欧美综合精品久久成人| 99在线观看免费视频精品观看| 欧美中文字幕在线观看| 亚洲综合欧美日韩| 欧美精品二区| 欧美国产亚洲精品久久久8v| 国产日韩综合一区二区性色av| 亚洲精品1区2区| 亚洲国产精品va在线看黑人动漫| 亚洲一区二区欧美日韩| 中日韩高清电影网| 欧美日韩dvd在线观看| 亚洲大胆人体视频| 伊人久久久大香线蕉综合直播| 亚洲欧美激情在线视频| 亚洲一区二区四区| 亚洲欧美色婷婷| 欧美一级一区| 国产精品久久久久毛片软件| 亚洲精品一二区| 一本色道久久加勒比88综合| 欧美国产1区2区| 欧美激情视频在线免费观看 欧美视频免费一| 国产欧美日韩91| 午夜精品一区二区三区在线视| 午夜精品久久久久久99热| 国产精品久久久久久妇女6080| 亚洲午夜黄色| 香港久久久电影| 国产欧美日韩另类视频免费观看| 亚洲色诱最新| 久久激情中文| 亚洲国内欧美| 欧美女同视频| 亚洲一区二区三区影院| 欧美一级视频| 永久久久久久| 欧美国产日韩精品免费观看| 亚洲精华国产欧美| 亚洲视频久久| 国产精品国产三级国产aⅴ无密码 国产精品国产三级国产aⅴ入口 | 亚洲综合好骚| 亚洲主播在线| 欧美色道久久88综合亚洲精品| 一二美女精品欧洲| 亚洲天堂男人| 国产精品久久久久99| 欧美福利在线观看| 99视频在线精品国自产拍免费观看 | 国产亚洲精品自拍| 久久天天狠狠| 欧美激情亚洲视频| 亚洲精品久久久久久久久久久| 美日韩精品免费观看视频| 亚洲精品视频免费观看| 亚洲免费福利视频| 欧美日韩三区四区| 亚洲一区二区免费看| 欧美成人一品| 一区二区三区视频在线| 国产农村妇女精品一区二区| 欧美一区二区三区视频在线| 国产人成精品一区二区三| 性色av一区二区三区红粉影视| 久久久久久久国产| 亚洲国内精品在线| 女女同性精品视频| 亚洲免费观看| 久久久久久久国产| 国产精品久99| 欧美一二区视频| 欧美国产日韩一区二区三区| 99国产精品国产精品久久| 国产精品久久久久久超碰| 久久大逼视频| 亚洲美女视频网| 亚洲盗摄视频| 久久成人18免费观看| 国自产拍偷拍福利精品免费一|