文章目录
- 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回调函数。这些回调函数可以根据需要对输入或输出数据进行转换或过滤。
- 接收数据:当有新的数据到达时,底层bufferevent会调用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;
}














![[JavaScript]JSON对象](https://img-blog.csdnimg.cn/923eff10c8ea4201b17ddd662b04442f.png)





