• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 200, comments - 8, trackbacks - 0, articles - 0

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

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

            等待連接可以寫入

            寫入盡量多的數據

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

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

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

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

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

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

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

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

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

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

            bufferevent和evbuffer

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

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

            回調和水位

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

            每個bufferevent有四個水位:

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

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

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

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

             

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

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

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

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

            BEV_EVENT_TIMEOUT:發生超時。

            BEV_EVENT_EOF:遇到文件結束指示。

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

            上述標志由2.0.2-alpha新引入

            延遲回調

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

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

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

            bufferevent的選項標志

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

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

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

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

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

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

            基于套接字的bufferevent一起工作

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

            5.1 創建基于套接字的bufferevent

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

            接口
            struct bufferevent *bufferevent_socket_new(
                
            struct event_base *base,
                evutil_socket_t fd,
                
            enum bufferevent_options options);

            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的套接字還沒有連接上,可以啟動新的連接。

            接口

            int bufferevent_socket_connect(struct bufferevent *bev,
                
            struct sockaddr *address, int addrlen);

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

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

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

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

            示例

            #include <event2/event.h>
            #include 
            <event2/bufferevent.h>
            #include 
            <sys/socket.h>
            #include 
            <string.h>

            void eventcb(struct bufferevent *bev, short events, void *ptr)
            {
                
            if (events & BEV_EVENT_CONNECTED) {
                     
            /* We're connected to 127.0.0.1:8080.   Ordinarily we'd do
                        something here, like start reading or writing. 
            */
                } 
            else if (events & BEV_EVENT_ERROR) {
                     
            /* An error occured while connecting. */
                }
            }

            int main_loop(void)
            {
                
            struct event_base *base;
                
            struct bufferevent *bev;
                
            struct sockaddr_in sin;

                
            base = event_base_new();

                memset(
            &sin, 0sizeof(sin));
                sin.sin_family 
            = AF_INET;
                sin.sin_addr.s_addr 
            = htonl(0x7f000001); /* 127.0.0.1 */
                sin.sin_port 
            = htons(8080); /* Port 8080 */

                bev 
            = bufferevent_socket_new(base-1, BEV_OPT_CLOSE_ON_FREE);

                bufferevent_setcb(bev, NULL, NULL, eventcb, NULL);

                
            if (bufferevent_socket_connect(bev,
                    (
            struct sockaddr *)&sin, sizeof(sin)) < 0) {
                    
            /* Error starting connection */
                    bufferevent_free(bev);
                    
            return -1;
                }

                event_base_dispatch(
            base);
                
            return 0;
            }

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

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

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

             

            5.3 通過主機名啟動連接

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

            接口

            int bufferevent_socket_connect_hostname(struct bufferevent *bev,
                
            struct evdns_base *dns_base, int family, const char *hostname,
                
            int port);
            int bufferevent_socket_get_dns_error(struct bufferevent *bev);

            這個函數解析名字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客戶端

            /* Don't actually copy this code: it is a poor way to implement an
               HTTP client.  Have a look at evhttp instead.
            */
            #include 
            <event2/dns.h>
            #include 
            <event2/bufferevent.h>
            #include 
            <event2/buffer.h>
            #include 
            <event2/util.h>
            #include 
            <event2/event.h>

            #include 
            <stdio.h>

            void readcb(struct bufferevent *bev, void *ptr)
            {
                
            char buf[1024];
                
            int n;
                
            struct evbuffer *input = bufferevent_get_input(bev);
                
            while ((n = evbuffer_remove(input, buf, sizeof(buf))) > 0) {
                    fwrite(buf, 
            1, n, stdout);
                }
            }

            void eventcb(struct bufferevent *bev, short events, void *ptr)
            {
                
            if (events & BEV_EVENT_CONNECTED) {
                     printf(
            "Connect okay.\n");
                } 
            else if (events & (BEV_EVENT_ERROR|BEV_EVENT_EOF)) {
                     
            struct event_base *base = ptr;
                     
            if (events & BEV_EVENT_ERROR) {
                             
            int err = bufferevent_socket_get_dns_error(bev);
                             
            if (err)
                                     printf(
            "DNS error: %s\n", evutil_gai_strerror(err));
                     }
                     printf(
            "Closing\n");
                     bufferevent_free(bev);
                     event_base_loopexit(
            base, NULL);
                }
            }

            int main(int argc, char **argv)
            {
                
            struct event_base *base;
                
            struct evdns_base *dns_base;
                
            struct bufferevent *bev;

                
            if (argc != 3) {
                    printf(
            "Trivial HTTP 0.x client\n"
                           
            "Syntax: %s [hostname] [resource]\n"
                           
            "Example: %s www.google.com /\n",argv[0],argv[0]);
                    
            return 1;
                }

                
            base = event_base_new();
                dns_base 
            = evdns_base_new(base1);

                bev 
            = bufferevent_socket_new(base-1, BEV_OPT_CLOSE_ON_FREE);
                bufferevent_setcb(bev, readcb, NULL, eventcb, 
            base);
                bufferevent_enable(bev, EV_READ
            |EV_WRITE);
                evbuffer_add_printf(bufferevent_get_output(bev), 
            "GET %s\r\n", argv[2]);
                bufferevent_socket_connect_hostname(
                    bev, dns_base, AF_UNSPEC, argv[
            1], 80);
                event_base_dispatch(
            base);
                
            return 0;
            }

            通用bufferevent操作

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

            6.1 釋放bufferevent

            接口

            void bufferevent_free(struct bufferevent *bev);

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

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

            這個函數由libevent 0.8版引入。

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

            接口

            typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
            typedef 
            void (*bufferevent_event_cb)(struct bufferevent *bev,
                
            short events, void *ctx);

            void bufferevent_setcb(struct bufferevent *bufev,
                bufferevent_data_cb readcb, bufferevent_data_cb writecb,
                bufferevent_event_cb eventcb, 
            void *cbarg);

            void bufferevent_getcb(struct bufferevent *bufev,
                bufferevent_data_cb 
            *readcb_ptr,
                bufferevent_data_cb 
            *writecb_ptr,
                bufferevent_event_cb 
            *eventcb_ptr,
                
            void **cbarg_ptr);

            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版引入。

            接口

            void bufferevent_enable(struct bufferevent *bufev, short events);
            void bufferevent_disable(struct bufferevent *bufev, short events);

            short bufferevent_get_enabled(struct bufferevent *bufev);

            可以啟用或者禁用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版引入。

            接口

            void bufferevent_setwatermark(struct bufferevent *bufev, short events,
                size_t lowmark, size_t highmark);

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

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

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

            示例

            #include <event2/event.h>
            #include 
            <event2/bufferevent.h>
            #include 
            <event2/buffer.h>
            #include 
            <event2/util.h>

            #include 
            <stdlib.h>
            #include 
            <errno.h>
            #include 
            <string.h>

            struct info {
                
            const char *name;
                size_t total_drained;
            };

            void read_callback(struct bufferevent *bev, void *ctx)
            {
                
            struct info *inf = ctx;
                
            struct evbuffer *input = bufferevent_get_input(bev);
                size_t len 
            = evbuffer_get_length(input);
                
            if (len) {
                    inf
            ->total_drained += len;
                    evbuffer_drain(input, len);
                    printf(
            "Drained %lu bytes from %s\n",
                         (unsigned 
            long) len, inf->name);
                }
            }

            void event_callback(struct bufferevent *bev, short events, void *ctx)
            {
                
            struct info *inf = ctx;
                
            struct evbuffer *input = bufferevent_get_input(bev);
                
            int finished = 0;

                
            if (events & BEV_EVENT_EOF) {
                    size_t len 
            = evbuffer_get_length(input);
                    printf(
            "Got a close from %s.  We drained %lu bytes from it, "
                        
            "and have %lu left.\n", inf->name,
                        (unsigned 
            long)inf->total_drained, (unsigned long)len);
                    finished 
            = 1;
                }
                
            if (events & BEV_EVENT_ERROR) {
                    printf(
            "Got an error from %s: %s\n",
                        inf
            ->name, evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
                    finished 
            = 1;
                }
                
            if (finished) {
                    free(ctx);
                    bufferevent_free(bev);
                }
            }

            struct bufferevent *setup_bufferevent(void)
            {
                
            struct bufferevent *b1 = NULL;
                
            struct info *info1;

                info1 
            = malloc(sizeof(struct info));
                info1
            ->name = "buffer 1";
                info1
            ->total_drained = 0;

                
            /*  Here we should set up the bufferevent and make sure it gets
                   connected 
            */

                
            /* Trigger the read callback only whenever there is at least 128 bytes
                   of data in the buffer. 
            */
                bufferevent_setwatermark(b1, EV_READ, 
            1280);

                bufferevent_setcb(b1, read_callback, NULL, event_callback, info1);

                bufferevent_enable(b1, EV_READ); 
            /* Start reading. */
                
            return b1;
            }

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

            接口

            struct evbuffer *bufferevent_get_input(struct bufferevent *bufev);
            struct evbuffer *bufferevent_get_output(struct bufferevent *bufev);

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

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

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

            接口

            int bufferevent_write(struct bufferevent *bufev,
                
            const void *data, size_t size);
            int bufferevent_write_buffer(struct bufferevent *bufev,
                
            struct evbuffer *buf);

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

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

            接口

            size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
            int bufferevent_read_buffer(struct bufferevent *bufev,
                
            struct evbuffer *buf);

            這些函數從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引入。

            示例

            #include <event2/bufferevent.h>
            #include 
            <event2/buffer.h>

            #include 
            <ctype.h>

            void
            read_callback_uppercase(
            struct bufferevent *bev, void *ctx)
            {
                    
            /* This callback removes the data from bev's input buffer 128
                       bytes at a time, uppercases it, and starts sending it
                       back.

                       (Watch out!  In practice, you shouldn't use toupper to implement
                       a network protocol, unless you know for a fact that the current
                       locale is the one you want to be using.)
                     
            */

                    
            char tmp[128];
                    size_t n;
                    
            int i;
                    
            while (1) {
                            n 
            = bufferevent_read(bev, tmp, sizeof(tmp));
                            
            if (n <= 0)
                                    
            break/* No more data. */
                            
            for (i=0; i<n; ++i)
                                    tmp[i] 
            = toupper(tmp[i]);
                            bufferevent_write(bev, tmp, n);
                    }
            }

            struct proxy_info {
                    
            struct bufferevent *other_bev;
            };
            void
            read_callback_proxy(
            struct bufferevent *bev, void *ctx)
            {
                    
            /* You might use a function like this if you're implementing
                       a simple proxy: it will take data from one connection (on
                       bev), and write it to another, copying as little as
                       possible. 
            */
                    
            struct proxy_info *inf = ctx;

                    bufferevent_read_buffer(bev,
                        bufferevent_get_output(inf
            ->other_bev));
            }

            struct count {
                    unsigned 
            long last_fib[2];
            };

            void
            write_callback_fibonacci(
            struct bufferevent *bev, void *ctx)
            {
                    
            /* Here's a callback that adds some Fibonacci numbers to the
                       output buffer of bev.  It stops once we have added 1k of
                       data; once this data is drained, we'll add more. 
            */
                    
            struct count *= ctx;

                    
            struct evbuffer *tmp = evbuffer_new();
                    
            while (evbuffer_get_length(tmp) < 1024) {
                             unsigned 
            long next = c->last_fib[0+ c->last_fib[1];
                             c
            ->last_fib[0= c->last_fib[1];
                             c
            ->last_fib[1= next;

                             evbuffer_add_printf(tmp, 
            "%lu", next);
                    }

                    
            /* Now we add the whole contents of tmp to bev. */
                    bufferevent_write_buffer(bev, tmp);

                    
            /* We don't need tmp any longer. */
                    evbuffer_free(tmp);
            }

            6.4 讀寫超時

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

            接口

            void bufferevent_set_timeouts(struct bufferevent *bufev,
                
            const struct timeval *timeout_read, const struct timeval *timeout_write);

            設置超時為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發起清空操作

            接口

            int bufferevent_flush(struct bufferevent *bufev,
                
            short iotype, enum bufferevent_flush_mode state)

            清空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沒有實現。

            類型特定的bufferevent函數

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

            接口

            int bufferevent_priority_set(struct bufferevent *bufev, int pri);
            int bufferevent_get_priority(struct bufferevent *bufev);

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

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

            這個函數由1.0引入。

            接口

            int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd);
            evutil_socket_t bufferevent_getfd(
            struct bufferevent *bufev);

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

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

            接口

            struct event_base *bufferevent_get_base(struct bufferevent *bev);

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

            接口

            struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev);

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

            這個函數由2.0.2-alpha引入。

            手動鎖定和解鎖

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

            接口

            void bufferevent_lock(struct bufferevent *bufev);
            void bufferevent_unlock(struct bufferevent *bufev);

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

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

            這些函數由2.0.6-rc引入。

            已廢棄的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的接口有所不同:

            接口

            struct bufferevent *bufferevent_new(evutil_socket_t fd,
                evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, 
            void *cbarg);
            int bufferevent_base_set(struct event_base *basestruct bufferevent *bufev);

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

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

            接口

            void bufferevent_settimeout(struct bufferevent *bufev,
                
            int timeout_read, int timeout_write);
            最后要指出的是,2.0之前版本中的evbuffer實現是極其低效的,這對將bufferevent用于高性能應用是一個問題。

            Feedback

            # re: 翻譯:libevent參考手冊第六章:bufferevent:概念和入門 (八) (轉)[未登錄]  回復  更多評論   

            2014-05-31 15:10 by zz
            不錯,學習了
            欧美亚洲日本久久精品| 国产精品久久久久久久人人看| 色综合久久久久| 日本精品久久久久影院日本| 亚洲午夜无码久久久久| 精品欧美一区二区三区久久久| 久久精品无码一区二区WWW| 久久精品草草草| 中文字幕久久精品无码| 久久精品国产精品亚洲| 人妻无码中文久久久久专区| 国产精品欧美亚洲韩国日本久久| 狠狠精品久久久无码中文字幕| 国产精品青草久久久久福利99 | 欧美日韩中文字幕久久伊人| 亚洲欧洲久久久精品| 91精品久久久久久无码| 久久综合给合久久狠狠狠97色| 久久久久亚洲精品天堂久久久久久| 亚洲AV日韩精品久久久久久久| 女同久久| 久久精品视屏| 99精品久久久久久久婷婷| 国产成人久久精品激情| 狠狠色综合网站久久久久久久高清| 亚洲一区中文字幕久久| 久久国产免费观看精品3| 国产精品久久久久久久人人看| 久久久久亚洲精品无码网址| 国产精品女同一区二区久久| 久久这里只有精品首页| 久久精品国产清高在天天线| 日韩精品久久久肉伦网站 | 久久久精品国产sm调教网站 | 亚洲国产精品久久久久久| 久久人人妻人人爽人人爽| 精品综合久久久久久98| 久久天天躁狠狠躁夜夜2020一| 思思久久好好热精品国产| 久久国产亚洲精品| 午夜精品久久久久|