黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

Libevent(4)— Bufferevent

系統(tǒng) 2966 0

轉(zhuǎn)自:http://name5566.com/4215.html

?

參考文獻(xiàn)列表:
http://www.wangafu.net/~nickm/libevent-book/

此文編寫的時候,使用到的 Libevent 為 2.0.21

Buffer IO 模式

bufferevent 提供給我們一種 Buffer IO 模式(這里以寫入數(shù)據(jù)為例):

  1. 在我們需要通過某個連接發(fā)送數(shù)據(jù)的時候,先將等待發(fā)送的數(shù)據(jù)放入到一個 buffer 中
  2. 等待此連接可以寫入數(shù)據(jù)
  3. 盡可能多的獲取 buffer 中的數(shù)據(jù)寫入此連接
  4. 如果 buffer 中還有需要寫入的數(shù)據(jù)則繼續(xù)等待直到此連接可以寫入數(shù)據(jù)

每一個 bufferevent 都包含了一個輸入 buffer 和一個輸出 buffer,它們的類型為 evbuffer(結(jié)構(gòu)體)。當(dāng)我們向 bufferevent 寫入數(shù)據(jù)的時候,實(shí)際上數(shù)據(jù)首先被寫入到了輸出 buffer,當(dāng) bufferevent 有數(shù)據(jù)可讀時,我們實(shí)際上是從輸入 buffer 中獲取數(shù)據(jù)。

目前 bufferevent 目前僅僅支持 stream-oriented 的協(xié)議(例如 TCP)并不支持 datagram-oriented 協(xié)議(例如 UDP)。一個 bufferevent 的實(shí)例負(fù)責(zé)一個特定的連接上的數(shù)據(jù)收發(fā)。

Libevent 可以按需要創(chuàng)建多種類型的 bufferevent:

  1. 基于 socket 的 bufferevent。此類型的 bufferevent 使用 socket 來進(jìn)行數(shù)據(jù)的收發(fā),使用 event 機(jī)制來判斷 socket 是否可以進(jìn)行讀寫操作
  2. 異步 IO bufferevent。此類型的 bufferevent 使用 IOCP 接口實(shí)現(xiàn)(僅 Windows 下可用且目前處于實(shí)驗(yàn)階段)
  3. Filtering bufferevent。此類型的 bufferevent 可以在同底層交互時完成一些額外的數(shù)據(jù)處理工作,例如可以完成數(shù)據(jù)的壓縮和解析工作。這種類型的 bufferevent 的一個實(shí)例會封裝了另外的一個 bufferevent,我們把這個被封裝的 bufferevent 叫做底層 bufferevent
  4. Paired bufferevent。本文不談

bufferevent 的回調(diào)函數(shù)

每個 bufferevent 實(shí)例可以有 3 個回調(diào)函數(shù)(通過接口 bufferevent_setcb 設(shè)置):

  1. 讀取回調(diào)函數(shù)。默認(rèn)情況下,只要從底層讀取到了數(shù)據(jù)此回調(diào)函數(shù)將被調(diào)用
  2. 寫入回調(diào)函數(shù)。默認(rèn)情況下,足夠多的數(shù)據(jù)被寫入底層此回調(diào)函數(shù)將被調(diào)用
  3. 事件回調(diào)函數(shù)。當(dāng)某些事件(錯誤)發(fā)生時被調(diào)用

