libevent高并发网络编程 - 03_bufferevent filter过滤器

news2024/11/27 1:21:19

文章目录

    • 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进行数据过滤的流程如下

  1. 创建底层bufferevent:首先需要创建一个底层的bufferevent,用于接收和发送原始数据。
  2. 创建filter bufferevent并包装:然后需要创建一个filter bufferevent,并将其包装在底层bufferevent的外部。这样,在数据从网络中读取到内存或从内存写入到网络之前,都会经过filter bufferevent的处理
  3. 设置回调函数:接着需要设置filter buffereventreadcbwritecb回调函数。这些回调函数可以根据需要对输入或输出数据进行转换或过滤。
  4. 接收数据:当有新的数据到达时,底层bufferevent会调用readcb回调函数,并将数据传递给filter buffereventfilter bufferevent可以在此处对数据进行处理,例如解密、解压缩、分割等操作。
  5. 发送数据:当应用程序调用bufferevent_write发送数据时,底层bufferevent会调用writecb回调函数,并将数据传递给filter bufferevent。filter bufferevent可以在此处对数据进行处理,例如加密、压缩、拼接等操作。
  6. 写入底层bufferevent:最后,filter bufferevent将处理后的数据写入底层bufferevent中,并返回处理后的数据长度。底层bufferevent会将数据发送到网络中。

需要注意的是,如果底层bufferevent关闭,filter bufferevent也会关闭。因此,需要适当处理错误和清理资源。

2. evbuffer

evbuffer是libevent库中用于缓存数据的结构体,它提供了一个高效的、可扩展的缓冲区,用于处理网络数据或文件I/O等场景中的读写操作。

evbuffer可以简单地理解为一个可变大小的byte数组,它支持以下常见的操作:

  1. 读写数据:evbuffer支持从缓冲区中读取和向缓冲区中写入数据,可以通过**evbuffer_add、evbuffer_prepend、evbuffer_remove**等函数来实现。
  2. 复制数据:evbuffer支持将缓冲区中的数据复制到另一个缓冲区中,可以通过evbuffer_add_buffer、evbuffer_prepend_buffer等函数来实现。
  3. 查找数据:evbuffer支持在缓冲区中查找指定的数据,可以使用evbuffer_search、evbuffer_find等函数来实现。
  4. 调整大小:evbuffer支持动态调整缓冲区的大小,可以使用evbuffer_expand、evbuffer_reserve_space等函数来实现。
  5. 异步通知: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的区别

evbufferbufferevent都是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 *sevbuffer *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;
}

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/525070.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

探索LeetCode【0010】正则表达式匹配(未懂)

目录 0.1 题目0.2 补充示例1. 参考B站视频2. 官方答案的评论-可用3. chatGPT的思路和解法-可用 0.1 题目 题目链接&#xff1a;【0010】正则表达式匹配 给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹…

UG NX二次开发(C++)-建模-删除对象

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1、前言2、在UG NX中创建一些测试对象3、查询这些对象的继承关系3、基于C创建的方法3.1 头文件3.2 声明删除对象的方法3.3 定义删除对象的方法3.4 填写调用代码 4、…

Vue电商项目--开发Search模块

Search模块的静态组件 search模块开发&#xff1f; 1.先静态页面静态组件拆分出来 2.发请求&#xff08;API&#xff09; 3.vuex&#xff08;三连环&#xff09; 4.组件获取仓库数据&#xff0c;动态展示数据 拆分静态组件&#xff0c;之前搞过。现在就不搞了&#xff0c;…

STL之迭代器

文章目录 什么是迭代器&#xff1f;迭代器的作用&#xff1a;为什么要使用迭代器&#xff1f;vector容器中迭代器应该怎么使用迭代器失效插入元素后失效删除元素后失效 什么是迭代器&#xff1f; 迭代器是一种检查容器内元素并且遍历容器内匀速的数据类型 迭代器的作用&#…

微服务之服务容错

Informal Essay By English Share a sentence that I think is very reasonable, as long as you can know the underlying logic of anything, you can hold it without fear 参考书籍&#xff1a; “凤凰架构” 引言 在 Martin Fowler 与 James Lewis合写的文章《Micros…

从立项到发布仅三个月,开源技术问答社区 Answer 是如何诞生的?

在祁宁家里&#xff0c;有一套完整的赛车模拟器&#xff0c;他甚至还请人到国外代购了最新的 VR 设备。作为沉浸式赛车游戏发烧友&#xff0c;除了享受速度与激情带来的愉悦感&#xff0c;祁宁在玩的过程中更多的是思考如何将技术能力进行产品化的问题。 Answer.dev 就是将技术…

【计网】第四章 网络层

