日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

libevent介绍

發(fā)布時(shí)間:2023/11/27 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libevent介绍 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

libevent是一款事件驅(qū)動(dòng)的網(wǎng)絡(luò)開(kāi)發(fā)包 由于采用 c 語(yǔ)言開(kāi)發(fā) 體積小巧,跨平臺(tái),速度極快。

通常我們?cè)诮⒎?wù)器的處理模型的時(shí)候,主要是下面集中模型;

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

???? 針對(duì)上面存在的問(wèn)題,通常采用的方法有: 以 Poll 的方式解決:當(dāng)一個(gè) Process 處理完一個(gè) Connection 后,不直接死掉,而繼續(xù)回到 accept() 的狀態(tài)繼續(xù)處理,但這樣會(huì)遇到 Memory-leak 的問(wèn)題,于是采用這種方式的人通常會(huì)再加上「處理過(guò) N 個(gè) Connection 后死掉,由 Parent Process 再 fork() 一只新的」。最有名的例子是 Apache 1.3服務(wù)器,大家可以參考其源代碼的實(shí)現(xiàn)。?hread-safe 的問(wèn)題可以尋找其他 Thread-safe Library 直接使用。Memory-leak 的問(wèn)題可以試著透過(guò) Garbage Collection Library 分析出來(lái)。Apache 2.0 的 Thread MPM 就是使用這個(gè)模式。
???? 然而,目前高效率的 Server 都偏好采用 Event-based,一方面是沒(méi)有 Create Process/Thread 所造成的 Overhead,另外一方面是不需要透過(guò) Shared Memory 或是 Mutex 在不同的 Process/Thread 之間交換資料。然而,Event-based 在實(shí)做上的幾個(gè)復(fù)雜的地方在于:
?select() 與 poll() 的效率過(guò)慢,造成每次要判斷「有哪些 Event 發(fā)生」這件事情的成本很高,這在 BSD 支援 kqueue()、Linux 支援 epoll()、Solaris 支援 /dev/poll 后就解決了,在Windows平臺(tái)上通過(guò)完成端口的方式解決了.但這兩組 Function 都不是 Standard,于是在不同的平臺(tái)上就必須再改一次。

對(duì)于非阻塞的IO模型,?因?yàn)?Nonblocking,所以在 write() 或是 send() 時(shí)滿(mǎn)了需要自己 Buffering。??因?yàn)?Nonblocking,所以不能使用 fgets() 或是其他類(lèi)似的 function,于是需要自己刻一個(gè) Nonblocking 的 fgets()。但是使用者所丟過(guò)來(lái)的資料又不能保證在一次 read() 或 recv() 就有一行,于是要自己做 Buffering。實(shí)際上這三件事情在 libevent 都有 Library 處理掉了.

?? libevent 是一個(gè)事件觸發(fā)的網(wǎng)絡(luò)庫(kù),適用于windows、linux、bsd等多種平臺(tái),內(nèi)部使用select、epoll、kqueue等系統(tǒng)調(diào)用管理事件機(jī) 制。著名的用于apache的php緩存庫(kù)memcached據(jù)說(shuō)也是libevent based,而且libevent在使用上可以做到跨平臺(tái),如果你將要開(kāi)發(fā)的應(yīng)用程序需要支持以上所列出的平臺(tái)中的兩個(gè)以上,那么強(qiáng)烈建議你采用這個(gè)庫(kù),即使你的應(yīng)用程序只需要支持一個(gè)平臺(tái),選擇libevent也是有好處的,因?yàn)樗梢愿鶕?jù)編譯/運(yùn)行環(huán)境切換底層的事件驅(qū)動(dòng)機(jī)制,這既能充分發(fā)揮系統(tǒng)的性能,又增加了軟件的可移植性。它封裝并且隔離了事件驅(qū)動(dòng)的底層機(jī)制,除了一般的文件描述符讀寫(xiě)操作外,它還提供有讀寫(xiě)超時(shí)、定時(shí)器和信號(hào)回調(diào),另外,它還允許為事件設(shè)定不同的優(yōu)先級(jí),當(dāng)前版本的libevent還提供dns和http協(xié)議的異步封裝,這一切都讓這個(gè)庫(kù)尤其適合于事件驅(qū)動(dòng)應(yīng)用程序的開(kāi)發(fā)。

