生活随笔
收集整理的這篇文章主要介紹了
libevent简介和使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
libevent是一個基于事件觸發的網絡庫,memcached底層也是使用libevent庫,今天學習下。
總體來說,libevent有下面一些特點和優勢:
* 統一數據源, 統一I/O事件,信號和定時器這三種事件;
* 可移植,跨平臺支持多種I/O多路復用技術, epoll、poll、dev/poll、select 和kqueue 等;
* 對并發編程支持,避免競態條件;
* 高性能,由事件驅動;
* 輕量級,專注于網絡;
libevent有下面幾大部分組成:
*?事件管理包括各種IO(socket)、定時器、信號等事件,也是libevent應用最廣的模塊;
*?緩存管理是指evbuffer功能;
*?DNS是libevent提供的一個異步DNS查詢功能;
*?HTTP是libevent的一個輕量級http實現,包括服務器和客戶端
一些資料:
* libevent官網:http://libevent.org/?
* libevent API:http://www.monkey.org/~provos/libevent/doxygen-2.0.1/index.html
* CSDN上剖析得很贊的文章:http://blog.csdn.net/sparkliang/article/details/4957667
// =============================================================================================
下面寫了2個簡單的使用例子,一個是定時器,一個是TCP服務器,都只涉及到libevent的事件管理模塊。
一、簡單定時器:實現程序每秒輸出一個“Game Over!”
event_init() =>?evtimer_set() =>?event_add() =>event_dispatch()
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<iostream>?? ?? ?? #include?<event.h>?? using?namespace?std;?? ?? ?? void?onTime(int?sock,?short?event,?void?*arg)?? {?? ????cout?<<?"Game?Over!"?<<?endl;?? ?? ????struct?timeval?tv;?? ????tv.tv_sec?=?1;?? ????tv.tv_usec?=?0;?? ?????? ????event_add((struct?event*)arg,?&tv);?? }?? ?? int?main()?? {?? ?????? ????event_init();?? ?? ????struct?event?evTime;?? ?????? ????evtimer_set(&evTime,?onTime,?&evTime);?? ?? ????struct?timeval?tv;?? ????tv.tv_sec?=?1;?? ????tv.tv_usec?=?0;?? ?????? ????event_add(&evTime,?&tv);?? ?? ?????? ????event_dispatch();?? ?? ????return?0;?? }??
編譯并執行,編譯加 -levent:
[cpp]?view plaincopy
gapp_devnet_1:/data/home/andyawang/code/2013_11/LibeventTest?#?mv?time.cpp?timer.cpp?? gapp_devnet_1:/data/home/andyawang/code/2013_11/LibeventTest?#?g++?-o?timer?timer.cpp?-levent?? gapp_devnet_1:/data/home/andyawang/code/2013_11/LibeventTest?#?./timer??? Game?Over!?? Game?Over!?? Game?Over!?? Game?Over!??
二、TCP服務器:
實現監聽本機8888端口并輸出客戶端發送過來的信息
event_base_new()=>event_set()=>event_base_set()=>event_add()=>event_base_dispatch()
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<string.h>?? #include?<iostream>?? #include?<sys/socket.h>?????? #include?<netinet/in.h>?????? #include?<arpa/inet.h>?????? #include?<netdb.h>?? ?? #include?<event.h>?? using?namespace?std;?? ?? ?? struct?event_base*?base;?? ?? ?? void?onRead(int?iCliFd,?short?iEvent,?void?*arg)?? {?? ????int?iLen;?? ????char?buf[1500];?? ?? ????iLen?=?recv(iCliFd,?buf,?1500,?0);?? ?? ????if?(iLen?<=?0)?{?? ????????cout?<<?"Client?Close"?<<?endl;?? ?? ?????????? ????????struct?event?*pEvRead?=?(struct?event*)arg;?? ????????event_del(pEvRead);?? ????????delete?pEvRead;?? ?? ????????close(iCliFd);?? ????????return;?? ????}?? ?? ????buf[iLen]?=?0;?? ????cout?<<?"Client?Info:"?<<?buf?<<?endl;?? }?? ?? ?? void?onAccept(int?iSvrFd,?short?iEvent,?void?*arg)?? {?? ????int?iCliFd;?? ????struct?sockaddr_in?sCliAddr;?? ?? ????socklen_t?iSinSize?=?sizeof(sCliAddr);?? ????iCliFd?=?accept(iSvrFd,?(struct?sockaddr*)&sCliAddr,?&iSinSize);?? ?? ?????? ????struct?event?*pEvRead?=?new?event;?? ????event_set(pEvRead,?iCliFd,?EV_READ|EV_PERSIST,?onRead,?pEvRead);?? ????event_base_set(base,?pEvRead);?? ????event_add(pEvRead,?NULL);?? }?? ?? int?main()?? {?? ?? ????int?iSvrFd;???? ????struct?sockaddr_in?sSvrAddr;?? ???????????????? ????memset(&sSvrAddr,?0,?sizeof(sSvrAddr));???? ????sSvrAddr.sin_family?=?AF_INET;???? ????sSvrAddr.sin_addr.s_addr?=?inet_addr("127.0.0.1");?????? ????sSvrAddr.sin_port?=?htons(8888);????? ?????????????????????????????? ?????? ????iSvrFd?=?socket(AF_INET,?SOCK_STREAM,?0);???? ????bind(iSvrFd,?(struct?sockaddr*)&sSvrAddr,?sizeof(sSvrAddr));???? ????listen(iSvrFd,?10);?? ?? ?????? ????base?=?event_base_new();?? ?????? ????struct?event?evListen;?? ?????? ????event_set(&evListen,?iSvrFd,?EV_READ|EV_PERSIST,?onAccept,?NULL);?? ?????? ????event_base_set(base,?&evListen);?? ?????? ????event_add(&evListen,?NULL);?? ?????? ?????? ????event_base_dispatch(base);?? ?? ????return?0;?? } ?
三. HTTP服務器
? ?
C代碼??
#include?<stdio.h>?? #include?<stdlib.h>?? #include?<unistd.h>?? #include?<event.h>?? #include?<evhttp.h>?? ?? void?reqHandler(struct?evhttp_request?*req,void?*arg)?? {?? ????struct?evbuffer?*buf?=?evbuffer_new();?? ?????? ?????? ????evbuffer_add_printf(buf,?"Thanks?for?the?request");?? ????evhttp_send_reply(req,HTTP_OK,"Client",buf);?? ?????? ????evbuffer_free(buf);?? ?????? ????return;?? }?
void http_handle(struct evhttp_request* req, void* arg)
{
??? struct evbuffer* buffer = evbuffer_new();
??? // 獲取客戶端請求的URL
??? const char* url;
??? url = evhttp_request_uri(req);
??? evbuffer_add_printf(buffer, "url = %s\n", url);
??? // 解析url的參數(即GET方法的參數)
??? struct evkeyvalq params;
??? evhttp_parse_query(url, ¶ms);
??? evbuffer_add_printf(buffer, "a = %s\n", evhttp_find_header(¶ms, "a"));
??? evbuffer_add_printf(buffer, "b = %s\n", evhttp_find_header(¶ms, "b"));
??? // 設置HTTP表頭
??? evhttp_add_header(req->output_headers, "Server", "mytest http server 0.1");
??? evhttp_add_header(req->output_headers, "Content-Type", "text/plain;charset=UTF-8");
??? evhttp_add_header(req->output_headers, "Connection", "close");
??? // 返回數據
??? evhttp_send_reply(req, HTTP_OK, "OK", buffer);
??? evbuffer_free(buffer);
}
int?main(int?argc,char?**argv)?? {?? ????short?port?=?8000;?? ????const?char?*addr?=?"192.168.1.11";?? ????struct?evhttp?*httpserv?=?NULL;?? ?? ????event_init();?? ?????????? ????httpserv?=?evhttp_start(addr,port);?? ?? ?????? ????evhttp_set_gencb(httpserv,?reqHandler,NULL);?? ????printf("Server?started?on?port?%d\n",port);?? ?? ????event_dispatch();?? ?? ????return?0;?? }??
? ? 瀏覽器訪問:?http://192.168.1.11:8000?會顯示 Thanks for the request
#include?<stdio.h>?? #include?<stdlib.h>?? #include?<unistd.h>?? #include?<event.h>?? #include?<evhttp.h>?? ?? void?reqHandler(struct?evhttp_request?*req,void?*arg)?? {?? ????struct?evbuffer?*buf?=?evbuffer_new();?? ?????? ?????? ????evbuffer_add_printf(buf,?"Thanks?for?the?request");?? ????evhttp_send_reply(req,HTTP_OK,"Client",buf);?? ?????? ????evbuffer_free(buf);?? ?????? ????return;?? }?
void http_handle(struct evhttp_request* req, void* arg)
{
??? struct evbuffer* buffer = evbuffer_new();
??? // 獲取客戶端請求的URL
??? const char* url;
??? url = evhttp_request_uri(req);
??? evbuffer_add_printf(buffer, "url = %s\n", url);
??? // 解析url的參數(即GET方法的參數)
??? struct evkeyvalq params;
??? evhttp_parse_query(url, ¶ms);
??? evbuffer_add_printf(buffer, "a = %s\n", evhttp_find_header(¶ms, "a"));
??? evbuffer_add_printf(buffer, "b = %s\n", evhttp_find_header(¶ms, "b"));
??? // 設置HTTP表頭
??? evhttp_add_header(req->output_headers, "Server", "mytest http server 0.1");
??? evhttp_add_header(req->output_headers, "Content-Type", "text/plain;charset=UTF-8");
??? evhttp_add_header(req->output_headers, "Connection", "close");
??? // 返回數據
??? evhttp_send_reply(req, HTTP_OK, "OK", buffer);
??? evbuffer_free(buffer);
}
int?main(int?argc,char?**argv)?? {?? ????short?port?=?8000;?? ????const?char?*addr?=?"192.168.1.11";?? ????struct?evhttp?*httpserv?=?NULL;?? ?? ????event_init();?? ?????????? ????httpserv?=?evhttp_start(addr,port);?? ?? ?????? ????evhttp_set_gencb(httpserv,?reqHandler,NULL);?? ????printf("Server?started?on?port?%d\n",port);?? ?? ????event_dispatch();?? ?? ????return?0;?? }?
總結
以上是生活随笔為你收集整理的libevent简介和使用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。