Libevent 官方文檔學習筆記(2. bufferevent部分)

本文地址:http://www.javashuo.com/article/p-unzqmpqa-mk.htmlsegmentfault


Libevent的輔助函數和數據類型

頭文件是<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_toop

適配函數的宏性能

#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);

Socket相關的函數

#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)

Bufferevent:概念和基本知識

傳統的libevent使用方法:

  1. 當須要放數據的時候,存入數據到buffer
  2. 等待socket可寫
  3. 儘可能向socket中寫更多的data
  4. 若是還有data未寫入,則再等待socket可寫

使用頭文件<event2/bufferevent.h>可使用bufferevent,節省read/write調用,只須要將數據放入/取出一個buffer便可
  目前bufferevent只支持TCP,將來可能支持UDP
  每一個bufferevent有一個read buffer和一個write buffer,都是struct evbuffer。這個後文再講。

回調和bufferevent

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中被執行,單線程。

Bufferevent的選項

BEV_OPT_CLOSE_ON_FREE:當bufferevent釋放時,關閉底層傳輸
BEV_OPT_THREADSAFE:爲bufferevent使用lock
BEV_OPT_DEFER_CALLBACKS:將callback設爲延遲的
BEV_OPT_UNLOCK_CALLBACKS:默認狀況下若是有THREADSAFE標誌,調用callback時會加鎖。使用這個標誌是的即使有THREADSAFE標誌,調用callback也不加鎖

使用基於socket的bufferevent

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);

通用的bufferevent操做

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沒有做用。

類型特定的bufferevent函數

如下幾個函數的含義正如字面意思,就不特別說明了

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);

Bufferevents:高級主題

這裏講了不少bufferevent的高級功能。本文章只是列出其中會使用到的部分

限制每次read/write的長度

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秒。

Bufferevents 和 SSL

這裏實際上是一個很重要的內容,講的是如何在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部分)

相關文章
相關標籤/搜索