???下面介紹libevent實(shí)現(xiàn)的框架

原文請(qǐng)參考: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庫(kù)的代碼結(jié)構(gòu)可以大概分成幾個(gè)模塊:
??? 事件處理框架
? ?事件引擎模塊
? ?Buffer管理模塊
?信號(hào)處理模塊

??1. 事件處理框架?
?
1.1 event_init() 初始化
? 首先要隆重介紹event_base對(duì)象:

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對(duì)象整合了事件處理的一些全局變量,? 角色是event對(duì)象的"總管家", 他包括了事件引擎函數(shù)對(duì)象(evsel, evbase), 當(dāng)前入列事件列表(event_count, event_count_active, eventqueue), 全局終止信號(hào)(event_gotterm), 活躍事件列表(avtivequeues), 事件隊(duì)列樹(shù)(timetree)...初始化時(shí)創(chuàng)建event_base對(duì)象,?選擇?當(dāng)前OS支持的事件引擎(epoll, poll, select...)并初始化, 創(chuàng)建全局信號(hào)隊(duì)列(signalqueue), 活躍隊(duì)列的內(nèi)存分配( 根據(jù)設(shè)置的priority個(gè)數(shù),默認(rèn)為1).
?1.2 event_set() 事件定義
??? event_set來(lái)設(shè)置event對(duì)象,包括所有者event_base對(duì)象, fd, 事件(EV_READ| EV_WRITE), 回掉函數(shù)和參數(shù),事件優(yōu)先級(jí)是當(dāng)前event_base的中間級(jí)別(current_base->nactivequeues/2). event對(duì)象的定義見(jiàn)下:

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)
?? 這個(gè)接口有兩個(gè)參數(shù), 第一個(gè)是要添加的事件, 第二個(gè)參數(shù)作為事件的超時(shí)值(timer). 如果該值非NULL, 在添加本事件的同時(shí)添加超時(shí)事件(EV_TIMEOUT)到時(shí)間隊(duì)列樹(shù)(timetree), 根據(jù)事件類(lèi)型處理如下:???
?? 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不是設(shè)置為EVLOOP_NONBLOCK, 該函數(shù)就會(huì)一直循環(huán)監(jiān)聽(tīng)事件/處理事件.
?? 每次循環(huán)過(guò)程中, 都會(huì)處理當(dāng)前觸發(fā)(活躍)事件:
?? (a). 檢測(cè)當(dāng)前是否有信號(hào)處理(gotterm, gotsig), 這些都是全局參數(shù),不適合多線(xiàn)程
?? (b). 時(shí)間更新,找到離當(dāng)前最近的時(shí)間事件, 得到相對(duì)超時(shí)事件tv
???(c). 調(diào)用事件引擎的dispatch wait事件觸發(fā), 超時(shí)值為tv, 觸發(fā)事件添加到activequeues
?? (d). 處理活躍事件, 調(diào)用caller的callbacks (event_process_acitve)
2. 事件引擎模塊 :
?
?? Linux下有多種I/O復(fù)用機(jī)制, .來(lái)處理多路事件監(jiān)聽(tīng), 常見(jiàn)的有epoll, poll, select, 按照優(yōu)先級(jí)排下來(lái)為:
?evport
?kqueue
?epoll
?devpoll
?rtsig
?poll
?select
?? 在event_init()選擇事件引擎時(shí),按照優(yōu)先級(jí)從上向下檢測(cè), 如果檢測(cè)成功,當(dāng)前引擎被選中.每個(gè)引擎需要定義幾個(gè)處理函數(shù),以epoll為例:

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

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

??? 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(), 添加信號(hào)事件, 關(guān)聯(lián)信號(hào)處理方法(sigaction)
?? 實(shí)際運(yùn)行過(guò)程中,如果某singal發(fā)生, 對(duì)應(yīng)的信號(hào)處理方法被調(diào)用, write a character to pipe
?? 同時(shí)pipe的另一端被激活, 添加信號(hào)到singalqueue, 在事件循環(huán)中evsignal_process處理信號(hào)callbacks.

libevent庫(kù)的具體使用方法

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

注:這段代碼來(lái)自于網(wǎng)絡(luò),雖然很粗糙,但是對(duì)libevent的使用方法已經(jīng)說(shuō)明的很清楚了.