對于 buffer 的讀、寫和回調(diào)行為可以通過幾個參數(shù)來配置,這幾個參數(shù)在 Libevent 中被叫做 watermark(水位標(biāo)記,我們可以將 buffer 想象為一個水池,水位標(biāo)記用于標(biāo)記水池中水的多少,也就是說,watermark 用于標(biāo)記 buffer 中的數(shù)據(jù)量)。watermark 被實(shí)現(xiàn)為整數(shù)(類型為 size_t),有幾種類型的 watermark:

  1. Read low-water mark 用于控制讀取回調(diào)函數(shù)的行為。當(dāng) bufferevent 進(jìn)行讀取操作時,Read low-water mark 的值決定了輸入 buffer 有多少數(shù)據(jù)后調(diào)用讀取回調(diào)函數(shù)。默認(rèn)的情況下,此值為 0,因此 bufferevent 讀取操作都會導(dǎo)致讀取回調(diào)函數(shù)被調(diào)用
  2. Read high-water mark 用于控制輸入 buffer 的大小。如果輸入 buffer 中的數(shù)據(jù)量達(dá)到 Read high-water mark 的值,那么 bufferevent 將停止讀取。默認(rèn)的情況下,此值為無限大
  3. Write low-water mark,用于控制寫入回調(diào)函數(shù)的行為。當(dāng) bufferevent 進(jìn)行寫入操作時,Write low-water mark 的值決定了輸出 buffer 有多少數(shù)據(jù)后調(diào)用寫入回調(diào)函數(shù)。默認(rèn)的情況下,此值為 0,因此寫入回調(diào)函數(shù)會在輸出 buffer 為空的時候被調(diào)用
  4. Write high-water mark,此值在使用 Filtering bufferevent 有特殊的用途

在一些特殊需求中(詳細(xì)并不討論),我們可能需要回調(diào)函數(shù)被延時執(zhí)行(這種被延時的回調(diào)函數(shù)被叫做 Deferred callbacks)。延時回調(diào)函數(shù)會在事件循環(huán)中排隊,并在普通事件回調(diào)函數(shù)(regular event’s callback)之后被調(diào)用。

從基于 socket 的 bufferevent 開始認(rèn)識 bufferevent

創(chuàng)建基于 socket 的 bufferevent:

  1. // 創(chuàng)建一個基于 socket 的 bufferevent
  2. // 函數(shù)執(zhí)行失敗返回 NULL
  3. struct bufferevent * bufferevent_socket_new (
  4. struct event_base * base ,
  5. // socket 文件描述符
  6. // 此 socket 必須被設(shè)置為非阻塞的
  7. // 可以設(shè)置為 -1 表示之后再設(shè)置
  8. evutil_socket_t fd ,
  9. // bufferevent 的選項
  10. enum bufferevent_options options );

buffervent 的選項可以用來改變 bufferevent 的行為??捎玫倪x項包括:

  1. BEV_OPT_CLOSE_ON_FREE
    當(dāng) bufferevent 被釋放同時關(guān)閉底層(socket 被關(guān)閉等)
  2. BEV_OPT_THREADSAFE
    為 bufferevent 自動分配鎖,這樣能夠在多線程環(huán)境中安全使用
  3. BEV_OPT_DEFER_CALLBACKS
    當(dāng)設(shè)置了此標(biāo)志,bufferevent 會延遲它的所有回調(diào)(參考前面說的延時回調(diào))
  4. BEV_OPT_UNLOCK_CALLBACKS
    如果 bufferevent 被設(shè)置為線程安全的,用戶提供的回調(diào)被調(diào)用時 bufferevent 的鎖會被持有
    如果設(shè)置了此選項,Libevent 將在調(diào)用你的回調(diào)時釋放 bufferevent 的鎖

建立連接:

  1. // address 和 addrlen 和標(biāo)準(zhǔn)的 connect 函數(shù)的參數(shù)沒有區(qū)別
  2. // 如果 bufferevent bev 沒有設(shè)置 socket(在創(chuàng)建時可以設(shè)置 socket)
  3. // 那么調(diào)用此函數(shù)將分配一個新的 socket 給 bev
  4. // 連接成功返回 0 失敗返回 -1
  5. int bufferevent_socket_connect ( struct bufferevent * bev ,
  6. struct sockaddr * address , int addrlen );

