bufferevent中提供了對讀寫回調的觸發條件及最大緩存長度的設置,即低高水位:
- 低水位:是讀寫回調函數的最低觸發數據長度,當輸入/輸出緩存區中的數據長度小於低水位時,讀/寫回調函數不會被觸發;
- 高水位:是緩存區的最大接收長度,當輸入/輸出緩存區中的數據長度大於高水位時,不會繼續向緩存區中增加數據。
水位設置函數bufferevent_setwatermark
void bufferevent_setwatermark (struct bufferevent *bufev, short events, size_t lowmark, size_t highmark)
該函數能夠為一個給定的bufferevent設置指定事件的低高水位。若events為EV_READ則為設置讀回調函數的水位;events為EV_WRITE則為設置寫回調函數的水位,
Demo
服務端:在創建了與客戶端連接的bufferevent后,設置低水位為6,高水位為10。
//server.c
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <malloc.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <event2/buffer.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
// 讀緩沖區回調
void read_cb(struct bufferevent *bev, void *arg)
{
char buf[1024] = {0};
bufferevent_read(bev, buf, sizeof(buf));
//這里不能直接輸出字符串
for(int i = 0; i < 20; ++i)
{
printf("%c", buf[i]);
}
printf("\n");
}
void cb_listener(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *addr, int len, void *ptr){
struct sockaddr_in *addr_in = (struct socketaddr*)addr;
printf("connect new client from: %s\n", inet_ntoa(addr_in->sin_addr));
struct event_base* base = (struct event_base*)ptr;
// 通信操作
// 添加新事件
struct bufferevent *bev;
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
// 給bufferevent緩沖區設置回調
bufferevent_setcb(bev, read_cb, NULL, NULL, NULL);
bufferevent_enable(bev, EV_READ);
bufferevent_enable(bev, EV_WRITE);
//設置讀寫的高低水位
bufferevent_setwatermark(bev, EV_READ|EV_WRITE, 6, 10);
}
int main(int argc, const char* argv[])
{
// init server
struct sockaddr_in serv;
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(9995);
serv.sin_addr.s_addr = htonl(INADDR_ANY);
struct event_base* base;
base = event_base_new();
// 創建套接字
// 綁定
// 接收連接請求
struct evconnlistener* listener;
listener = evconnlistener_new_bind(base, cb_listener, base,
LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
36, (struct sockaddr*)&serv, sizeof(serv));
event_base_dispatch(base);
evconnlistener_free(listener);
event_base_free(base);
return 0;
}
客戶端:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>
void send_cb(evutil_socket_t fd, short what, void *arg)
{
char buf[1024] = {0};
struct bufferevent* bev = (struct bufferevent*)arg;
read(fd, buf, sizeof(buf));
bufferevent_write(bev, buf, strlen(buf)+1);
}
int main(int argc, const char* argv[])
{
struct event_base* base;
base = event_base_new();
struct bufferevent* bev;
bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
// 連接服務器
struct sockaddr_in serv;
memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_port = htons(9995);
evutil_inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));
// 設置回調
bufferevent_setcb(bev, read_cb, NULL, event_cb, NULL);
bufferevent_enable(bev, EV_READ | EV_PERSIST);
// 創建一個事件
struct event* ev = event_new(base, STDIN_FILENO,
EV_READ|EV_PERSIST, send_cb, bev);
event_add(ev, NULL);
event_base_dispatch(base);
event_base_free(base);
return 0;
}
客戶端發送數據:
sunminming@sunminming:~/libevent/watermask$ ./client
服務器已連接
a
qwertyuio
服務器接收的數據:
sunminming@sunminming:~/libevent/watermask$ ./server
connect new client from: 127.0.0.1
a
qwertyu
我們從客戶端一共發送了兩次信息,第一次發送3個字符:'a','\n','\0';第二次發送11個字符'q','w','e','r','t','y','u','i','o','\n','\0')。
因此,讀回調函數輸出的前10個字符應該為:'a','\n','\0','q','w','e','r','t','y','u';之后還輸出了10個buf數組中原本就存在的'\0';最后輸出換行符。