• <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緩沖 (轉(zhuǎn))

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

            前言

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

            結(jié)構(gòu)

                關(guān)于libevent的緩沖模塊,主要就是圍繞evbuffer結(jié)構(gòu)體展開。先看下evbuffer的定義:

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

                orig_buffer指向由realloc分配的連續(xù)內(nèi)存區(qū)域,buffer指向有效數(shù)據(jù)的內(nèi)存區(qū)域,totallen表示orig_buffer指向的內(nèi)存
            區(qū)域的大小,misalign表示buffer相對于orig_buffer的偏移,off表示有效數(shù)據(jù)的長度。

            實(shí)際運(yùn)作

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

            void evbuffer_drain(struct evbuffer *buf, size_t len)

             

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


            int evbuffer_expand(struct evbuffer *buf, size_t datlen)

             

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

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


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

             

                該函數(shù)用于添加一段用戶數(shù)據(jù)到evbuffer中。很簡單,就是先判斷是否有足夠的空閑內(nèi)存,如果沒有則調(diào)用evbuffer_expand
            擴(kuò)充之,然后直接memcpy,更新off指標(biāo)。


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

             

                該函數(shù)用于將evbuffer中的數(shù)據(jù)復(fù)制給用戶空間(讀數(shù)據(jù))。簡單地將數(shù)據(jù)memcpy,然后調(diào)用evbuffer_drain移動相關(guān)指標(biāo)。


            struct evbuffer* evbuffer_new(void)
            動態(tài)分配一個struct evbuffer結(jié)構(gòu),需要調(diào)用evbuffer_free釋放內(nèi)存。

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

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

            移動數(shù)據(jù)從一個evbuffer到另一個evbuffer。

            實(shí)際上還是調(diào)用了evbuffer_add添加數(shù)據(jù)到outbuf中。但會清除inbuf中的數(shù)據(jù)。

            返回值:成功返回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)

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

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

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


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

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

            char *evbuffer_readline(struct evbuffer *buffer)

            讀取數(shù)據(jù)以"\r\n","\n\r", "\r" 或者 "\n"結(jié)尾。

            返回動態(tài)分配內(nèi)存,需要調(diào)用者自己使用free來釋放內(nèi)存。返回一個以\0結(jié)尾的字符串。


            void evbuffer_setcb(struct evbuffer *buffer,
                
            void (*cb)(struct evbuffer *, size_t, size_t, void *),
                
            void *cbarg)
            設(shè)置回調(diào)函數(shù)。當(dāng)緩沖區(qū)中發(fā)生變化時, 調(diào)用設(shè)置的回調(diào)函數(shù)。

            Evbuffer提供的API已經(jīng)全部介紹完畢,接下來我們通過一個實(shí)例進(jìn)一步學(xué)習(xí)如何使用evbuffer, 想要使用evbuffer,系統(tǒng)里必須已經(jīng)安裝了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一坑| 欧美日韩中文字幕久久久不卡| 亚洲七七久久精品中文国产| 久久精品日日躁夜夜躁欧美| 日韩人妻无码精品久久久不卡 | 精品久久久久久久| 成人午夜精品久久久久久久小说 | 波多野结衣AV无码久久一区| 久久精品国产免费| 欧美性大战久久久久久| 新狼窝色AV性久久久久久| 亚洲精品成人久久久| 99国产精品久久| 亚洲精品国产美女久久久| 国产精品永久久久久久久久久| 亚洲愉拍99热成人精品热久久| 国产成人99久久亚洲综合精品| 亚洲人成伊人成综合网久久久| 国产精品99久久不卡| 国内精品久久人妻互换| 久久中文字幕无码专区| 久久精品无码一区二区日韩AV | 97久久久精品综合88久久| 久久久久噜噜噜亚洲熟女综合 | 亚洲欧美日韩中文久久 | 精品久久无码中文字幕| 老男人久久青草av高清| 中文字幕无码免费久久| 日本精品久久久久久久久免费| 色成年激情久久综合| 久久精品三级视频| 99久久夜色精品国产网站| 色综合合久久天天综合绕视看| 国产亚洲综合久久系列| 亚洲精品无码成人片久久| 一本久久a久久精品亚洲| 日韩人妻无码一区二区三区久久99| 久久伊人中文无码| 伊人久久大香线蕉无码麻豆 | 久久99精品国产自在现线小黄鸭 | 久久久久久亚洲精品不卡|