簡單的一個范例:

  1. #include <event2/event.h>
  2. #include <event2/bufferevent.h>
  3. #include <sys/socket.h>
  4. #include <string.h>
  5. ?
  6. // 事件回調(diào)函數(shù)
  7. void eventcb ( struct bufferevent * bev , short events , void * ptr )
  8. {
  9. // 連接成功建立
  10. if ( events & BEV_EVENT_CONNECTED ) {
  11. /* We're connected to 127.0.0.1:8080. Ordinarily we'd do
  12. something here, like start reading or writing. */
  13. // 出現(xiàn)錯誤
  14. } else if ( events & BEV_EVENT_ERROR ) {
  15. /* An error occured while connecting. */
  16. }
  17. }
  18. ?
  19. int main_loop ( void )
  20. {
  21. struct event_base * base ;
  22. struct bufferevent * bev ;
  23. struct sockaddr_in sin ;
  24. ?
  25. base = event_base_new ();
  26. ?
  27. // 初始化連接地址
  28. memset (& sin , 0 , sizeof ( sin ));
  29. sin . sin_family = AF_INET ;
  30. sin . sin_addr . s_addr = htonl ( 0x7f000001 ); /* 127.0.0.1 */
  31. sin . sin_port = htons ( 8080 ); /* Port 8080 */
  32. ?
  33. // 創(chuàng)建一個基于 socket 的 bufferevent
  34. // 參數(shù) -1 表示并不為此 bufferevent 設(shè)置 socket
  35. bev = bufferevent_socket_new ( base , - 1 , BEV_OPT_CLOSE_ON_FREE );
  36. ?
  37. // 為 bufferevent bev 設(shè)置回調(diào)函數(shù)
  38. // 這里僅僅設(shè)置了事件回調(diào)函數(shù)
  39. // 后面會詳細(xì)談及此函數(shù)
  40. bufferevent_setcb ( bev , NULL , NULL , eventcb , NULL );
  41. ?
  42. // 進(jìn)行連接
  43. if ( bufferevent_socket_connect ( bev ,
  44. ( struct sockaddr *)& sin , sizeof ( sin )) < 0 ) {
  45. /* Error starting connection */
  46. bufferevent_free ( bev );
  47. return - 1 ;
  48. }
  49. ?
  50. // 開始事件循環(huán)
  51. event_base_dispatch ( base );
  52. return 0 ;
  53. }

更多的 bufferevent API

釋放 bufferevent

  1. // 如果存在未完成的延時回調(diào),bufferevent 會在回調(diào)完成后才被真正釋放
  2. void bufferevent_free ( struct bufferevent * bev );

bufferevent 回調(diào)函數(shù)的設(shè)置和獲取

  1. // 讀取、寫入回調(diào)函數(shù)原型
  2. // ctx 為用戶自定義數(shù)據(jù)(由 bufferevent_setcb 設(shè)定)
  3. typedef void (* bufferevent_data_cb )( struct bufferevent * bev , void * ctx );
  4. ?
  5. // 事件回調(diào)函數(shù)原型
  6. // ctx 為用戶自定義數(shù)據(jù)(由 bufferevent_setcb 設(shè)定)
  7. // events 選項可以為:
  8. // BEV_EVENT_READING --- 在 bufferevent 上進(jìn)行讀取操作時出現(xiàn)了一個事件
  9. // BEV_EVENT_WRITING --- 在 bufferevent 上進(jìn)行寫入操作時出現(xiàn)了一個事件
  10. // BEV_EVENT_ERROR --- 進(jìn)行 bufferevent 操作時(例如調(diào)用 bufferevent API)出錯,獲取詳細(xì)的錯誤信息使用 EVUTIL_SOCKET_ERROR()
  11. // BEV_EVENT_TIMEOUT --- 在 bufferevent 上出現(xiàn)了超時
  12. // BEV_EVENT_EOF --- 在 bufferevent 上遇到了文件結(jié)束符
  13. // BEV_EVENT_CONNECTED --- 在 bufferevent 上請求連接完成了
  14. typedef void (* bufferevent_event_cb )( struct bufferevent * bev , short events , void * ctx );
  15. ?
  16. // 設(shè)置回調(diào)函數(shù)
  17. // 如果希望禁用回調(diào)函數(shù),那么設(shè)置對應(yīng)的參數(shù)為 NULL
  18. void bufferevent_setcb (
  19. // bufferevent
  20. struct bufferevent * bufev ,
  21. // 讀取回調(diào)函數(shù)
  22. bufferevent_data_cb readcb ,
  23. // 寫入回調(diào)函數(shù)
  24. bufferevent_data_cb writecb ,
  25. // 事件回調(diào)函數(shù)
  26. bufferevent_event_cb eventcb ,
  27. // 用戶定義的數(shù)據(jù)
  28. // 這三個回調(diào)函數(shù)均共享此參數(shù)
  29. void * cbarg
  30. );
  31. ?
  32. // 取回回調(diào)函數(shù)
  33. // 參數(shù)為 NULL 表示忽略
  34. void bufferevent_getcb (
  35. struct bufferevent * bufev ,
  36. bufferevent_data_cb * readcb_ptr ,
  37. bufferevent_data_cb * writecb_ptr ,
  38. bufferevent_event_cb * eventcb_ptr ,
  39. void ** cbarg_ptr
  40. );

