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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

libevent(1)

發布時間:2024/8/24 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libevent(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

很多時候,除了響應事件之外,應用還希望做一定的數據緩沖。比如說,寫入數據的時候,通常的運行模式是:

l?決定要向連接寫入一些數據,把數據放入到緩沖區中

l?等待連接可以寫入

l?寫入盡量多的數據

l?記住寫入了多少數據,如果還有更多數據要寫入,等待連接再次可以寫入

這種緩沖IO模式很通用,libevent為此提供了一種通用機制,即bufferevent。bufferevent由一個底層的傳輸端口(如套接字),一個讀取緩沖區和一個寫入緩沖區組成。與通常的事件在底層傳輸端口已經就緒,可以讀取或者寫入的時候執行回調不同的是,bufferevent在讀取或者寫入了足夠量的數據之后調用用戶提供的回調。

有多種共享公用接口的bufferevent類型,編寫本文時已存在以下類型:

l?基于套接字的bufferevent:使用event_*接口作為后端,通過底層流式套接字發送或者接收數據的bufferevent

l?異步IO?bufferevent:使用Windows?IOCP接口,通過底層流式套接字發送或者接收數據的bufferevent(僅用于Windows,試驗中)

l?過濾型bufferevent:將數據傳輸到底層bufferevent對象之前,處理輸入或者輸出數據的bufferevent:比如說,為了壓縮或者轉換數據。

l?成對的bufferevent:相互傳輸數據的兩個bufferevent。

注意:截止2.0.2-alpha版,這里列出的bufferevent接口還沒有完全正交于所有的bufferevent類型。也就是說,下面將要介紹的接口不是都能用于所有bufferevent類型。libevent開發者在未來版本中將修正這個問題。

也請注意:當前bufferevent只能用于像TCP這樣的面向流的協議,將來才可能會支持像UDP這樣的面向數據報的協議。

本節描述的所有函數和類型都在event2/bufferevent.h中聲明。特別提及的關于evbuffer的函數聲明在event2/buffer.h中,詳細信息請參考下一章。

1?bufferevent和evbuffer

每個bufferevent都有一個輸入緩沖區和一個輸出緩沖區,它們的類型都是“struct?evbuffer”。有數據要寫入到bufferevent時,添加數據到輸出緩沖區;bufferevent中有數據供讀取的時候,從輸入緩沖區抽取(drain)數據。

evbuffer接口支持很多種操作,后面的章節將討論這些操作。

2?回調和水位

每個bufferevent有兩個數據相關的回調:一個讀取回調和一個寫入回調。默認情況下,從底層傳輸端口讀取了任意量的數據之后會調用讀取回調;輸出緩沖區中足夠量的數據被清空到底層傳輸端口后寫入回調會被調用。通過調整bufferevent的讀取和寫入“水位(watermarks)”可以覆蓋這些函數的默認行為。

每個bufferevent有四個水位:

l?讀取低水位:讀取操作使得輸入緩沖區的數據量在此級別或者更高時,讀取回調將被調用。默認值為0,所以每個讀取操作都會導致讀取回調被調用。

l?讀取高水位:輸入緩沖區中的數據量達到此級別后,bufferevent將停止讀取,直到輸入緩沖區中足夠量的數據被抽取,使得數據量低于此級別。默認值是無限,所以永遠不會因為輸入緩沖區的大小而停止讀取。

l?寫入低水位:寫入操作使得輸出緩沖區的數據量達到或者低于此級別時,寫入回調將被調用。默認值是0,所以只有輸出緩沖區空的時候才會調用寫入回調。

l?寫入高水位:bufferevent沒有直接使用這個水位。它在bufferevent用作另外一個bufferevent的底層傳輸端口時有特殊意義。請看后面關于過濾型bufferevent的介紹。

?

bufferevent也有“錯誤”或者“事件”回調,用于向應用通知非面向數據的事件,如連接已經關閉或者發生錯誤。定義了下列事件標志:

l?BEV_EVENT_READING:讀取操作時發生某事件,具體是哪種事件請看其他標志。

l?BEV_EVENT_WRITING:寫入操作時發生某事件,具體是哪種事件請看其他標志。

l?BEV_EVENT_ERROR:操作時發生錯誤。關于錯誤的更多信息,請調用EVUTIL_SOCKET_ERROR()。

l?BEV_EVENT_TIMEOUT:發生超時。

l?BEV_EVENT_EOF:遇到文件結束指示。

l?BEV_EVENT_CONNECTED:請求的連接過程已經完成。

上述標志由2.0.2-alpha版新引入。

3?延遲回調

默認情況下,bufferevent的回調在相應的條件發生時立即被執行。(evbuffer的回調也是這樣的,隨后會介紹)在依賴關系復雜的情況下,這種立即調用會制造麻煩。比如說,假如某個回調在evbuffer?A空的時候向其中移入數據,而另一個回調在evbuffer?A滿的時候從中取出數據。這些調用都是在棧上發生的,在依賴關系足夠復雜的時候,有棧溢出的風險。

要解決此問題,可以請求bufferevent(或者evbuffer)延遲其回調。條件滿足時,延遲回調不會立即調用,而是在event_loop()調用中被排隊,然后在通常的事件回調之后執行。

(延遲回調由libevent?2.0.1-alpha版引入)

4?bufferevent的選項標志

創建bufferevent時可以使用一個或者多個標志修改其行為??勺R別的標志有:

l?BEV_OPT_CLOSE_ON_FREE:釋放bufferevent時關閉底層傳輸端口。這將關閉底層套接字,釋放底層bufferevent等。

l?BEV_OPT_THREADSAFE:自動為bufferevent分配鎖,這樣就可以安全地在多個線程中使用bufferevent。

l?BEV_OPT_DEFER_CALLBACKS:設置這個標志時,bufferevent延遲所有回調,如上所述。

l?BEV_OPT_UNLOCK_CALLBACKS:默認情況下,如果設置bufferevent為線程安全的,則bufferevent會在調用用戶提供的回調時進行鎖定。設置這個選項會讓libevent在執行回調的時候不進行鎖定。

(BEV_OPT_UNLOCK_CALLBACKS由2.0.5-beta版引入,其他選項由2.0.1-alpha版引入)

5?與基于套接字的bufferevent一起工作

基于套接字的bufferevent是最簡單的,它使用libevent的底層事件機制來檢測底層網絡套接字是否已經就緒,可以進行讀寫操作,并且使用底層網絡調用(如readv、writev、WSASend、WSARecv)來發送和接收數據。

5.1?創建基于套接字的bufferevent

可以使用bufferevent_socket_new()創建基于套接字的bufferevent。

接口

base是event_base,options是表示bufferevent選項(BEV_OPT_CLOSE_ON_FREE等)的位掩碼,fd是一個可選的表示套接字的文件描述符。如果想以后設置文件描述符,可以設置fd為-1。

成功時函數返回一個bufferevent,失敗則返回NULL。

bufferevent_socket_new()函數由2.0.1-alpha版新引入。

5.2?在基于套接字的bufferevent上啟動連接

如果bufferevent的套接字還沒有連接上,可以啟動新的連接。

接口

address和addrlen參數跟標準調用connect()的參數相同。如果還沒有為bufferevent設置套接字,調用函數將為其分配一個新的流套接字,并且設置為非阻塞的。

如果已經為bufferevent設置套接字,調用bufferevent_socket_connect()將告知libevent套接字還未連接,直到連接成功之前不應該對其進行讀取或者寫入操作。

連接完成之前可以向輸出緩沖區添加數據。

如果連接成功啟動,函數返回0;如果發生錯誤則返回-1。

示例

bufferevent_socket_connect()函數由2.0.2-alpha版引入。在此之前,必須自己手動在套接字上調用connect(),連接完成時,bufferevent將報告寫入事件。

注意:如果使用bufferevent_socket_connect()發起連接,將只會收到BEV_EVENT_CONNECTED事件。如果自己調用connect(),則連接上將被報告為寫入事件。

這個函數在2.0.2-alpha版引入。

?

5.3?通過主機名啟動連接

常常需要將解析主機名和連接到主機合并成單個操作,libevent為此提供了:

接口

這個函數解析名字hostname,查找其family類型的地址(允許的地址族類型有AF_INET,AF_INET6和AF_UNSPEC)。如果名字解析失敗,函數將調用事件回調,報告錯誤事件。如果解析成功,函數將啟動連接請求,就像bufferevent_socket_connect()一樣。

dns_base參數是可選的:如果為NULL,等待名字查找完成期間調用線程將被阻塞,而這通常不是期望的行為;如果提供dns_base參數,libevent將使用它來異步地查詢主機名。關于DNS的更多信息,請看第九章。

跟bufferevent_socket_connect()一樣,函數告知libevent,bufferevent上現存的套接字還沒有連接,在名字解析和連接操作成功完成之前,不應該對套接字進行讀取或者寫入操作。

函數返回的錯誤可能是DNS主機名查詢錯誤,可以調用bufferevent_socket_get_dns_error()來獲取最近的錯誤。返回值0表示沒有檢測到DNS錯誤。

示例:簡單的HTTP?v0客戶端

6?通用bufferevent操作

本節描述的函數可用于多種bufferevent實現。

6.1?釋放bufferevent

接口

這個函數釋放bufferevent。bufferevent內部具有引用計數,所以,如果釋放bufferevent時還有未決的延遲回調,則在回調完成之前bufferevent不會被刪除。

如果設置了BEV_OPT_CLOSE_ON_FREE標志,并且bufferevent有一個套接字或者底層bufferevent作為其傳輸端口,則釋放bufferevent將關閉這個傳輸端口。

這個函數由libevent?0.8版引入。

6.2?操作回調、水位和啟用/禁用

接口

bufferevent_setcb() 函數修改bufferevent的一個或者多個回調。readcb、writecb和eventcb函數將分別在已經讀取足夠的數據、已經寫入足夠的數 據,或者發生錯誤時被調用。每個回調函數的第一個參數都是發生了事件的bufferevent,最后一個參數都是調用 bufferevent_setcb()時用戶提供的cbarg參數:可以通過它向回調傳遞數據。事件回調的events參數是一個表示事件標志的位掩碼:請看前面的“回調和水位”節。

要禁用回調,傳遞NULL而不是回調函數。注意:bufferevent的所有回調函數共享單個cbarg,所以修改它將影響所有回調函數。

這個函數由1.4.4版引入。類型名bufferevent_data_cb和bufferevent_event_cb由2.0.2-alpha版引入。

接口

可以啟用或者禁用bufferevent上的EV_READ、EV_WRITE或者EV_READ?|?EV_WRITE事件。沒有啟用讀取或者寫入事件時,bufferevent將不會試圖進行數據讀取或者寫入。

沒有必要在輸出緩沖區空時禁用寫入事件:bufferevent將自動停止寫入,然后在有數據等待寫入時重新開始。

類似地,沒有必要在輸入緩沖區高于高水位時禁用讀取事件:bufferevent將自動停止讀取,然后在有空間用于讀取時重新開始讀取。

默認情況下,新創建的bufferevent的寫入是啟用的,但是讀取沒有啟用。

可以調用bufferevent_get_enabled()確定bufferevent上當前啟用的事件。

除了bufferevent_get_enabled()由2.0.3-alpha版引入外,這些函數都由0.8版引入。

接口

bufferevent_setwatermark()函數調整單個bufferevent的讀取水位、寫入水位,或者同時調整二者。(如果events參數設置了EV_READ,調整讀取水位。如果events設置了EV_WRITE標志,調整寫入水位)

對于高水位,0表示“無限”。

這個函數首次出現在1.4.4版。

示例

6.3?操作bufferevent中的數據

如果只是通過網絡讀取或者寫入數據,而不能觀察操作過程,是沒什么好處的。bufferevent提供了下列函數用于觀察要寫入或者讀取的數據。(Reading?and?writing?data?from?the?network?does?you?no?good?if?you?can't?look?at?it.Bufferevents?give?you?these?methods?to?give?them?data?to?write,and?to?get?the?data?to?read.)

接口

這兩個函數提供了非常強大的基礎:它們分別返回輸入和輸出緩沖區。關于可以對evbuffer類型進行的所有操作的完整信息,請看下一章。

如果寫入操作因為數據量太少而停止(或者讀取操作因為太多數據而停止),則向輸出緩沖區添加數據(或者從輸入緩沖區移除數據)將自動重啟操作。

這些函數由2.0.1-alpha版引入。

接口

這些函數向bufferevent的輸出緩沖區添加數據。bufferevent_write()將內存中從data處開始的size字節數據添加到輸出緩沖區的末尾。bufferevent_write_buffer()移除buf的所有內容,將其放置到輸出緩沖區的末尾。成功時這些函數都返回0,發生錯誤時則返回-1。

這些函數從0.8版就存在了。

接口

這 些函數從bufferevent的輸入緩沖區移除數據。bufferevent_read()至多從輸入緩沖區移除size字節的數據,將其存儲到內存中 data處。函數返回實際移除的字節數。bufferevent_read_buffer()函數抽空輸入緩沖區的所有內容,將其放置到buf中,成功時 返回0,失敗時返回-1。

注意,對于bufferevent_read(),data處的內存塊必須有足夠的空間容納size字節數據。

bufferevent_read()函數從0.8版就存在了;bufferevnet_read_buffer()由2.0.1-alpha版引入。

示例

6.4?讀寫超時

跟其他事件一樣,可以要求在一定量的時間已經流逝,而沒有成功寫入或者讀取數據的時候調用一個超時回調。

接口

設置超時為NULL會移除超時回調。

試圖讀取數據的時候,如果至少等待了timeout_read秒,則讀取超時事件將被觸發。試圖寫入數據的時候,如果至少等待了timeout_write秒,則寫入超時事件將被觸發。

注意,只有在讀取或者寫入的時候才會計算超時。也就是說,如果bufferevent的讀取被禁止,或者輸入緩沖區滿(達到其高水位),則讀取超時被禁止。類似的,如果寫入被禁止,或者沒有數據待寫入,則寫入超時被禁止。

讀取或者寫入超時發生時,相應的讀取或者寫入操作被禁止,然后超時事件回調被調用,帶有標志BEV_EVENT_TIMEOUT?|?BEV_EVENT_READING或者BEV_EVENT_TIMEOUT?|?BEV_EVENT_WRITING。

這個函數從2.0.1-alpha版就存在了,但是直到2.0.4-alpha版才對于各種bufferevent類型行為一致。

6.5?對bufferevent發起清空操作

接口

清空bufferevent要求bufferevent強制從底層傳輸端口讀取或者寫入盡可能多的數據,而忽略其他可能保持數據不被寫入的限制條件。函數的細節功能依賴于bufferevent的具體類型。

iotype參數應該是EV_READ、EV_WRITE或者EV_READ?|?EV_WRITE,用于指示應該處理讀取、寫入,還是二者都處理。state參數可以是BEV_NORMAL、BEV_FLUSH或者BEV_FINISHED。BEV_FINISHED指示應該告知另一端,沒有更多數據需要發送了;而BEV_NORMAL和BEV_FLUSH的區別依賴于具體的bufferevent類型。

失敗時bufferevent_flush()返回-1,如果沒有數據被清空則返回0,有數據被清空則返回1。

當前(2.0.5-beta版)僅有一些bufferevent類型實現了bufferevent_flush()。特別是,基于套接字的bufferevent沒有實現。

7?類型特定的bufferevent函數

這些bufferevent函數不能支持所有bufferevent類型。

接口

這個函數調整bufev的優先級為pri。關于優先級的更多信息請看event_priority_set()。

成功時函數返回0,失敗時返回-1。這個函數僅能用于基于套接字的bufferevent。

這個函數由1.0版引入。

接口

這些函數設置或者返回基于fd的事件的文件描述符。只有基于套接字的bufferevent支持setfd()。兩個函數都在失敗時返回-1;setfd()成功時返回0。

bufferevent_setfd()函數由1.4.4版引入;bufferevent_getfd()函數由2.0.2-alpha版引入。

接口

這個函數返回bufferevent的event_base,由2.0.9-rc版引入。

接口

這個函數返回作為bufferevent底層傳輸端口的另一個bufferevent。關于這種情況,請看關于過濾型bufferevent的介紹。

這個函數由2.0.2-alpha版引入。

8?手動鎖定和解鎖

有時候需要確保對bufferevent的一些操作是原子地執行的。為此,libevent提供了手動鎖定和解鎖bufferevent的函數。

接口

注意:如果創建bufferevent時沒有指定BEV_OPT_THREADSAFE標志,或者沒有激活libevent的線程支持,則鎖定操作是沒有效果的。

用這個函數鎖定bufferevent將自動同時鎖定相關聯的evbuffer。這些函數是遞歸的:鎖定已經持有鎖的bufferevent是安全的。當然,對于每次鎖定都必須進行一次解鎖。

這些函數由2.0.6-rc版引入。

9?已廢棄的bufferevent功能

從1.4到2.0版,bufferevent的后端代碼一直在進行修訂。在老的接口中,訪問bufferevent結構體的內部是很平常的,并且還會使用依賴于這種訪問的宏。

更復雜的是,老的代碼有時候將“evbuffer”前綴用于bufferevent功能。

這里有一個在2.0版之前使用過的東西的概要:

老的函數定義在event.h中,而不是在event2/bufferevent.h中。

如果仍然需要訪問bufferevent結構體內部的某些公有部分,可以包含event2/bufferevent_struct.h。但是不建議這么做:不同版本的Libevent中bufferevent結構體的內容可能會改變。本節描述的宏和名字只有在包含了event2/bufferevent_compat.h時才能使用。

較老版本中用于設置bufferevent的接口有所不同:

接口

bufferevent_new()函數僅僅在已經廢棄的“默認”event_base上創建一個套接字bufferevent。調用bufferevent_base_set()可以調整套接字bufferevent的event_base。

較老版本不使用timeval結構體設置超時,而是使用秒數:

接口

最后要指出的是,2.0之前版本中的evbuffer實現是極其低效的,這對將bufferevent用于高性能應用是一個問題。

轉載于:https://www.cnblogs.com/zzyoucan/p/3751166.html

總結

以上是生活随笔為你收集整理的libevent(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。