轉自:https://blog.csdn.net/sdoyuxuan/article/details/81634047nginx
bufferevent
bufferevent介紹
因爲咱們在網絡通訊中有不少讀寫的場景,因此Libevent也提供了相應的bufferevent。這些bufferevent由一個底層的傳輸對象(socket),一個ReadBuufer,一個WriteBuffer構成。與以前普通的event不一樣的是bufferevent只有從它的傳輸對象(fd)讀取到了足夠多的數據後纔會調用它的回調函數。
bufferevent有四種類型,這四種類型共享一個接口:安全
基於socket的bufferevent,這些socket是以流形式的套接字,使用 event_* 的接口,因此它目前不支持udp
異步I/O的bufferevent ,這個只針對於IOCP
filtering bufferevents (過濾型),這個類型的bufferevent在把數據傳輸給底層的bufferevent對象前都會對數據進行輸入或者輸出的處理,好比咱們常常的解壓或者序列化/反序列化
paired bufferevent ,這種類型的bufferevent能夠互相通訊,這個像開了一個消息隊列或者管道
固然Libevent並無實現出這些公共的接口支持全部類型的buffervevent。這些bufferevent的細節能夠從event2/bufferevent.h中看到,evbuffer能夠從event2/buffer.h看到。網絡
不適用場景
不適用場景一 – 每次處理的數據量過大時
每次bufferevent都會從tcp的接受緩衝區幫咱們最多讀取4096個字節,那麼其實這樣就很顯得雞肋,若是咱們去處理大量數據的時候,它最多幫咱們讀出4096個字節,因此可能它幫咱們讀出的內容可能不夠咱們去進行一次數據的處理操做,因此咱們只能本身去使用它的Evbuffer緩衝區去讀更多的數據去處理業務。併發
不適用場景二 – 多路複用
在多路複用的場景下,可能咱們每次只從緩衝區處理一小部分數據,而後結束當前處理操做,把剩下的數據交給下一個處理模塊處理,這樣就能夠併發的處理更多的fd(socket)。nginx就是這樣的思路,把一個HTTP請求的處理分紅多個模塊,這樣就可使用多路複用同時處理多個鏈接的請求。可是在bufferevent中,它直接幫咱們讀上來了4096個字節,可能把下一個模塊的內容也讀到當前模塊,不利於去模塊化劃分,因此也不適合多路複用。less
雞肋的超時
bufferevent能夠給相應的read / write 操做設置超時,若是超時觸發後沒有寫或者讀就緒就會進入異常邏輯,轉而去調用 event 回調函數,這個其實十分不合理,由於咱們設置了一個超時給一個readcb 或者 writecb ,超時觸發後卻調用了eventcb函數。沒什麼用,只有read和timeout 同時觸發時,纔會進入正常邏輯,那有read觸發時咱們要 timeout有毛用?異步
何爲bufferevent
這個bufferevent就像咱們c語言中的標準輸入流和標準輸出流。在c 語言中FILE流對象,它也是封裝了一個文件描述符和一個輸入緩衝區和輸出緩衝區。那麼同理,在bufferevent中當有數據到達的時候,它代替了咱們讀取數據就像stdin同樣,咱們並無調用read系統調用只是調用了scanf數據就會被咱們讀上來。相同的是在bufferevent中,咱們把數據寫到output緩衝區後,不一樣擔憂什麼時候發送它會自動幫咱們發。
從buffer的設計來看,buffer就是減小咱們系統調用I/O函數的次數,將屢次數據一次性刷出提升I/O效率,這點在bufferevent中也是有體現到的。socket
如何自動讀取
由bufferevent內部封裝的rdevent去等待讀就緒,讀就緒後調用evbuffer_read把fd的數據讀到Input中,而後判斷若是高於read低水位線調用咱們本身設置的readcb。每次它最多幫咱們讀取 4096(EVBUFFER_MAX_READ)個字節。 tcp
evbuffer 和 bufferevent的關係
bufferevent中的輸入/輸出緩衝區類型就是 struct evbuffer。當咱們有數據要讀,能夠把它讀到bufferevent的輸入緩衝區中,有數據要寫同理。模塊化
bufferevent的回調函數與水位線
每個bufferevent都有一個讀callback 和 一個寫callback函數。默認,任何讀自於bufferevent的底層傳輸對象的數據都會致使讀callback被調用,而且每當有足夠的數據從寫緩衝區刷新到底層傳輸對象時寫callback被調用,你能夠經過調整下面的水位線來達到重寫這些回調函數的表現。
1. Read low-water mark : 讀取操做使得輸入緩衝區的數據量在此級別或者更高時 ,讀取回調將被調用。默認值爲 0,因此每一個讀取操做都會致使讀取回調被調用。
2. Read high-water mark:若是 bufferevent的輸入緩衝區達到這個級別後,bufferevent就中止讀取直到有足夠的數據被消費使咱們低於這個線,才能恢復讀取。默認是0,因此咱們不會由於輸入緩衝區的大小就中止讀取數據
3. Write low-water mark:每當一個write (發送)操做致使寫緩衝區中的數據小於等於這個線,寫callback就會被調用。默認是0,因此基本上不會調用寫callback 函數,除非write操做把寫緩衝區的數據搬空了,這個時候write callback 函數纔會回調。
4. Write high-water mark:沒啥用函數
bufferevent的回調函數中的short類型的參數標誌
BEV_EVENT_READING
1
一個bufferevent發送了讀操做,用來查看哪個event發送了讀操做
BEV_EVENT_WRITING
1
一個bufferevent發送了寫操做,用來查看哪個event發送了寫操做
BEV_EVENT_ERROR
1
當發送了一個error的時候這個標誌就會被標記起來,能夠經過EVUTIL_SOCKET_ERROR函數來查看
BEV_EVENT_TIMEOUT
1
當bufferevent發送了超時
BEV_EVENT_EOF
1
獲得了一個EOF
BEV_EVENT_CONNECTED
1
該bufferevent的socket成爲ESTABLELISHED狀態
建立bufferevent的標誌
你可使用如下一個或者多個標記去建立一個bufferevent,如下這些值都是int類型
BEV_OPT_CLOSE_ON_FREE :當free的時候,底層傳輸的對象會被close
BEV_OPT_THREADSAFE : 自動的給這個bufferevent申請鎖,因此設置後bufferevent是線程安全的
BEV_OPT_DEFER_CALLBACKS:延遲callback
BEV_OPT_UNLOCK_CALLBACKS: 默認bufferevent是線程安全的,設置這個選項後不在線程安全
延遲callback
由於函數的調用都是在棧上,那麼bufferEvent就有可能,當輸入回調和輸出回調之間關係特別複雜時就有有可能在連續的互相調用下發生了棧溢出,因此咱們能夠設置延遲bufferevent的回調函數。這些被延遲的回調函數會被加入event_loop的隊列中,當全部的常規回調調用完畢後,就會調用它們
基於socket的bufferevent(建立一個基於socket的bufferevent)
v2.0.1
struct bufferevent * bufferevent_socket_new(
struct event_base * base,
evutil_socket_t fd,
int bufferevent_options options);
1
2
3
4
5
這個FD是一個可選的套接字文件描述符,並且這個套接字必須是非阻塞模式的套接字,若是這個參數咱們設置爲-1,表示稍後去設置這個文件描述符,options就是上面介紹的選項。
#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, 0, sizeof(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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
bufferevent_socket_connect 函數只在 v2.0.2之後有,以前只能手動connect ,若是這個鏈接成功,bufferevent會收到一個寫就緒。若是經過bufferevent_socket_connect發起鏈接就會收到BEV_EVENT_CONNECTED標誌。
使用本身connect的socket並給其綁定的bufferevent加上CONNECTED標誌
若是你本身想調用connect函數還想收到BEV_EVENT_CONNECTED標誌,你能夠先調用connect(成功調用才行),而後調用bufferevent_socket_connect(bev, NULL, 0)。
以域名的方式發起一個鏈接
常常,咱們都想把域名解析和鏈接合併成一個單獨的操做
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);
1
2
3
4
family指的是地址協議族,目前只支持AF_INET,AF_INET6,AF_UNSPEC。若是這個域名解析失敗,它會調用相應 bufferevent的回調函數,若是解析成功以bufferevent_connect的方式發起鏈接。若是失敗的話,咱們能夠經過bufferevent_socket_get_dns_error來得到錯誤碼。
若是dns_base參數爲空,那麼Libevent會阻塞式解析,這個確定不是咱們想要的,若是咱們提供參數那麼Libevent就會使用它異步的去解析。
/* 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(base, 1);
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
bufferEvent是基於引用計數的,因此當有未處理的延遲callback函數時,bufferevent不會當即釋放,直到這個回調函數調用完畢。若是咱們設置了BEV_OPT_CLOSE_ON_FREE 標誌,在free的同時也會close 掉 bufferEvent對應的fd。
設置bufferevent的callback、watermark、enabled operations
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); 1.4.4
void bufferevent_getcb(struct bufferevent *bufev,bufferevent_data_cb
*readcb_ptr,bufferevent_data_cb *writecb_ptr,bufferevent_event_cb
*eventcb_ptr,void **cbarg_ptr);2.1.1
1
2
3
4
5
6
7
8
9
bufferevent_setcb函數是用來設置buffferevent的回調函數的一個函數。其中readcb、writecb、event是讀就緒,寫就緒,event就緒(flag標誌條件就緒,flag標誌是上面提到的error\timeout\eof\connect事件) 的回調函數。其中cbarg參數被那三個函數共享,因此一旦改變三個函數都收影響,event_cb的short參數是bufferevent的flag標誌的集合。你能夠經過傳遞NULL來表示你關閉了相應的回調函數,以此來表示你不關心相應的事件。
其實咱們給bufferevent設置的回調函數並非註冊到了其event上,bufferevent其實底層封裝了一層event,它有本身的callback函數。咱們設置的callback函數只是根據底層event的相應反映而調用的。
注意當有錯誤發生了,就觸發event回調函數,這個時候若是由於read操做觸發的錯誤,那麼read功能就會被關閉,由於write觸發的錯誤write功能就會被關閉。
bufferevent的讀寫功能的開啓與關閉
咱們能夠經過EV_READ,EV_WRITE或EV_READ|EV_WRITE去開啓或者關閉一個bufferevent的讀寫功能。當讀或者寫功能關閉了,這個bufferevent將不會再嘗試去讀或者寫在fd上。
當bufferevent的輸出緩衝區爲空的時候,咱們不須要主動的去關閉寫功能,這個時候它自動關閉寫功能而且當有數據到來時它會自動重啓,可是當寫緩衝區數據低於write-low-water的時候write-callback函數會被調用,這個時候寫緩衝區數據就會被填充而後再度開啓寫功能。寫入同理當輸入緩衝區的數據超過read-high-water的時候咱們也不用主動關閉讀功能,由於bufferevent會自動關閉讀功能,當有更多的空間的時候再開啓讀功能。默認的一個新建立的bufferevent是隻有寫功能沒有讀功能的,你能夠主動調用打開讀功能。
開啓或關閉讀寫功能
void bufferevent_enable(struct bufferevent * bufev,short events);
void bufferevent_disable(struct bufferevent * bufev,short events);
short bufferevent_get_enabled(struct bufferevent * bufev); //查看bev是否有開啓某些功能
1
2
3
開啓或關閉一個選項至關於在bufev對應的event_base中註冊或者刪除一個相應的event事件,若是EV_READ|EV_WRITE都關閉了且該event_base只註冊了bufferevent,那麼循環會終止已經沒有註冊的事件。
當咱們enable一個選項的時候,這個EV_READ 或者 EV_WRITE 是以持久化的形式(EV_PERSIST)的形式註冊到了其相應的event_base中。
設置水位線
水位線的設置根據標誌所決定以下所示
EV_READ 表示設置讀水位線
EV_WRITE 表示設置寫水位線
EV_READ | EV_WRTE 表示設置讀和寫的水位線
若是咱們設置highmark爲0就是表示不限制高水位線
void bufferevent_setwatermark(struct bufferevent * bufev,short events,
size_t lowmark,size_t highmark); 1.4.4
1
2
設置水位線demo
#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, 128, 0);
bufferevent_setcb(b1, read_callback, NULL, event_callback, info1);
bufferevent_enable(b1, EV_READ); /* Start reading. */
return b1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
如何使用bufferevent去讀寫網絡數據
上層應用都是在輸入緩衝區中讀取數據,在輸出緩衝區中寫入數據,因此輸入緩衝區數據應該愈來愈少,輸出緩衝區數據應該愈來愈多。當輸出緩衝區爲空的時候,bufferevent自動中止寫入功能,輸入緩衝區數據大於高水位線的時候自動中止讀功能,當數據量恢復正常的時候,它們也恢復正常,這些就是讀寫的一些機制。下面介紹返回倆個緩衝區的接口
struct evbuffer *bufferevent_get_input(struct bufferevent *bufev);
struct evbuffer *bufferevent_get_output(struct bufferevent *bufev);
1
2
struct evbuffer 就是具體的緩衝區的類型。那麼咱們能夠經過這個結構體來跟bufferevent來進行數據交互,下面是數據交互的接口
int bufferevent_write(struct bufferevent *Dstbufev,
const void *Srcdata, size_t size);
int bufferevent_write_buffer(struct bufferevent *Dstbufev,
struct evbuffer *Srcbuf);
size_t bufferevent_read(struct bufferevent *Srcbufev, void *DstData,
size_t size);
int bufferevent_read_buffer(struct bufferevent *SrcBufev,
struct evbuffer *DstBuf);
1
2
3
4
5
6
7
8
write類的函數都是把用戶緩衝區的數據添加到OutPut 的緩衝區中的末尾。read類的函數都是把相應bufferevent中的數據移動到用戶的緩衝區中,若是InPut緩衝區數據爲0則函數返回0。
write操做的注意點
若是咱們調用bufferevent_write函數的時候往寫緩衝區中寫數據了,可是寫的數據過少的時候,write 操做就會把寫緩衝區內的全部數據都發送出去,這個時候寫緩衝區空了就會觸發寫緩衝區的回調函數補充數據,write操做又由於寫緩衝區內又數據再次搬移,這個時候就會形成死循環
讀寫交互demo
#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 *c = 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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
bufferevent 的超時機制
咱們能夠設置一個timeout的時機,若是這個時間都超時了,bufferevent都沒有進行相應的read/write操做,那麼就會觸發這個bufferevent的callback函數,而且會設置下面的標誌
BEV_EVENT_TIMEOUT|BEV_EVENT_READING
或者
BEV_EVENT_TIMEOUT|BEV_EVENT_WRITING
1
2
3
timeout機制生效的前提下是bufferevent沒有關閉相應的read/write的功能。若是bufferevent關閉了read功能或者 Input緩衝區超過了high-water的時候,read-timeout失效。若是bufferevent關閉了write功能或者Output緩衝區空了的時候,write-timeout失效。失效後會觸發咱們設置的event回調函數,若是此時event_base 沒有進程EV_WRITE操做或者其餘的event事件則循環退出。
下面是設置超時的接口函數:
void bufferevent_set_timeouts(struct bufferevent *bufev,
const struct timeval *timeout_read, const struct timeval *timeout_write);
v2.0.4 纔在各個bufferevent類型中表現一致
1
2
3
注意當給EV_READ添加超時事件,當超時觸發後底層就進行read操做,這個時候若是socket沒有數據就會阻塞住,因此得設置該socket爲非阻塞socket,若是非阻塞socket那麼該bufferevent會再次被調度
其次這個超時真的很雞肋,若是超時事件觸發的同時EV_READ|EV_WRITE事件也觸發了,那麼該read / write 操做正常進行,若是沒有隻有timeout事件觸發了當作異常處理,會調用event 回調函數,也就是說咱們給 readcb 設置一個timeout,若是超時了卻調用的是eventcb 這是十分不合理的。
刷新bufferevent
int bufferevent_flush(struct bufferevent *bufev,
short iotype, enum bufferevent_flush_mode state);
-1 : 失敗
0 : 無數據可刷
1 : 成功刷了一些數據
1
2
3
4
5
iotype:EV_READ, EV_WRITE, or EV_READ|EV_WRITE
state : BEV_NORMAL, BEV_FLUSH, or BEV_FINISHED
FIN就像 tcp的fin段同樣,它給告訴對端Libevent別發送數據了。當咱們使用刷新的時候,數據就會被強制的進行 read / write操做。一個很重要的是,這個函數不支持 socket類型的bufferevent。
特定類型的bufferevent的操縱函數
下面四個函數,前三個只針對 socket類型的bufferevent。這些函數能夠設置優先級和設置fd。
int bufferevent_priority_set(struct bufferevent *bufev, int pri);
int bufferevent_get_priority(struct bufferevent *bufev); v2.1.2
int bufferevent_setfd(struct bufferevent *bufev, evutil_socket_t fd);
evutil_socket_t bufferevent_getfd(struct bufferevent *bufev); 2.0.2
struct event_base *bufferevent_get_base(struct bufferevent *bev); 2.0.9
struct bufferevent *bufferevent_get_underlying(struct bufferevent *bufev);
2.0.2
1
2
3
4
5
6
7
bufferevent 的lock函數
因爲輸入輸出緩衝區的存在,有的時候咱們想操縱bufferevent的時候是具備原子性的,那麼咱們可使用Libevent給咱們提供的專門針對於 bufferevent的加鎖函數
void bufferevent_lock(struct bufferevent * bufev); void bufferevent_unlock(struct bufferevent * bufev); 12 第一個函數,若是咱們已經給一個bufferevent加了鎖再次調用也是安全的。第二個函數,咱們只能解鎖一次,不然出錯。若是沒有設置BEV_OPT_THREADSAFE選項,調這個函數沒有什麼影響--------------------- 做者:sdoyuxuan 來源:CSDN 原文:https://blog.csdn.net/sdoyuxuan/article/details/81634047 版權聲明:本文爲博主原創文章,轉載請附上博文連接!