使用 libevent 构建高性能网络应用
使用 libevent 构建高性能网络应用
在现代网络编程中,高性能和可扩展性是开发者追求的核心目标。为了实现这一目标,许多开发者选择使用事件驱动库来管理 I/O 操作和事件处理。libevent 是一个轻量级、高性能的事件通知库,广泛应用于网络服务器、代理、缓存等场景。
本文将详细介绍 libevent 的核心概念、使用方法以及如何利用它构建高性能的网络应用。
1. 什么是 libevent?
libevent 是一个用 C 语言编写的事件驱动库,旨在提供一种高效的方式来处理 I/O 事件、定时器和信号。它的主要特点包括:
- 跨平台:支持 Linux、macOS、Windows 等多种操作系统。
- 高性能:基于操作系统提供的高效 I/O 多路复用机制(如
epoll、kqueue、IOCP等)。 - 易用性:提供了简洁的 API,方便开发者快速上手。
- 可扩展性:支持多种事件类型(如 I/O 事件、定时器事件、信号事件)。
libevent 被广泛应用于许多知名项目,如 Memcached、Tor 和 Chromium。
2. 安装 libevent
在开始使用 libevent 之前,需要先安装它。
在 Ubuntu 上安装
sudo apt-get install libevent-dev
在 macOS 上安装
brew install libevent
在 Windows 上安装
可以通过 vcpkg 安装:
vcpkg install libevent
3. 核心概念
事件循环(Event Loop)
libevent 的核心是事件循环(Event Loop),它负责监听和分发事件。事件循环会不断地检查是否有事件发生,并调用相应的回调函数进行处理。
事件(Event)
事件是 libevent 的基本单位,表示一个需要监听的操作。事件可以是以下几种类型:
- I/O 事件:如文件描述符可读或可写。
- 定时器事件:在指定时间后触发。
- 信号事件:当进程接收到特定信号时触发。
事件基(Event Base)
事件基是事件循环的核心结构,用于管理所有的事件。每个事件都需要与一个事件基关联。
4. 基本用法
初始化事件基
在使用 libevent 之前,需要先初始化一个事件基:
#include <event2/event.h>struct event_base *base = event_base_new();
if (!base) {fprintf(stderr, "Could not initialize libevent!\n");return 1;
}
创建事件
创建一个事件需要指定事件类型、文件描述符、回调函数以及回调函数的参数。例如,创建一个监听标准输入可读事件的事件:
#include <event2/event.h>
#include <stdio.h>void stdin_read_cb(evutil_socket_t fd, short events, void *arg) {char buf[1024];int len = read(fd, buf, sizeof(buf) - 1);if (len > 0) {buf[len] = '\0';printf("Read: %s\n", buf);} else {printf("EOF or error\n");event_base_loopexit((struct event_base *)arg, NULL);}
}int main() {struct event_base *base = event_base_new();if (!base) {fprintf(stderr, "Could not initialize libevent!\n");return 1;}struct event *ev = event_new(base, STDIN_FILENO, EV_READ | EV_PERSIST, stdin_read_cb, base);if (!ev) {fprintf(stderr, "Could not create event!\n");return 1;}event_add(ev, NULL);event_base_dispatch(base);event_free(ev);event_base_free(base);return 0;
}
运行事件循环
调用 event_base_dispatch 启动事件循环:
event_base_dispatch(base);
事件循环会一直运行,直到没有更多事件需要处理或调用 event_base_loopexit 退出。
5. 高级特性
定时器事件
libevent 支持创建定时器事件,在指定时间后触发回调函数。例如,创建一个 2 秒后触发的定时器:
#include <event2/event.h>
#include <stdio.h>void timer_cb(evutil_socket_t fd, short events, void *arg) {printf("Timer triggered!\n");
}int main() {struct event_base *base = event_base_new();if (!base) {fprintf(stderr, "Could not initialize libevent!\n");return 1;}struct event *ev = evtimer_new(base, timer_cb, NULL);if (!ev) {fprintf(stderr, "Could not create timer event!\n");return 1;}struct timeval tv = {2, 0};evtimer_add(ev, &tv);event_base_dispatch(base);event_free(ev);event_base_free(base);return 0;
}
信号事件
libevent 还支持监听信号事件。例如,监听 SIGINT 信号(Ctrl+C):
#include <event2/event.h>
#include <stdio.h>
#include <signal.h>void signal_cb(evutil_socket_t fd, short events, void *arg) {printf("Caught signal %d!\n", fd);event_base_loopexit((struct event_base *)arg, NULL);
}int main() {struct event_base *base = event_base_new();if (!base) {fprintf(stderr, "Could not initialize libevent!\n");return 1;}struct event *ev = evsignal_new(base, SIGINT, signal_cb, base);if (!ev) {fprintf(stderr, "Could not create signal event!\n");return 1;}event_add(ev, NULL);event_base_dispatch(base);event_free(ev);event_base_free(base);return 0;
}
6. 实际应用场景
高性能网络服务器
libevent 可以用于构建高性能的网络服务器。例如,使用 libevent 实现一个简单的 TCP 回显服务器:
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>void echo_read_cb(struct bufferevent *bev, void *ctx) {struct evbuffer *input = bufferevent_get_input(bev);struct evbuffer *output = bufferevent_get_output(bev);evbuffer_add_buffer(output, input);
}void echo_event_cb(struct bufferevent *bev, short events, void *ctx) {if (events & BEV_EVENT_ERROR) {perror("Error from bufferevent");}if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {bufferevent_free(bev);}
}void accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd,struct sockaddr *address, int socklen, void *ctx) {struct event_base *base = evconnlistener_get_base(listener);struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL);bufferevent_enable(bev, EV_READ | EV_WRITE);
}int main() {struct event_base *base = event_base_new();if (!base) {fprintf(stderr, "Could not initialize libevent!\n");return 1;}struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_port = htons(8080);struct evconnlistener *listener = evconnlistener_new_bind(base, accept_conn_cb, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1,(struct sockaddr *)&sin, sizeof(sin));if (!listener) {fprintf(stderr, "Could not create listener!\n");return 1;}event_base_dispatch(base);evconnlistener_free(listener);event_base_free(base);return 0;
}
7. 总结
libevent 是一个功能强大且易于使用的事件驱动库,适用于构建高性能的网络应用。通过它,开发者可以轻松管理 I/O 事件、定时器和信号,而无需关心底层平台的差异。
希望本文能帮助你快速上手 libevent,并将其应用到实际项目中。如果你有任何问题或建议,欢迎在评论区留言!
参考文档
- libevent 官方网站
- libevent GitHub 仓库
- libevent 官方文档
Happy coding! 🚀
相关文章:
使用 libevent 构建高性能网络应用
使用 libevent 构建高性能网络应用 在现代网络编程中,高性能和可扩展性是开发者追求的核心目标。为了实现这一目标,许多开发者选择使用事件驱动库来管理 I/O 操作和事件处理。libevent 是一个轻量级、高性能的事件通知库,广泛应用于网络服务…...
人脸表情识别系统分享(基于深度学习+OpenCV+PyQt5)
最近终于把毕业大论文忙完了,众所周知硕士大论文需要有三个工作点,表情识别领域的第三个工作点一般是做一个表情识别系统出来,如下图所示。 这里分享一下这个表情识别系统: 采用 深度学习OpenCVPyQt5 构建,主要功能包…...
AtCoder - arc086_d Shift and Decrement分析与实现
分析与思路 可以把操作流程表示成下图 以进行四次除法操作为例: 这里有一个关键点:对于每个p_i (0< i <x-1) ,x是除法操作的次数,如果p_i>2,可以将2个p_i的减法操作去掉,在p_(i1)中增加一个减法…...
学习111
项目名称项目简介主要功能技术原理GitHub地址browser-use智能浏览器工具,让AI像人类一样操作浏览器,实现网页自动化网页浏览与操作、多标签页管理、视觉识别与内容提取、操作记录与重复执行、自定义动作支持、主流LLM模型支持为大语言模型服务的创新Pyth…...
Android Jetpack Compose介绍
Android Jetpack Compose Android Jetpack Compose 是 Google 推出的现代 UI 工具包,用于以声明式的方式构建 Android 应用的 UI。它摒弃了传统的 XML 布局方式,完全基于 Kotlin 编写,提供了更简洁、更强大的 UI 开发体验。以下是 Compose 的…...
tcping 命令的使用,ping IP 和端口
1. Windows系统安装 下载tcping工具:根据系统位数(32位或64位)下载对应的tcping.exe文件。安装步骤: 将下载的tcping.exe文件复制到C:\Windows\System32目录下。如果下载的是64位版本,需将文件名改为tcpi…...
天地图InfoWindow插入React自定义组件
截至2025年03月21日天地图的Marker不支持添加Label; 同时Label和Icon是不支持自定义HTMLElement只支持String;目前只有InfoWindow支持自定义HTMLElement; 效果图 React核心api import ReactDOM from react-dom/client const content document.createElement(div);…...
003-掌控命令行-CLI11-C++开源库108杰
首选的现代C风格命令行参数解析器! (本课程包含两段教学视频。) 以文件对象监控程序为实例,五分钟实现从命令行读入多个监控目标路径;区分两大时机,学习 CLI11 构建与解析参数两大场景下的异常处理;区分三…...
理解 Node.js 中的 process`对象与常用操作
理解 Node.js 中的 process 对象与常用操作 在 Node.js 中,process 是一个全局对象,提供了与当前 Node.js 进程相关的信息和操作。无论是获取进程信息、处理信号、访问环境变量,还是控制进程行为,process 都是不可或缺的工具。 看…...
鸿蒙HarmonyOS NEXT应用崩溃分析及修复
鸿蒙HarmonyOS NEXT应用崩溃分析及修复 如何保证应用的健壮性,其中一个指标就是看崩溃率,如何降低崩溃率,就需要知道存在哪些崩溃,然后对症下药,解决崩溃。那么鸿蒙应用中存在哪些崩溃类型呢?又改如何解决…...
【conda activate无效】 conda: error: argument COMMAND: invalid choice: ‘activate‘
conda activate失效了 在使用conda activate时出现报错: usage: conda [-h] [-v] [--no-plugins] [-V] COMMAND ... conda: error: argument COMMAND: invalid choice: activate (choose from clean, compare, config, create, info, init, install, list, notice…...
Redis + 布隆过滤器解决缓存穿透问题
Redis 布隆过滤器解决缓存穿透问题 1. Redis 布隆过滤器解决缓存穿透问题 📌 什么是缓存穿透? 缓存穿透指的是查询的数据既不在缓存,也不在数据库,导致每次查询都直接访问数据库,增加数据库压力。 例如࿱…...
机器学习——分类、回归、聚类、LASSO回归、Ridge回归(自用)
纠正自己的误区:机器学习是一个大范围,并不是一个小的方向,比如:线性回归预测、卷积神经网络和强化学都是机器学习算法在不同场景的应用。 机器学习最为关键的是要有数据,也就是数据集 名词解释:数据集中的…...
HarmonyOS鸿蒙开发 BuilderParam在父组件的Builder的点击事件报错:Error message:is not callable
HarmonyOS鸿蒙开发 BuilderParam在父组件的Builder的点击事件报错:Error message:is not callable 最近在鸿蒙开发过程中,UI做好了,根据列表item进行点击跳转,报错了 报错信息如下 Error message:is not callable Stacktrace:at…...
【canvas】一键自动布局:如何让流程图节点自动找到最佳位置
一键自动布局:如何让流程图节点自动找到最佳位置 引言 在流程图、拓扑图和系统架构图设计中,节点布局往往是最令人头疼的问题。如果手动调整每个节点位置,不仅耗时费力,还难以保证美观性和一致性。本文将深入解析如何实现自动布…...
[每周一更]-(第137期):Go + Gin 实战:Docker Compose + Apache 反向代理全流程
文章目录 **1. Go 代码示例(main.go)****2. Dockerfile 多段构建**3.构建 Docker 镜像**4. docker-compose.yml 直接拉取镜像****5. 运行容器****6. 测试 API**7、配置域名访问**DNS解析:将域名转换为IP地址****DNS寻址示例** 8.错误记录 访问…...
HTTPS 加密过程详解
HTTPS 详解及其加密过程流程框架 HTTPS(Hypertext Transfer Protocol Secure)是一种基于 HTTP 协议的安全通信协议,通过 SSL/TLS 协议对传输数据进行加密和身份验证,解决了 HTTP 明文传输的安全隐患。以下是其核心原理和加密流程的…...
SpringCache小记
Spring Cache 小记 官方文档:https://springdoc.cn/spring-cache-tutorial/ 基础知识 常用注解 EnableCaching:开启缓存功能,一般放在启动类上。 Cacheable:表示该方法支持缓存。当调用被注解的方法时,如果对应的键已…...
Web-Machine-N7靶机通关攻略
获取靶机ip arp-scan -l 端口扫描 nmap xxxx 访问80端口发现没用 扫描目录 gobuster dir -u http:/192.168.117.160 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium,txt -x php,html,txt ,zip 打开exploit.html 点击F12,修改localhost为靶机ip&#…...
笔记本运行边缘计算
笔记本电脑可以用来运行PCDN(Peer-to-Peer Content Delivery Network)服务。实际上,如果你有闲置的笔记本电脑,并且它具备一定的硬件条件和网络环境,那么它可以成为一个不错的PCDN节点。 运行PCDN的基本要求 硬件需求…...
self Attention为何除以根号dk?(全新角度)
全网最独特解析:self Attention为何除根号dk? 一、假设条件:查询向量和键向量服从正态分布 假设查询向量 q i q_i qi和键向量 k j k_j kj的每个分量均为独立同分布的随机变量,且服从标准正态分布,即:…...
第十五次CCF-CSP认证(含C++源码)
第十五次CCF-CSP认证 小明上学满分思路 数据中心满分思路 小明放学满分题解 小明上学 题目链接 满分思路 其实题目看着长,但是做起来是非常好写的,其实主要原因在于,他的红绿灯的变化规律是一定的,而且小明路上的每次红绿灯情况…...
基于Azure Delta Lake与Databricks的医疗数据变更管理
设计Azure云架构方案实现Azure Delta Lake和Azure Databricks,在医疗场景下记录所有数据变更,满足合规性要求(如 GDPR),并具备回滚能力,能快速恢复误删数据(如 RESTORE TABLE table VERSION AS …...
简述Mybatis的插件运行原理,以及如何编写一个插件?
MyBatis 插件运行原理 MyBatis 插件的核心原理基于 Java 的动态代理和责任链模式。下面详细阐述其工作机制: 动态代理 MyBatis 允许你在四大核心对象(Executor、StatementHandler、ParameterHandler 和 ResultSetHandler)的方法执行前后进…...
Java-servlet(七)详细讲解Servlet注解
Java-servlet(七)详细讲解Servlet注解 前言一、注解的基本概念二、Override 注解2.1 作用与优势2.2 示例代码 三、Target 注解3.1 定义与用途3.2 示例代码 四、WebServlet 注解4.1 作用4.2 示例代码 五、反射与注解5.1 反射的概念5.2 注解与反射的结合使…...
SQLark 实战 | 如何通过对象名和 DDL 快速搜索数据库对象
在数据库运维管理、应用开发和问题定位时,常常需要搜索相关的数据库对象。本文将为你介绍如何使用 SQLark 的搜索功能,实现对数据库对象的快速查找与定位。 👉 前往 SQLark 官网:www.sqlark.com 下载全功能免费版。 通过对象名称搜…...
C/S模型-TCP
下图是基于TCP协议的客户端/服务器程序的一般流程: TCP协议通讯流程 服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SY…...
51c自动驾驶~合集24
我自己的原文哦~ https://blog.51cto.com/whaosoft/11926510 #DriveArena 上海AI Lab又放大招:首个高保真闭环生成仿真平台 仓库链接:https://github.com/PJLab-ADG/DriveArena 项目链接:https://pjlab-adg.github.io/DriveArena/ D…...
19.哈希表的实现
1.哈希的概念 哈希(hash)⼜称散列,是⼀种组织数据的⽅式。从译名来看,有散乱排列的意思。本质就是通过哈希函数把关键字Key跟存储位置建⽴⼀个映射关系,查找时通过这个哈希函数计算出Key存储的位置,进⾏快速查找。 1.2.直接定址法…...
【PCB工艺】晶体管的发展历史
晶体管被认为是20世纪最伟大的发明之一,因为没有晶体管就不会有现代电脑、手机或平板,你也无法阅读到这里的内容,因为不存在网络。 ——本文纯粹出于对过往奋斗在这个领域中科学家的缅怀。科学家有太多宝贵的思想和经验值得我们认真总结和…...
