本文地址:http://www.javashuo.com/article/p-unzqmpqa-mk.htmlsegmentfault
頭文件是<event2/util.h>
。如下只列出我本身會用到的部分。數據結構
evutil_socket_t
Socket的抽象。除了Windows以外,其餘系統都是一個int類型。若是考慮Windows的兼容性的話,建議用這個類型。異步
標準整型socket
如下是幾種數據長度的定義函數
---------------------------------------------------------- Type 位寬 符號數 最大值 最小值 ---------------------------------------------------------- ev_uint64_t 64 x EV_UINT64_MAX 0 ev_int64_t 64 √ EV_INT64_MAX EV_INT64_MIN ev_uint32_t 32 x EV_UINT32_MAX 0 ev_int32_t 32 √ EV_INT32_MAX EV_INT32_MIN ev_uint16_t 16 x EV_UINT16_MAX 0 ev_int16_t 16 √ EV_INT16_MAX EV_INT16_MIN ev_uint8_t 8 x EV_UINT8_MAX 0 ev_int8_t 8 √ EV_INT8_MAX EV_INT8_MIN
其餘一些類型ev_ssize_t
ev_off_t
oop
適配函數的宏性能
#define evutili_timer_add(tvp, uvp, vvp) #define evutili_timer_sub(tvp, uvp, vvp)
計算timeval數據加減的宏,vvp = tvp +/- uvp。注意三者都要使用指針學習
#define evutil_timerclear(tvp) #define evutil_timerisset(tvp)
將timeval清零,或者判斷是否被清零ui
#define evutil_timercmp(tvp, uvp, cmp)
判斷timeval的前後,其中cmp是比較富豪,好比==
, <=
, >=
, <
, >
, !=
線程
int evutil_gettimeofday (struct timeval *tv, struct timezone *tz);
#define evutil_socket_geterror (sock) #define evutil_socket_error_to_string (errcode)
得到指定socket的error code,以及轉爲可讀的string
int evutil_make_socket_nonblocking (evutil_sopcket_t sock);
將一個socket非阻塞。
ev_int64_t evutil_strtoll (const char *s, char **endptr, int base); int evutil_snprintf (char *but, size_t buflen, const char *format, ...); int evutil_vsnprintf (char *bug, size_t buflen, const char *format, va_list ap);
#define evutil_offsetof (type, field)
傳統的libevent使用方法:
使用頭文件<event2/bufferevent.h>
可使用bufferevent,節省read/write調用,只須要將數據放入/取出一個buffer便可
目前bufferevent只支持TCP,將來可能支持UDP
每一個bufferevent有一個read buffer和一個write buffer,都是struct evbuffer
。這個後文再講。
Bufferevent使用叫作watermarks
(水位線)的東西來定義回調函數的調用時機。有如下幾個watermarks:
Read low-water mark
:當read buffer的量大於等於這麼多時,調用callback。默認是0,即一有數據就回調。
Read high-water mark
:當read buffer的量大於等於這麼多時,中止read,直到buffer裏面的數據低於這個值爲止,從新開始read。默認是無限。
Write low-water mark
:當write buffer的量小於等於這麼多時,調用回調。默認是0
Write high-water mark
:bufferevent未直接使用這個值。參見後文
Bufferevent也有錯誤回調和事件回調,用於告知一些非數據時間和錯誤。以下:
BEV_EVENT_READING
BEV_EVENT_WRITING
BEV_EVENT_ERROR
:操做發生錯誤。須要調用EVUTIL_SOCKET_ERROR()
來判斷出現了什麼錯誤
BEV_EVENT_TIMEOUT
BEV_EVENT_EOF
BEV_EVENT_CONNECTED
:請求鏈接已經完成
延遲迴調
通常狀況下,bufferevent的callback時馬上調用的。可是若是調用關係很複雜的話可能會出bug,這個時候能夠將bufferevent設置爲延遲的(defered
),這樣會使得回調函數放在event loop中被執行,單線程。
BEV_OPT_CLOSE_ON_FREE
:當bufferevent釋放時,關閉底層傳輸BEV_OPT_THREADSAFE
:爲bufferevent使用lockBEV_OPT_DEFER_CALLBACKS
:將callback設爲延遲的BEV_OPT_UNLOCK_CALLBACKS
:默認狀況下若是有THREADSAFE標誌,調用callback時會加鎖。使用這個標誌是的即使有THREADSAFE標誌,調用callback也不加鎖
struct bufferevent *bufferevent_socket_new ( struct event_base *base, evutil_socket_t fd, enum bufferevent_options options);
這裏的fd能夠不指定,此時fd的參數是-1。若是指定了fd,這個fd必須是已經nonblock的。
int bufferevent_socket_connect (struct bufferevent *bev, struct sockaddr *address, int addrlen);
這是對connect()
的封裝。若是bev的fd是-1,那麼會自動調用socket()
,而且設置nonblock。,隨後再異步調用connect()
;若是fd已經指定了,那麼只是告訴bev去作connect()
操做。
正常狀況下,這會引發BEV_EVENT_CONNECTED
回調
int bufferevent_socket_connect_hostname ( struct bufferevent *bev, struct event_base *dns_base, int family, const char *hostname, int port);
這是connect()
封裝的另外一個版本,可是目標改成hostname。這會致使bufferevent自動去解析DNS。其中family
可選如下值:AF_INET
, AF_INET6
, AF_UNSPEC
。
dns_base參數可選。若是是NULL,那麼bufferevent會一直阻塞直到DNS解析完成——固然不推薦這麼作。若是帶了參數,則libevent會異步處理DNS請求。
剩下的工做與上面的connect封裝相同。
int bufferevent_socket_get_dns_error (struct bufferevent *bev);
void bufferevent_free (struct bufferevent *bev);
釋放bfferevent。若是callback是defered的,那麼bufferevent會等到callback返回以後才釋放。
若是指定了BEV_OPT_CLOSE_ON_FREE,那麼socket也會被close掉。
typedef void (*bufferevent_data_cb) (struct bufferevent *bev, void *ctx); typedef void (*bufferevent_event_cb) (struct bufferevent *bev, short events, void *ctx); void buffevent_setcb (struct buffevent *bufev, bufferevent_data_cb readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg); void bufferevent_get_cb (struct buffevent *bufev, bufferevent_data_cb *readcb_ptr, bufferevent_data_cb *writecb_ptr, bufferevent_event_cb *eventcb_ptr, void **cbarg_ptr);
設置。獲取bufferevent的callback。若是不想使用某個callback,則傳入NULL。
void bufferevent_enable (struct bufferevent *bufev, short events); void bufferevent_disable (struct bufferevent *bufev, short events); short bufferevent_getenabled (struct bufferevent *bufev);
使能/禁用指定的的callback。默認狀況下,剛初始化的bufferevent,write使能,而read禁止。
void bufferevent_setwatermark (struct buffevent *bev, short events, size_t lowmark, size_t highmark);
設置watermark。對於high-watermark,0表示無限。
struct evbuffer *bufferevent_get_input (struct bufferevent *bev); struct evbuffer *bufferevent_get_output(struct bufferevent *bev);
獲取到bufferevent中對應的read/write buffer。
int bufferevent_write (struct bufferevent *ev, const void *data, size_t size); int bufferevent_write_buffer (struct bufferevent *bev, struct evbuffer *buf);
函數一:直接向bufferevent附加數據
函數二:將evbuffer的所有內容附加到bufferevent中並晴空evbuffer
size_t bufferevent_read (struct bufferevent *bev, void *data, size_t size); int bufferevent_read_buffer (struct bufferevent *bev, struct evbuffer *buf);
函數一:直接從bufferevent中讀出數據,返回數據長度
函數二:將bufferevent中的所有數據抽取到evbuffer中
void bufferevent_set_timeouts (struct bufferevent *bev, const struct timeval *timeout_read, const struct timeval *timeout_write);
設置timeout,使得當一段時間沒有數據時,觸發回調函數。此時的實踐中會包含 BEV_EVENT_TIMEOUT
位
int bufferevent_flush (struct bufferevent *bufev, short iotype, enum bufferevent_flush_mode state);
強制讀/寫儘量多的數據。這個函數目前對socket沒有做用。
如下幾個函數的含義正如字面意思,就不特別說明了
int bufferevent_priority_set (struct bufferevent *bev, int pri); int bufferevent_get_priority (struct bufferevent *bev); int bufferevent_setfd (struct bufferevent *bev, evutil_socket_t fd); evutil_socket_t bufferevent_getfd (struct bufferevent *bev); struct event_base *bufferevent_get_base (struct bufferevent *bev); struct bufferevent *bufferevent_get_underlying (struct bufferevent *bev); void bufferevent_lock (struct bufferevent *bev); void buyfferevent_unlock(struct bufferevent *bev);
這裏講了不少bufferevent的高級功能。本文章只是列出其中會使用到的部分
int bufferevent_set_max_single_read (struct bufferevent *bev, size_t size); int bufferevent_set_max_single_write(struct bufferevent *bev, size_t size);
同時也有相對應的get函數
#define EV_RATE_LIMIT_MAX EV_SSIZE_MAX struct ev_token_bucket_cfg; struct ev_token_bucket_cfg *ev_token_bucket_cfg_new ( size_t read_rate, size_t read_burst, size_t write_rate, size_t write_burst, const struct timeval *tick_len); void ev_token_bucket_cfg_free (struct ev_token_bucket_cfg *cfg); int bufferevent_set_rate_limit (struct bufferevent *bev, struct ev_token_bucket_cfg *cfg);
其中ev_token_bucket_cfg_new()
的前四個函數的單位均爲bytes/tick
,而tick
的單位由tick_len
指定。若是tick_len
爲NULL,那麼默認爲1秒。
這裏實際上是一個很重要的內容,講的是如何在bufferevent中使用SSL。Libevent將SSL深度耦合了進來,使得你能夠很方便地使用bufferevent來完成SSL通訊。
呃,缺點就是libevent和OpenSSL的缺點的集合。其實對於嵌入式開發來講,由於CPU是分立的,因此性能上的缺點並不明顯,最大的問題是佔用磁盤空間啊!Libevent的庫自己就不小,加上OpenSSL更是超大。我弄懂libevent的時候,咱們的系統已經準備改用其餘的異步I/O和SSL庫,因此我也就不看了
另外吐槽一下:咱們這麼多年了仍是沒時間把libevent和OpenSSL徹底替換的工做作完,在這期間我本身都把libev、libuv、PolarSSL(mbedTLS)、cyaSSL看了……
Libevent官方文檔學習筆記(1. libevent_core部分)
Libevent官方文檔學習筆記(2. bufferevent部分)(本文)
Libevent官方文檔學習筆記(3. evbuffer部分)