记录 Libevent的常用功能示例

2023-11-05

介绍

Libevent是开源社区一款高性能的I/O框架库,是reactor模式的优秀体现。网上相关资料很多,这篇博文主要以尽量简练的代码实现TcpServer服务器功能,代码覆盖大部分的常用函数接口。通过代码能对Libevent的整体框架,函数使用有直观的理解,配置好Libevent库的前提下,下方代码可直接复制运行。

代码

#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <thread>
#include <unordered_map>
#include <utility>
#include <signal.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>

//读取客户端
void do_read(evutil_socket_t fd, short event, void *arg) 
{
	printf("do_read! fd=%d threadid=%d ", fd, std::this_thread::get_id());

	//继续等待接收数据  
	char buf[1024] = {0};    
	int len = recv(fd, buf, 1024, 0);
	if (len > 0) 
	{
		printf("data=%s\n", buf);
		send(fd, buf, len, 0); 
	}
	else if (len == 0)
	{
		printf("client close\n");
		struct event *ev = (struct event *)arg;
		event_free(ev);
		closesocket(fd);
	}
}

void read_cb(struct bufferevent *bev, void *arg)
{
	evutil_socket_t fd = bufferevent_getfd(bev);
	evbuffer *evBuf = bufferevent_get_input(bev);
	int size = evbuffer_get_length(evBuf);

	char data[128] = {0};
	int len = evbuffer_remove(evBuf, data, size);
	printf("read_cb fd=%d threadid=%d size=%d data=%s\n", fd, std::this_thread::get_id(), size, data);

	send(fd, data, len, 0);
}

void write_cb(struct bufferevent *bev, void *arg)
{

}

void error_cb(struct bufferevent *bev, short event, void *arg)
{
	evutil_socket_t fd = bufferevent_getfd(bev);
	printf("fd = %d, ", fd);

	if (event & BEV_EVENT_TIMEOUT)
		printf("Timed out\n");
	else if (event & BEV_EVENT_EOF)
		printf("Connection closed\n");
	else if (event & BEV_EVENT_ERROR)
		printf("Other error\n");

	bufferevent_free(bev);
}

//回调函数,用于监听连接进来的客户端socket
void do_accept(evutil_socket_t fd, short event, void *arg) 
{   
	struct sockaddr_in client_addr; //客户端网络地址结构体   
	int in_size = sizeof(struct sockaddr_in);

	//客户端socket  
	int client_socketfd = accept(fd, (struct sockaddr *) &client_addr, &in_size); //等待接受请求,这边是阻塞式的  
	if (client_socketfd < 0) 
	{
		puts("accpet error");
		exit(1);
	}

	printf("do_accept! fd=%d threadid=%d\n", client_socketfd, std::this_thread::get_id());

	//类型转换
	struct event_base *base_ev = (struct event_base *)arg;

	//socket发送欢迎信息  
	char msg[] = "Welcome to Connect!";
	int size = send(client_socketfd, msg, strlen(msg), 0);

	//创建一个事件,这个事件主要用于监听和读取客户端传递过来的数据 持久类型
#if 0
	struct event *ev = event_new(base_ev, client_socketfd, EV_TIMEOUT | EV_READ | EV_PERSIST, do_read, event_self_cbarg());
	event_add(ev, NULL);
#else
	struct bufferevent *bev = bufferevent_socket_new(base_ev, client_socketfd, BEV_OPT_CLOSE_ON_FREE);
	bufferevent_setcb(bev, read_cb, NULL, error_cb, base_ev);
	bufferevent_enable(bev, EV_READ | EV_WRITE | EV_PERSIST);
	bufferevent_setwatermark(bev, EV_READ, 0, 0);
#endif

}

void signal_cb(evutil_socket_t fd, short event, void *arg)
{
	struct event *signal = (struct event *)arg;

	printf("signal_cb: got signal %d\n", event_get_signal(signal));
	event_del(signal);

	event_base_loopbreak(event_get_base(signal));
}

