1. 程式人生 > >libevent原始碼分析--evbuffer緩衝

libevent原始碼分析--evbuffer緩衝

實際運作

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

void evbuffer_drain(struct evbuffer *buf, size_t len)

      在這個函式中,最後一個部分是呼叫了evbuffer中的回撥,如果這個buffer已經被修改,那麼直接呼叫這個buffer中的回撥!

    該函式主要操作一些指標,當每次從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, constvoid*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 *constchar* 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");
    
return0;
}

相關推薦

libevent原始碼分析--evbuffer緩衝

實際運作     這裡我將結合具體的程式碼分析libevent是如何操作上面那個佇列式的evbuffer的,先看一些輔助函式: void evbuffer_drain(struct evbuffer *buf, size_t len)       在這個函式中,最後一個部分是呼叫了evbuffer中的

Libevent原始碼分析-----evbuffer結構與基本操作

        對於非阻塞IO的網路庫來說,buffer幾乎是必須的。Libevent在1.0版本之前就提供了buffer功能。現在來看一下Libevent的buffer。 buffer相關結構體:         Libevent為buffer定義了下面

Libevent原始碼分析-----更多evbuffer操作函式

鎖操作:         在前一篇博文可以看到很多函式在操作前都需要對這個evbuffer進行加鎖。同event_base不同,如果evbuffer支援鎖的話,要顯式地呼叫函式evbuffer_enable_locking。 //buffer.c檔案 int//

Libevent原始碼分析(五)--- evbuffer的基本操作

之前幾節分析了libevent底層的結構和執行機制,接下來的幾節將會分析Bufferevents,Bufferevents在event的基礎上加入了資料快取邏輯,使得事件和資料結合在一起。libevent的bufferevent有六種型別,分別是:buffere

MySQL 原始碼分析 Innodb緩衝池刷髒的多執行緒實現

簡介 為了提高效能,大多數的資料庫在操作資料時都不會直接讀寫磁碟,而是中間經過緩衝池,將要寫入磁碟的資料先寫入到緩衝池裡,然後在某個時刻後臺執行緒把修改的資料刷寫到磁碟上。MySQL的InnoDB引擎也使用緩衝池來快取從磁碟讀取或修改的資料頁,如果當前資料庫需要操作的資料集比緩衝池中的空閒頁面大

libevent原始碼分析--鎖和多執行緒

寫在前面: ​ 這個原始碼是分析libevent-2.0.20-stable, 並非最新版本的libevent,作者並沒有全看原始碼,在這裡會推薦以下參考的一些網站,也歡迎大家在不足的地方提出來進行討論。 鎖 ​ libevent的內部實現不需要多執行緒,

libevent原始碼分析

1 libevent簡介 libevent是一個事件通知庫,適用於windows、linux、bsd等多種平臺,內部使用select、epoll、kqueue、IOCP等系統呼叫管理事件機制。著名分散式快取軟體memcached也是基於libevent,而且l

libevent原始碼分析(五)

libevent-1.4/sample/signal-test.c event_add(&signal_int, NULL); 將 struct event signal_int新增到struct event_base* base,即註冊號監聽事件以及回

libevent原始碼分析(六)

libevent-1.4/sample/singnal-test.c 接下來看看 event_base_dispatch(base); 這個函式是整個Reactor的核心,是一個loop. 函式定義: int event_base_dispatch(struct

Libevent原始碼分析-----event-config.h指明所在系統的環境

        如果你開啟Libevent的一些檔案,比如util.h檔案。就會發現使用了很多巨集定義,並根據一些巨集定義而進行條件編譯。這些巨集定義往往來自event-config.h檔案中。         如util.h檔案的程式碼開始處: #ifdef _EV

Libevent原始碼分析-----記憶體分配

    Libevent的記憶體分配函式還是比較簡單的,並沒有定義記憶體池之類的東西。如同前一篇部落格那樣,給予Libevent庫的使用者充分的設定權(定製),即可以設定使用者(Libevent庫的使用者)自己的記憶體分配函式。至於怎麼分配,主動權在於使用者。但在設定(定製)

Libevent原始碼分析-----event_io_map雜湊表

  上一篇部落格說到了TAILQ_QUEUE佇列,它可以把多個event結構體連在一起。是一種歸類方式。本文也將講解一種將event歸類、連在一起的結構:雜湊結構。 雜湊結構體:         雜湊結構由下面幾個結構體一起配合工作: struct event_l

Libevent原始碼分析-----event_signal_map

相關結構體:                 因為event_signal_map結構體實在太簡單了,所以不像event_io_map那樣,有一個專門的檔案。由於沒有專門的檔案,那麼只能從蛛絲馬跡上探索這個event_signal_map結構了。         通過一些

Libevent原始碼分析-----配置event_base

    前面的博文都是講一些Libevent的一些輔助結構,現在來講一下關鍵結構體:event_base。         這裡作一個提醒,在閱讀Libevent原始碼時,會經常看到backend這個單詞。其直譯是“後端”。實際上其指的是Libevent內部使用的多路I

Libevent原始碼分析-----跨平臺Reactor介面的實現

        之前的博文講了怎麼實現執行緒、鎖、記憶體分配、日誌等功能的跨平臺。Libevent最重要的跨平臺功能還是實現了多路IO介面的跨平臺(即Reactor模式)。這使得使用者可以在不同的平臺使用統一的介面。這篇博文就是來講解Libevent是怎麼實現這一點的。

Libevent原始碼分析-----Libevent工作流程探究

        之前的博文講了很多Libevent的基礎構件,現在以一個實際例子來初步探究Libevent的基本工作流程。由於還有很多Libevent的細節並沒有講所以,這裡的探究還是比較簡潔,例子也相當簡單。 #include<unistd.h> #in

Libevent原始碼分析-----訊號event的處理

訊號event的工作原理:         前面講解了Libevent如何監聽一個IO事件,現在來講一下Libevent如何監聽訊號。Libevent對於訊號的處理是採用統一事件源的方式。簡單地說,就是把訊號也轉換成IO事件,整合到Libevent中。         統

Libevent原始碼分析-----與event相關的一些函式和操作

        Libevent提供了一些與event相關的操作函式和操作。本文就重點講一下這方面的原始碼。         在Libevent中,無論是event還是event_base,都是使用指標而不會使用變數。實際上,如果檢視Libevent不同的版本,就可

Libevent原始碼分析-----超時event的處理

如何成為超時event:                 Libevent允許建立一個超時event,使用evtimer_new巨集。 //event.h檔案 #define evtimer_new(b, cb, arg) event_new((b), -1, 0,

Libevent原始碼分析-----通用型別和函式

        Libevent定義了一系列的可移植的相容型別和函式。這使得在各個系統上都有一致的效果,Libevent一般都會在相容通用型別和函式的前面加上ev或evutil字首。         在實現上,Libevent都是使用條件編譯+巨集定義的方式。使用這