Libevent (15) bufferevent filter filter and examples

1. Brief description of bufferevent filter

Something like filter, I believe that programmers with experience in php framework or java springboot should be familiar with it, is a processor loaded before the input stream or after the output stream, which is used to separate from the business to do some extra things.

(1) The read (received) data first enters the filter, and then passes it to the user for reading after the filter is processed, that is, before the filter is read, for example, the compressed data must first be decompressed in the filter, and then in the underlying Read the decompressed original;
(2) The written (sent) data is initiated by the user, and then passed to the filter, and then sent out after the filter is processed, that is, after the filter is written, such as the original sent in the underlying The data will be compressed in the filter before sending.

二、bufferevent API

1、bufferevent_filter_new

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);

Callback function bufferevent_filter_cb:

/**
 * @brief: 回调函数,用于实现 bufferevent 的过滤器
 *
 * @param src: 源事件缓存
 * @param dst: 目的事件缓存
 * @param dst_limit: 写入 dst 的字节上限,-1表示无限制
 * @param mode: 数据刷新模式
 * @param ctx: 用户传递的参数
 *
 * @return: 返回过滤器的处理结果,详见后面说明
 */
typedef enum bufferevent_filter_result (*bufferevent_filter_cb)(
    struct evbuffer *src, struct evbuffer *dst, 
    ev_ssize_t dst_limit, enum bufferevent_flush_mode mode, void *ctx);

// filter 回调函数返回值
enum bufferevent_filter_result {
	// 正常
	BEV_OK = 0,
	// 还需要更多的数据才能输出
	BEV_NEED_MORE = 1,
	// filter 发生错误,无法进一步处理数据
	BEV_ERROR = 2
};

// filter 数据刷新模式
enum bufferevent_flush_mode {
	// 正常处理数据
	BEV_NORMAL = 0,
	// 检查发送的所有数据
	BEV_FLUSH = 1,
	// 读完或写完数据后,会有 EOF 标志
	BEV_FINISHED = 2
};

2. evbuffer structure

This structure is used to transfer data between filter bufferevent and underlying bufferevent.

(1) evbuffer is just a data buffer, implemented using a linked list, without any I/O operations.
(2) bufferevent is an event buffer I/O, which implements basic socket recv/send operations internally.

3、evbuffer_add 和 evbuffer_remove

/**
 * @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);

4. Examples

#include <iostream>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <thread>
#include <errno.h>
#include <string.h>
#ifndef _WIN32
#include <signal.h>
#else
#endif
using namespace std;
#define PORT 5001

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){
    cout<<"listen_cb "<<endl;
	//创建bufferevent 绑定bufferevent filter
	event_base *base = (event_base *)arg;
	bufferevent *bev = bufferevent_socket_new(base, s, BEV_OPT_CLOSE_ON_FREE);
	//绑定bufferevent filter
	bufferevent *bev_filter = bufferevent_filter_new(bev,
	    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
	WSADATA wsa;
	int a = WSAStartup(MAKEWORD(2, 2), &wsa);   
#else
	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
		return 1;
#endif
    event_base *base = event_base_new();
    //创建网络服务器
	
	//设置监听的端口和地址
	sockaddr_in sin;
	memset(&sin,0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	
	evconnlistener *ev = evconnlistener_new_bind(base,
	        listen_cb, //回调函数
			base, //回调函数的参数arg
			LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
			10, //listen back
			(sockaddr*)&sin,
			sizeof(sin)
			);
	
	//进入事件主循环
	event_base_dispatch(base);
	//释放资源
	evconnlistener_free(ev);
	event_base_free(base);
    return 0;
}

reference:

(1) libevent (12) bufferevent filter zlib compression communication (2)

(2) libevent high concurrent network programming - 03_bufferevent filter filter

(3) Libevent Learning Eleven: bufferevent filter filter and API

Guess you like

Origin blog.csdn.net/mars21/article/details/131414432