文章目录
- 1. bufferevent_filter过滤器简介
- 2. evbuffer
- 2.1 evbuffer常用API
- 2.2 evbuffer和bufferevent的区别
- 3. bufferevent filter过滤器常用API
- 3.1 bufferevent_filter_new()
- 4 bufferevent filter 过滤器例子
1. bufferevent_filter过滤器简介
bufferevent filter
是libevent库提供的一个功能,可以通过添加filter对输入或输出数据进行转换和过滤,可以在 读取前和写入后对数据进行一系列的预处理操作。
bufferevent filter
是一种包装另一个bufferevent的方式,它提供了两个回调函数:readcb和writecb。这些回调函数可以在读取或写入数据之前或之后对数据进行处理。例如,可以使用bufferevent filter将所有传入数据转换为大写字母,并将其发送到底层bufferevent中。
使用bufferevent filter
进行数据过滤的流程如下:
- 创建底层
bufferevent
:首先需要创建一个底层的bufferevent
,用于接收和发送原始数据。 - 创建
filter bufferevent
并包装:然后需要创建一个filter bufferevent
,并将其包装在底层bufferevent
的外部。这样,在数据从网络中读取到内存或从内存写入到网络之前,都会经过filter bufferevent
的处理。 - 设置回调函数:接着需要设置
filter bufferevent
的readcb
和writecb
回调函数。这些回调函数可以根据需要对输入或输出数据进行转换或过滤。 - 接收数据:当有新的数据到达时,底层
buffereven
t会调用readcb
回调函数,并将数据传递给filter bufferevent
。filter bufferevent
可以在此处对数据进行处理,例如解密、解压缩、分割等操作。 - 发送数据:当应用程序调用
bufferevent_write
发送数据时,底层bufferevent
会调用writecb
回调函数,并将数据传递给filter bufferevent
。filterbufferevent
可以在此处对数据进行处理,例如加密、压缩、拼接等操作。 - 写入底层
bufferevent
:最后,filter bufferevent
将处理后的数据写入底层bufferevent
中,并返回处理后的数据长度。底层bufferevent
会将数据发送到网络中。
需要注意的是,如果底层bufferevent
关闭,filter bufferevent
也会关闭。因此,需要适当处理错误和清理资源。
2. evbuffer
evbuffer
是libevent库中用于缓存数据的结构体,它提供了一个高效的、可扩展的缓冲区,用于处理网络数据或文件I/O等场景中的读写操作。
evbuffer
可以简单地理解为一个可变大小的byte数组,它支持以下常见的操作:
- 读写数据:
evbuffer
支持从缓冲区中读取和向缓冲区中写入数据,可以通过**evbuffer_add
、evbuffer_prepend、evbuffer_remove
**等函数来实现。 - 复制数据:
evbuffer
支持将缓冲区中的数据复制到另一个缓冲区中,可以通过evbuffer_add_buffer、evbuffer_prepend_buffer等函数来实现。 - 查找数据:
evbuffer
支持在缓冲区中查找指定的数据,可以使用evbuffer_search、evbuffer_find等函数来实现。 - 调整大小:
evbuffer
支持动态调整缓冲区的大小,可以使用evbuffer_expand、evbuffer_reserve_space等函数来实现。 - 异步通知:
evbuffer
支持异步通知机制,在缓冲区满或空时可以触发特定的回调函数,以便应用程序进行相应的处理。
总之,evbuffer
是bufferevent 上发送或接收的数据,其实这个结构体就是在 filter bufferevent 和 underlying bufferevent 之间传递数据用的。
2.1 evbuffer常用API
/**
* @breif: 添加数据到 evbuffer 的结尾处
*
* @param buf: 待添加数据的 evbuffer 对象
* @param data: 数据指针
* @param datlen: 数据长度,单位 byte
*
* @return: 成功返回0,失败返回-1
*/
int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen);
/**
* @brief: 从 evbuffer 的开始处读取指定长度的数据
* 若 evbuffer 中的数据不足指定长度,则尽可能多的读取数据
*
* @param buf: 待读取数据的 evbuffer 对象
* @param data: 数据指针
* @param datlen: 数据长度,单位 byte
*
* @return: 成功返回读取的字节数,失败返回-1
*/
int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen);
简单来说,evbuffer_add 类似向队尾插入数据,evbuffer_remove 类似从队头读取数据。事实上它内部就是链表实现的
2.2 evbuffer和bufferevent的区别
evbuffer
和bufferevent
都是libevent库提供的数据处理相关的结构体,但它们的作用和使用方式有所不同。
-
evbuffer
是一个仅存储数据的缓冲区,不涉及网络、文件I/O等底层操作。evbuffer主要用于读取、写入和管理内存中的数据,并且具有高效的、可扩展的特点。 -
而
bufferevent
则是在evbuffer基础上封装了一系列网络或文件I/O操作,包括事件循环、socket连接、读写数据等。它可以方便地进行异步I/O操作,并且提供了事件通知机制,使得应用程序可以在特定事件发生时得到通知。
因此,evbuffer主要用于内存数据的读写操作,而bufferevent则主要用于网络或文件I/O操作的封装。同时,evbuffer常常与bufferevent配合使用,例如将bufferevent的输入输出数据先放入evbuffer中,再进行其他数据处理操作。
3. bufferevent filter过滤器常用API
3.1 bufferevent_filter_new()
bufferevent_filter_new()是libevent库中创建一个新的bufferevent filter的函数,用于将一个已有的bufferevent包装成一个新的filter bufferevent。该函数的定义如下:
struct bufferevent *
bufferevent_filter_new(struct bufferevent *underlying,
bufferevent_filter_cb input_filter,
bufferevent_filter_cb output_filter,
int options,
void (*free_context)(void *),
void *ctx);
其中参数说明如下:
underlying:指向要被包装的底层Bufferevent。
input_filter:输入数据过滤器函数,用于处理从底层Bufferevent读取到的数据。
output_filter:输出数据过滤器函数,用于处理发送到底层Bufferevent的数据。
options:BufferEvent的选项标志(例如BUFFEREVENT_SSL)。
free_context:释放上下文的函数指针。
ctx:过滤器的上下文信息。
回调函数原型
bufferevent_filter_result filter_in(evbuffer *s, evbuffer *d,
ev_ssize_t limit,
bufferevent_flush_mode mode, void *arg);
参数说明如下:
s:指向底层Bufferevent发送的数据的evbuffer指针。
d:指向Filter Bufferevent要处理的evbuffer指针。
limit:要复制的最大字节数。
mode:Flush模式(例如,如果为BEV_NORMAL,则立即刷新缓冲区)。
arg:传递给回调函数的参数。
filter_in()函数会处理从底层Bufferevent读取到的数据,并把处理后的数据放入Filter Bufferevent要处理的evbuffer中。
返回值类型为bufferevent_filter_result,表示数据过滤的结果。常见的结果包括:
BEV_OK:读取并处理了所有数据。
BEV_NEED_MORE:需要更多的数据才能完成操作。
BEV_ERROR:发生错误。
evbuffer *s
和evbuffer *d
都是指向evbuffer
类型的指针变量,但是它们所指向的缓冲区有所不同。
s
通常指向源缓冲区,表示从这个缓冲区读取数据。而d
通常指向目标缓冲区,表示将数据写入到这个缓冲区中。在数据过滤器函数中,通常会从源缓冲区读取一部分数据,并对其进行处理后再将其写入到目标缓冲区中。
4 bufferevent filter 过滤器例子
在输入过滤器中将客户端发送的数据转为大写,在输出过滤器中将发送给客户端的数据打上头尾标签。代码如下
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <string.h>
#include <iostream>
#ifndef _WIN32
#include <signal.h>
#else
#endif
#include <string>
using namespace std;
bufferevent_filter_result filter_in(evbuffer *s,evbuffer *d,ev_ssize_t limit,
bufferevent_flush_mode mode,void *arg)
{
cout<<"filter_in"<<endl;
char data[1024] = {0};
//读取并清理原数据
int len = evbuffer_remove(s, data, sizeof(data)-1);
//所有字母转成大写
for (int i = 0; i < len; ++i)
{
data[i] = toupper(data[i]);
}
evbuffer_add(d, data, len);
return BEV_OK;
}
bufferevent_filter_result filter_out(evbuffer *s,evbuffer *d,ev_ssize_t limit,
bufferevent_flush_mode mode,void *arg)
{
cout<<"filter_out"<<endl;
char data[1024] = {0};
//读取并清理原数据
int len = evbuffer_remove(s,data,sizeof(data)-1);
string str = "";
str += "================\n";
str += data;
str += "================\n";
evbuffer_add(d,str.c_str(),str.size());
return BEV_OK;
}
void read_cb(bufferevent*bev,void *arg)
{
cout<<"read_cb"<<endl;
char data[1024] = {0};
int len = bufferevent_read(bev,data,sizeof(data)-1);
cout<<data<<endl;
//回复客户消息,经过输出过滤
bufferevent_write(bev,data,len);
}
void write_cb(bufferevent*bev,void *arg)
{
cout<<"write_cb"<<endl;
}
void event_cb(bufferevent*bev,short events,void *arg)
{
cout<<"event_cb"<<endl;
}
void listen_cb(evconnlistener *ev,evutil_socket_t s,sockaddr*sin,int slen,void *arg)
{
event_base *base = (event_base*)arg;
cout << "listen_cb" << endl;
//创建bufferevent
bufferevent *bev = bufferevent_socket_new(base,s,BEV_OPT_CLOSE_ON_FREE);
//绑定bufferevent filter
bufferevent * bev_filter = bufferevent_filter_new(
bev, //指向要被包装的底层Bufferevent
filter_in,//输入过滤函数
filter_out,//输出过滤函数
BEV_OPT_CLOSE_ON_FREE, //关闭filter是同时关闭bufferevent
0, //清理的回调函数
0 //传递给回调的参数
);
//设置bufferevent的回调
bufferevent_setcb(bev_filter,read_cb,write_cb,event_cb,
NULL);//回调函数的参数
bufferevent_enable(bev_filter,EV_READ|EV_WRITE);
}
int main(int argc,char *argv[])
{
#ifdef _WIN32
//初始化socket库
WSADATA wsa;
WSAStartup(MAKEWORD(2,2),&wsa);
#else
//忽略管道信号,发送数据给已关闭的socket
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
return 1;
#endif
std::cout << "test server!\n";
//创建libevent的上下文
event_base * base = event_base_new();
if (base)
{
cout << "event_base_new success!" << endl;
}
//监听端口
//socket ,bind,listen 绑定事件
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(5001);
evconnlistener *ev = evconnlistener_new_bind(base, // libevent的上下文
listen_cb, //接收到连接的回调函数
base, //回调函数获取的参数 arg
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,//地址重用,evconnlistener关闭同时关闭socket
10, //连接队列大小,对应listen函数
(sockaddr*)&sin, //绑定的地址和端口
sizeof(sin)
);
//事件分发处理
if(base)
event_base_dispatch(base);
if(ev)
evconnlistener_free(ev);
if(base)
event_base_free(base);
return 0;
}