設(shè)置 watermark

  1. // events 參數(shù)可以為
  2. // EV_READ 表示設(shè)置 read watermark
  3. // EV_WRITE 表示設(shè)置 write watermark
  4. // EV_READ | EV_WRITE 表示設(shè)置 read 以及 write watermark
  5. void bufferevent_setwatermark ( struct bufferevent * bufev , short events ,
  6. size_t lowmark , size_t highmark );

獲取到輸入和輸出 buffer

  1. // 獲取到輸入 buffer
  2. struct evbuffer * bufferevent_get_input ( struct bufferevent * bufev );
  3. // 獲取到輸出 buffer
  4. struct evbuffer * bufferevent_get_output ( struct bufferevent * bufev );

添加數(shù)據(jù)到輸出 buffer

  1. // 下面兩個函數(shù)執(zhí)行成功返回 0 失敗返回 -1
  2. ?
  3. // 向 bufev 的輸出 buffer 中添加大小為 size 的數(shù)據(jù)
  4. // 數(shù)據(jù)的首地址為 data
  5. int bufferevent_write ( struct bufferevent * bufev ,
  6. const void * data , size_t size );
  7. // 向 bufev 的輸出 buffer 中添加數(shù)據(jù)
  8. // 數(shù)據(jù)來源于 buf
  9. // 此函數(shù)會清除 buf 中的所有數(shù)據(jù)
  10. int bufferevent_write_buffer ( struct bufferevent * bufev ,
  11. struct evbuffer * buf );

從輸入 buffer 中獲取數(shù)據(jù)

  1. // 從 bufev 的輸入 buffer 中獲取最多 size 字節(jié)的數(shù)據(jù)保存在 data 指向的內(nèi)存中
  2. // 此函數(shù)返回實(shí)際讀取的字節(jié)數(shù)
  3. size_t bufferevent_read ( struct bufferevent * bufev , void * data , size_t size );
  4. // 獲取 bufev 的輸入 buffer 中的所有數(shù)據(jù)并保存在 buf 中
  5. // 此函數(shù)成功返回 0 失敗返回 -1
  6. int bufferevent_read_buffer ( struct bufferevent * bufev ,
  7. struct evbuffer * buf );

關(guān)于 bufferevent 的一些高級話題,可以參考: http://www.wangafu.net/~nickm/libevent-book/Ref6a_advanced_bufferevents.html

evbuffers

evbuffer 是一個隊列,在其尾部添加數(shù)據(jù)和在其頭部刪除數(shù)據(jù)均被優(yōu)化了。evbuffer 相關(guān)的 API 在這里可以查看: http://www.wangafu.net/~nickm/libevent-book/Ref7_evbuffer.html

Libevent(4)— Bufferevent


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。?!

發(fā)表我的評論
最新評論 總共0條評論