int main(int argc, char **argv)
{
	//初始化windows socket库
	WORD wVersionRequested = MAKEWORD(2, 2);
	WSADATA wsa_data;
	WSAStartup(0x0201, &wsa_data);
 
	struct sockaddr_in server_addr;   //服务器网络地址结构体    
	memset(&server_addr, 0, sizeof(server_addr)); //数据初始化--清零    
	server_addr.sin_family = AF_INET; //设置为IP通信    
	server_addr.sin_addr.s_addr = INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上    
	server_addr.sin_port = htons(8888); //服务器端口号    

	//创建服务端套接字  
	int server_socketfd = socket(PF_INET, SOCK_STREAM, 0);
	if (server_socketfd < 0) 
	{
		puts("socket error");
		return 0;
	}

	evutil_make_listen_socket_reuseable(server_socketfd); //设置端口重用
	evutil_make_socket_nonblocking(server_socketfd); //设置无阻塞

	//绑定IP  
	if (bind(server_socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0) 
	{
		puts("bind error");
		return 0;
	}

	//监听 监听队列长度  
	listen(server_socketfd, 10);

	printf("Server Start! main threadid=%d\n", std::this_thread::get_id());

	auto func = [=]() 
	{
		//创建event_base 事件的集合,多线程的话 每个线程都要初始化一个event_base
		struct event_base *base_ev = event_base_new();

		//创建一个事件,类型为持久性EV_PERSIST,回调函数为do_accept(主要用于监听连接进来的客户端)
		//将base_ev传递到do_accept中的arg参数
		struct event *ev = event_new(base_ev, server_socketfd, EV_TIMEOUT | EV_READ | EV_PERSIST, do_accept, base_ev);
		event_add(ev, NULL);

		//信号事件
		struct event *signal_int = evsignal_new(base_ev, SIGINT, signal_cb, event_self_cbarg());
		event_add(signal_int, NULL);

		//事件循环
		event_base_dispatch(base_ev);
		//销毁event_base
		event_base_free(base_ev);
	};

	std::thread thread(func);
	thread.join();

	printf("Server Stop\n");
	WSACleanup();

	getchar();
	return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

记录 Libevent的常用功能示例 的相关文章

  • 无捕获 lambda 是结构类型吗?

    P1907R1 http www open std org jtc1 sc22 wg21 docs papers 2019 p1907r1 html 接受 C 20 引入结构类型 它们是非类型模板参数的有效类型 GCC 和 Clang 都接
  • TPL Dataflow如何删除块之间的链接

    我想知道 如何删除块之间的链接 换句话说 我想要与 LinkTo 相反 我想写一个基于 tlp 数据流的记录器 我编写了这个接口 并希望在需要时删除 ILogListener 的订阅 public interface ILogManager
  • 我应该如何以非 root 身份读取 Linux 上的 Intel PCI 非核心性能计数器?

    我想要一个库 允许对 Linux 可执行文件的关键部分进行 自我分析 就像人们可以使用一个部分计时一样获取当日时间 http linux die net man 2 gettimeofday or RDTSC http www strchr
  • 从值获取键 - Dictionary>

    我无法通过指定值来获取密钥 我实现这一目标的最佳方法是什么 var st1 new List
  • 未定义的参考错误 - rand

    我正在创建一个命令行 C 测试应用程序 可执行 以便在我的 root Android 设备上运行 该可执行文件使用多个预构建的 C 库 其中之一使用 rand 在链接状态期间我收到错误 rand 的未定义引用 为了检查路径是否设置正确 我尝
  • 获取在 Unity 中实现接口的所有类型

    如果您只想知道解决方案 请跳至更新 我有一个应用程序 它使用以下代码来获取并运行许多工作方法 var type typeof IJob var types AppDomain CurrentDomain GetAssemblies Sele
  • C# 中具有字符串键类型的不区分大小写字典

    如果我有一个Dictionary
  • PostgreSQL:42883 运算符不存在:没有时区的时间戳 = 文本

    我正在使用 Npgsql 3 0 3 0 和 PetaPoco 最新版本 当我运行这个命令时 var dateCreated DateTime Now just an example var sql new Sql WHERE date c
  • unique_ptr需要存储删除器怎么可能没有开销呢?

    先看看C Primer讲了什么unique ptr and shared ptr 16 1 6 美元 效率和灵活性 我们可以确定的是shared ptr不将删除者视为直接成员 因为删除器的类型直到运行时才知道 因为删除器的类型是a类型的一部
  • 安全地检查“this”是否为空

    首先 我知道在空指针上调用方法是未定义的行为 我还知道 因为这不应该发生 编译器可以 并且确实 假设this始终为非空 但在实际代码中 有时您会不小心这样做 通常 它没有任何不良影响 当然除了this方法中为 null 并且事情可能会崩溃
  • 检查文件是真实文件还是符号链接

    有没有办法使用 C 来判断文件是真实文件还是符号链接 我已经挖过了MSDN W32 文档 https learn microsoft com en us windows win32 fileio file management functi
  • SQL 选择与带有通配符的 URL 匹配的行

    我在数据库中有一个表 其中一列包含一个 URL 例如http example com users http example com users 轮廓 我得到了一个 URL 例如http example com users 234 profi
  • 根据值更改 DataGrid 单元格颜色

    我有一个 WPF 数据网格 我想要根据值使用不同的单元格颜色 我的 xaml 上有以下代码 Style TargetType DataGridCell 但不是只选择一个单元格而是选择所有行 我缺少什么 如果您尝试设置DataGrid Cel
  • Err_Response_Headers_Multiple_Content_Disposition

    我需要导出 2csv单击一个按钮即可打开文件 下面是我生成2的代码csv files using System Data using System Data SqlClient using System Text using System
  • C# 如何在没有 GacUtil 的情况下在 GAC 中注册程序集?

    我需要使用批处理文件在 GAC 中注册程序集 有没有办法找到安装位置GacUtil exe或者有没有办法在没有 GacUtil 的情况下注册程序集 Your bestbet is to use a powershell script tha
  • const int 列表而不是 enum

    我开始研究大型 C 代码库 并发现使用带有多个 const ints 字段的静态类 这个类的行为与枚举完全一样 我想将类转换为实际的枚举 但权力被拒绝 我想转换它的主要原因是这样我可以将枚举作为数据类型而不是 int 这对可读性有很大帮助
  • std::regex 的行为不一致

    我有以下问题 std regex如果我传递结果 行为会有所不同boost filesystem path string vs 将结果存储在中间字符串变量中 第一个将返回一个被截断的匹配 并且稍后不被接受std stoull 抛出 inval
  • 我如何错误地使用 C 中的 round() 函数?

    我从中得到了意想不到的结果round and roundf 中的函数math h图书馆 这是示例代码 include
  • 什么时候适合在 C++ 中使用 static(在未命名的命名空间上)?

    我一整天都在阅读有关未命名命名空间的文章 大多数文章都解释了何时应该在 static 关键字上使用未命名命名空间 但我仍然有一个大问题什么时候适合使用静态 毕竟它还没有完全弃用 那么带有静态函数的头文件我现在应该将它们放入未命名的命名空间中
  • 使用抽象类作为模板类型

    我对c 还是很陌生 来自java 我有一个 stl 类型列表Actor When Actor仅包含 真实 方法就没有问题 我现在想将这个类扩展到几个类 并且需要将一些方法更改为抽象的 因为它们不再具有具体的意义 正如我 从文档中 预期的那样

随机推荐

  • ubuntu c语言头文件,Ubuntu找不到stdio.h等头文件_安装c库_build-essential安装失败解决...

    最近安装的Ubuntu1804系统 vim gcc都是现安的 用gcc编译时出现找不到头文件情况 于是百度 原来linux类的操作系统上面开发程序 光有了gcc 是不行的 它还需要一个 build essentia 作用是提供编译程序必须软
  • 【无标题】torch.optim.SGD参数详解

    torch optim SGD是PyTorch中实现的Stochastic Gradient Descent SGD 优化器 用于更新神经网络中的参数 以最小化损失函数 从而提高模型的精度 它的一些重要参数如下 lr 学习率 learnin
  • office文档图标显示不正常

    一直用Office2013 前几天用到WPS一个功能 用完后就卸载了 结果电脑中的office文档图标 word excel ppt等 都显示异常 网上查找好久解决了 网址如下 https jingyan baidu com article
  • target_link_libraries 和link_libraries区别

    TARGET LINK LIBRARIES 设置要链接的库文件的名称 语法 TARGET LINK LIBRARIES targetlibrary1
  • 数据结构--并查集

    并查集适用情况 1 有时候 并不关心数据之间的前后关系 也不关心数据的层次关系 一些确定元素只是单纯的聚集在一起 这样的元素聚集集合被称为集合 当希望知道某个数据是否存在一个集合中 或者两个元素是否在同一个集合中时 就需要使用一些集合数据结
  • windows 安装NVM 出现版本切换不成功 问题解决与分析

    1 安装nvm的时候要去删除默认目录下C Program Files nodejs的文件夹 安装完成后也要去检查这个文件夹是不是存在 2 配置环境变量 对应第一步的 2 使用nvm install 版本号 如果能成功下载node 注意说的成
  • FFmpeg部署及操作指南

    什么是FFmpeg FFmpeg是一个开源的跨平台音视频处理工具集 可以用于处理 转换 编辑和流媒体音视频文件 它提供了一组强大的命令行工具 可以实现音视频的解码 编码 封装 过滤 转码等功能 FFmpeg的功能 FFmpeg的功能非常多
  • matlab分类算法函数,MATLAB分类与预测算法函数

    1 glmfit 功能 构建一个广义线性回归模型 使用格式 b glmfit X y distr 根据属性数据X以及每个记录对应的类别数据y构建一个线性回归模型 distr可取值为 binomial gamma inverse gaussi
  • C#系列之值类型与引用类型

    目录 1 变量类型的复习 2 值类型和引用类型的区别 1 变量类型的复习 无符号整形 byte b 1 ushort us 1 uint ui 1 ulong ul 1 有符号整形 sbyte sb 1 short s 1 int i 1
  • LINUX下更改字符编码方式-增加GB2312

    修改local文件 sudo gedit var lib locales supported d local 添加zh CN GB2312字符集 如下 en US UTF 8 UTF 8 zh CN UTF 8 UTF 8 zh CN GB
  • 推荐几个 VS Code 扩展、主题和字体

    前言 工欲善其事 必先利其器 VS Code 作为当前最流行的开源代码编辑器之一 要说它为什么这么受大众喜爱 我觉得一是它现代化的界面 二是它强大的扩展系统 得益于 VS Code 的扩展系统 我们可以给编辑器加上各种 Buff 让它变成自
  • 深度学习经典网络:ShuffleNet 系列网络(ShuffleNet v1)

    ShuffleNet v1 http openaccess thecvf com content cvpr 2018 html Zhang ShuffleNet An Extremely CVPR 2018 paper html tenso
  • 第十四届蓝桥杯模拟赛第二期J题答案(C++代码)

    A题 题面 请找到一个大于 2022 的最小数 这个数转换成二进制之后 最低的 6 个二进制为全为 0 请将这个数的十进制形式作为答案提交 思路 由于最低6位都是0 且 11111000000 2 lt 2048 10 所以选要选取 100
  • 让vs2008与vs2012同时打开同一个项目文件

    在开发过程中 小组开发经常碰到很多人用的ide版本不同 而项目组成员为了参与多个项目 经常安装多个版本的ide 本文主要讲解vs2008与vs2012之间如何在源码管理下同时打开一个项目文件进行开发 本文以c 开发为例 其他语言一样 1 关
  • 并发编程 :Concurrent 用户指南 ( 下 )

    并发编程 Concurrent 用户指南 下 2017 09 04 ImportNew 来源 高广超 www jianshu com p 8cb5d816cb69 锁 Lock java util concurrent locks Lock
  • gradlew 命令说明

    gradlew 命令 快速构建命令 查看所有任务 gradlew tasks all gradlew命令都可以使用简写 例如 gradlew assembleRelease 简写为 gradlew aR 查看项目的依赖都依赖了哪些库 gra
  • Android 3.0 SDK中新增API详解

    Android 3 0 SDK中新增了哪些API呢 我们总结下平板系统honeycomb中的新特性 首先需要澄清的是经过eoeAndroid发现设置模拟器的分辨率到普通WVGA这样的解析度时平板的特性自动消失和Android 2 3没有什么
  • Pytorch 随机种子设置 不可控因素

    为确保模型训练过程中 需要设置模型的随机种子 具体操作如下 主程序 def torch seed seed torch manual seed seed torch cuda manual seed seed torch cuda manu
  • redis三个连接客户端框架的选择:Jedis,Redisson,Lettuce

    Jedis api 在线网址 http tool oschina net uploads apidocs redis clients jedis Jedis html redisson 官网地址 https redisson org red
  • 记录 Libevent的常用功能示例

    介绍 Libevent是开源社区一款高性能的I O框架库 是reactor模式的优秀体现 网上相关资料很多 这篇博文主要以尽量简练的代码实现TcpServer服务器功能 代码覆盖大部分的常用函数接口 通过代码能对Libevent的整体框架