文章目录 4.1-1 网络层概述4.1-2 SDN 的基本概念一、路由器功能&#xff1a;转发&#xff0c;路由选择二、数据平面三、控制平面介绍&#xff08;1&#xff09;传统方法/每路由器法&#xff08;2&#xff09;SDN 方法&#xff1a;Software-Defined Networking 四、控制平面中的…

一文掌握DTC

1. 前言 从单片机STM32开始转到汽车电子已经有一年时间了&#xff0c;到如今为止&#xff0c;很少写文章了&#xff0c;原因很简单&#xff0c;肚子里面没有墨水&#xff0c;就不给大家献丑了。而现在写在这篇文章&#xff0c;属实也是有了一定的了解。所以还不是很了解这个方…

从一到无穷大 #9 Firestore:开发者友好的Serverless NoSQL Database

引言 简单浏览了下ICDE 2023 industry-and-applications-track 部分的文章&#xff0c;其中我感兴趣的文章有三篇&#xff0c;分别为&#xff1a; Accelerating Cloud-Native Databases with Distributed PMem StoresBackward-Sort for Time Series in Apache IoTDBFirestore…

10年测开经验面试35K公司后,吐血整理出高频面试题和答案!

一&#xff1a;前言 在当今竞争激烈的职场环境中&#xff0c;拥有丰富的测试开发经验已成为众多企业青睐的重要条件之一。而在面试过程中&#xff0c;高频面试题更是能够考察应聘者的实际能力和知识水平。本文作者具备10年的测试开发经验&#xff0c;并通过面试获得了35K公司的…

VMWare16和Ubuntu20.04虚拟机安装记录

VMWare网盘链接&#xff1a;https://pan.baidu.com/s/1zZvtwnH9N47_k3pAy2dZCg 提取码&#xff1a;1234 Ubuntu下载网址&#xff1a;Ubuntu Release 推荐20.04&#xff0c;网上的教程也比较多 列举两个我参考的&#xff0c;其实都大差不差。 保姆级教程|VMware安装Ubuntu20…

Android之 activity活动页面详解

一 四大组件 1.1 Activity组件&#xff0c;它一个单独的窗口&#xff0c;程序流程都必须在Activity中运行&#xff0c;所有它是最基本的模块。 1.2 service组件&#xff0c;用于在后台完成用户指定的操作。 1.3 content provider组件&#xff0c;会为所有的应用准备一个内容…

线对象QgsLineString

几何对象中线用QgsLineString进行封装支持Z和M值&#xff0c;用于表示2维的&#xff0c;2. 5维的&#xff0c;3维的线线是由一串点连接而成 创建线 QgsLineString() #创建空的线QgsLineString(points: Iterable[QgsPoint]) #从一串QgsPoint创建QgsLineString(x: Iterable…

[JavaScript]JSON对象

eval函数 eval函数能将一个字符串当做一段JS代码解释并执行。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&quo…

大数据经典项目案列——滴滴数据分析(云服务器-零基础从配置到项目落地1)

本次我们项目采用阿里云服务器&#xff0c;采用以下技术及框架协议&#xff0c;进行数据分析&#xff1a; HDFSHiveSpark SQLZeppelin 当然我们也可以利用数据库清洗好的数据&#xff0c;采用 1.Tableau 2.Pythonechartsweb前端 3.腾讯云、阿里云BI报表 4.当然我们也可以采…

51单片机(十四)LCD1602

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

SpringCloud Alibaba 配置中心功能

一、快速入门 1、创建工程nacos-client7777 pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&q…

基于企业网的信息安全防护系统的设计与实现_kaic

摘 要 这篇文章提供了一种新的&#xff0c;基于“禁止一切”安全策略和VxD技术的企业网络安全保障方案&#xff0c;旨在帮助企业更好地应对外界的威胁。通过设计一套完善的企业网信息安全防护系统&#xff0c;不仅可以有效地解决企业网络中存在的问题&#xff0c;而且还可以有…

一文带你了解和掌握Markdown编辑神器mdnice

无论你是博客写作爱好者&#xff0c;还是想要自己动手开发一个网站&#xff0c;你都可能会接触到Markdown。Markdown是一种轻量级的标记语言&#xff0c;它允许人们使用易读易写的纯文本格式编写文档&#xff0c;然后转换成有效的HTML内容。然而&#xff0c;当你想要将你的Mark…

MYSQL主从复制和读写分离.2

搭建MYSQL读写分离 master :192.168.142.10 slave1:192.168.142.20 slave2:192.168.142.30 Amoeba:192.168.142.40 客户端:192.168.142.50 ----Amoeba服务器配置---- ##安装 Java 环境## 因为 Amoeba 基于是 jdk1.5 开发的&#xff0c;所以官方推荐使用 jdk1.5 或 1.6 版…