附源碼:使用方法

?#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;
}

在寫(xiě) Nonblocking Network Program 通常要處理 Buffering 的問(wèn)題,但并不好寫(xiě),主要是因?yàn)?read() 或 recv() 不保證可以一次讀到一行的份量進(jìn)來(lái)。

在 libevent 里面提供相當(dāng)不錯(cuò)的 Buffer Library 可以用,完整的說(shuō)明在 man event 的時(shí)候可以看到,最常用的應(yīng)該就是以 evbuffer_add()、evbuffer_readline() 這兩個(gè) Function,其他的知道存在就可以了,需要的時(shí)候再去看詳細(xì)的用法。

下面直接提供 libevent-buff.c 當(dāng)作范例,編譯后看執(zhí)行結(jié)果,再回頭來(lái)看 source code 應(yīng)該就有感覺(jué)了:

#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() 表示進(jìn)入 event loop,當(dāng) Queue 里面的任何一個(gè) File Description 發(fā)生事件的時(shí)候就會(huì)進(jìn)入 callback function 執(zhí)行。

總結(jié)

以上是生活随笔為你收集整理的libevent介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲成av人片在线观看无码 | 精品人伦一区二区三 | 中文在线永久免费观看 | wwwww在线观看| 国产一区二区精品久久 | 日韩激情电影在线 | 成人91看片 | japanesexxxx日本妞 | 福利一二三区 | 日日日日操 | 一级片aaaaa| 久久极品 | 高清毛片aaaaaaaaa片 | 我我色综合 | 国产精品无码久久久久久电影 | 国产成人精品一区二区无码呦 | 伊人久久久久久久久 | 91免费视频黄 | 六月婷婷在线 | 在线视频观看你懂得 | 麻豆网站在线免费观看 | 欧洲亚洲激情 | 亚洲国产小视频 | 在线播放精品视频 | 久久免费小视频 | 日本视频免费 | 瑟瑟视频网站 | 99在线观看免费 | 日本精品一区二区 | 97国产精品视频人人做人人爱 | 国产成人精品视频 | 天堂中文字幕在线观看 | 六月婷婷综合网 | 国产午夜视频 | 国产伦精品免费视频 | 国产精品夜色一区二区三区 | 青娱网电信一区电信二区电信三区 | 国产精品久久久久久久久久久免费看 | 91麻豆蜜桃一区二区三区 | 无码毛片aaa在线 | av中文字幕一区二区 | 国产高清视频一区二区 | 老司机在线看片 | 操丰满女人| 99re在线视频免费观看 | 日日日日日日 | 日韩理论视频 | 69亚洲| 伊人资源 | 日本久操视频 | 精品久久久影院 | 亚洲欧洲色 | 日韩jizz| 久久久久久久久久久久国产精品 | 91搞搞| 欧美三级少妇高潮 | 久久青青视频 | 国产欧美激情在线观看 | 国产精品久久久久久白浆 | 夜夜骚av | 欧美性一级 | 口爆吞精一区二区三区 | 亚洲午夜精品在线 | av成人免费观看 | 日韩毛片中文字幕 | 秋霞一级视频 | 亚洲国产精品成人综合在线 | 制服.丝袜.亚洲.中文.综合懂 | 内射国产内射夫妻免费频道 | www.中文字幕在线观看 | 国产精品亲子伦对白 | 午夜性激情 | 波多野结衣在线视频免费观看 | 中文字幕高清一区 | 性做爰视频免费播放大全 | 91调教打屁股xxxx网站 | 自拍1区| 国产v亚洲v天堂无码 | 懂色aⅴ一区二区三区免费 国产精品99在线观看 | 夜间福利在线 | 国内精品偷拍 | 色欧美片视频在线观看 | 欧美一二区 | 男女国产视频 | 免费看成人aa片无码视频羞羞网 | 免费av一区二区三区 | 欧美伦理一区 | 天天搞天天 | 色xxxx | 日韩精品在线一区二区三区 | 久久久高清免费视频 | 精品一区二区久久久 | 亚洲色图一区二区三区 | 在线综合av| 99在线精品视频免费观看软件 | 激情午夜网| 在线观看av大片 | 丝袜福利视频 | 在线免费av网站 |