• <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

            libevent: evbuffer緩沖 (轉)

            Posted on 2013-02-01 20:15 鑫龍 閱讀(14056) 評論(0)  編輯 收藏 引用 所屬分類: LIBEVENT

            前言

                可以說對于任何網絡庫(模塊)而言,一個緩沖模塊都是必不可少的。緩沖模塊主要用于緩沖從網絡接收到的數據,以及
            用戶提交的數據(用于發送)。很多時候,我們還需要將網絡模塊層(非TCP層)的這些緩沖數據拷貝到用戶層,而這些內存拷貝
            都會消耗時間。
                在這里,我簡要分析下libevent的相關代碼(event.h和buffer.c)。

            結構

                關于libevent的緩沖模塊,主要就是圍繞evbuffer結構體展開。先看下evbuffer的定義:

            struct evbuffer{
              
            // 當前有效緩沖區的內存起始地址
             u_char *buffer; 
              
            // 整個分配(realloc)用來緩沖的內存起始地址
              u_char *orig_buffer; 
              
            // origin_buffer和buffer之間的字節數
             size_t misalign; 
              
            // 整個分配用來緩沖的內存字節數
             size_t totallen; 
              
            // 當前有效緩沖區的長度(字節數)
             size_t off; 
              
            //回到函數,當緩沖區有變化的時候會被調用
             void (*cb)(struct evbuffer *, size_t, size_t, void *);
              
            //回調函數的參數
             void *cbarg; 
            };
             libevent的緩沖是一個連續的內存區域,其處理數據的方式(寫數據和讀數據)更像一個隊列操作方式:從后寫入,從前
            讀出。evbuffer分別設置相關指針(一個指標)用于指示讀出位置和寫入位置。其大致結構如圖:

                orig_buffer指向由realloc分配的連續內存區域,buffer指向有效數據的內存區域,totallen表示orig_buffer指向的內存
            區域的大小,misalign表示buffer相對于orig_buffer的偏移,off表示有效數據的長度。

            實際運作

                這里我將結合具體的代碼分析libevent是如何操作上面那個隊列式的evbuffer的,先看一些輔助函數:

            void evbuffer_drain(struct evbuffer *buf, size_t len)

             

                該函數主要操作一些指標,當每次從evbuffer里讀取數據時,libevent便會將buffer指針后移,同時增大misalign,減小off,
            而該函數正是做這件事的。說白了,該函數就是用于調整緩沖隊列的前向指標。


            int evbuffer_expand(struct evbuffer *buf, size_t datlen)

             

                該函數用于擴充evbuffer的容量。每次向evbuffer寫數據時,都是將數據寫到buffer+off后,buffer到buffer+off之間已被
            使用,保存的是有效數據,而orig_buffer和buffer之間則是因為讀取數據移動指標而形成的無效區域。
                evbuffer_expand的擴充策略在于,首先判斷如果讓出orig_buffer和buffer之間的空閑區域是否可以容納添加的數據,如果
            可以,則移動buffer和buffer+off之間的數據到orig_buffer和orig_buffer+off之間(有可能發生內存重疊,所以這里移動調用的
            是memmove),然后把新的數據拷貝到orig_buffer+off之后;如果不可以容納,那么重新分配更大的空間(realloc),同樣會移動
            數據。
                擴充內存的策略為:確保新的內存區域最小尺寸為256,且以乘以2的方式逐步擴大(256、512、1024、...)。

                了解了以上兩個函數,看其他函數就比較簡單了。可以看看具體的讀數據和寫數據:


            int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)

             

                該函數用于添加一段用戶數據到evbuffer中。很簡單,就是先判斷是否有足夠的空閑內存,如果沒有則調用evbuffer_expand
            擴充之,然后直接memcpy,更新off指標。


            int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)

             

                該函數用于將evbuffer中的數據復制給用戶空間(讀數據)。簡單地將數據memcpy,然后調用evbuffer_drain移動相關指標。


            struct evbuffer* evbuffer_new(void)
            動態分配一個struct evbuffer結構,需要調用evbuffer_free釋放內存。

            void evbuffer_free(struct evbuffer *buffer)
            釋放buffer所占用的內存。

            int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)

            移動數據從一個evbuffer到另一個evbuffer。

            實際上還是調用了evbuffer_add添加數據到outbuf中。但會清除inbuf中的數據。

            返回值:成功返回0, 失敗返回-1。


            int evbuffer_add_printf( struct evbuffer *const char* fmt, )
            添加一個格式化的字符串到evbuffer尾部。


            u_char *evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)

            查找緩沖區中是否存在指定的字符串what。

            注意這里使用的是u_char類型,說明有可能查找的數據不是以’\0’結尾

            如果存在返回指向字符串what的指針,沒有則返回NULL。


            int evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
            調用read/recv函數,從文件描述符fd上讀取數據到evbuffer中。如果緩沖區不夠,調用evbuffer_expand擴充緩沖區。

            int evbuffer_write(struct evbuffer *buffer, int fd)
            把緩沖區中的數據,調用send/write函數寫入文件描述符fd上, 如果send/write函數寫入的字節數大于0,則調用evbuffer_drain刪除已寫的數據。

            char *evbuffer_readline(struct evbuffer *buffer)

            讀取數據以"\r\n","\n\r", "\r" 或者 "\n"結尾。

            返回動態分配內存,需要調用者自己使用free來釋放內存。返回一個以\0結尾的字符串。


            void evbuffer_setcb(struct evbuffer *buffer,
                
            void (*cb)(struct evbuffer *, size_t, size_t, void *),
                
            void *cbarg)
            設置回調函數。當緩沖區中發生變化時, 調用設置的回調函數。

            Evbuffer提供的API已經全部介紹完畢,接下來我們通過一個實例進一步學習如何使用evbuffer, 想要使用evbuffer,系統里必須已經安裝了libevent。

            例子代碼如下:evbuffer-test.c

            #include <stdio.h>
            #include <string.h>
            #include <assert.h>

            //引入libevent頭文件
            #include "event.h"

            int main(int argc, char** argv)
            {
                
            struct evbuffer* buff = NULL;
                
            char c, c2[3= {0};
                

                
            buff = evbuffer_new();
                
            assert(buff != NULL);
                

                
            evbuffer_add(buff, "1"1);
                
            evbuffer_add(buff, "2"1);
                
            evbuffer_add(buff, "3"1);
                
            evbuffer_add_printf(buff, "%d%d"45);
                
            assert(buff->off == 5);

                
            evbuffer_remove(buff, &c, sizeof(char));
                
            assert(c == '1');
                
            evbuffer_remove(buff, &c, sizeof(char));
                
            assert(c == '2');
                
            evbuffer_remove(buff, &c, sizeof(char));
                
            assert(c == '3');
                
            evbuffer_remove(buff, c2, 2);
                
            assert(strcmp(c2, "45"== 0);
                

                
            assert(buff->off == 0);
              

                
            evbuffer_add(buff, "test\r\n"6);
                
            assert(buff->off == 6);
                

                
            char* line = evbuffer_readline(buff);
                
            assert(strcmp(line, "test"==0);
                
            assert(buff->off == 0);
                
            free(line);
               

                
            evbuffer_free(buff);
                

                
            printf("ok\n");
                

                
            return 0;
            }

             

             

            久久久久亚洲AV无码麻豆| 日本亚洲色大成网站WWW久久| 国内精品伊人久久久影院| 亚洲精品乱码久久久久久久久久久久 | 国产精品久久午夜夜伦鲁鲁| 久久精品国产只有精品2020| 精品无码久久久久久久久久| 97视频久久久| 99久久国产主播综合精品| 久久久久久久免费视频| 久久亚洲高清观看| 久久久久久久波多野结衣高潮| 精品久久久久中文字幕日本| 久久夜色精品国产亚洲av| 久久人爽人人爽人人片AV| 观看 国产综合久久久久鬼色 欧美 亚洲 一区二区 | 国产精品久久久久久五月尺| 69久久夜色精品国产69| 亚洲人成无码网站久久99热国产| 无码人妻精品一区二区三区久久久 | 久久久久亚洲AV无码麻豆| 亚洲欧洲精品成人久久奇米网| 精品久久久久久中文字幕| 午夜天堂av天堂久久久| 久久久久无码精品| 久久成人影院精品777| 久久人人爽人人爽人人片AV麻烦| 国产成人精品久久一区二区三区av | 丁香久久婷婷国产午夜视频| 久久99精品国产自在现线小黄鸭 | 久久精品国产2020| 亚洲另类欧美综合久久图片区| 国产精品青草久久久久福利99| 久久影院综合精品| 国内精品久久久久影院薰衣草 | 国产精品九九久久精品女同亚洲欧美日韩综合区 | 国产一级做a爰片久久毛片| 久久精品中文騷妇女内射| 久久青青草原亚洲av无码app| 久久久久久久久波多野高潮| 国产亚洲精久久久久久无码77777|