详解Libevent网络库

article/2025/9/10 13:11:56

项目中要用到libevent,所以就自学了libevent,参考资料为张亮的《libevent源码深度剖析》和《linux高性能服务器编程》

Libevent简介

Libevent是开源社区一款高性能的I/O框架库,其具有如下特点:

1.跨平台支持。Libevent支持Linux、UNIX和Windows。

2.统一事件源。libevent对i/o事件、信号和定时事件提供统一的处理。

3.线程安全。libevent使用libevent_pthreads库来提供线程安全支持。

4.基于reactor模式的实现。

reactor基本知识

reactor是i/o框架库的核心,它主要提供的几个方法是:

1.handle_events:该方法执行事件循环,重复如下过程:等待事件,然后依次处理所有就绪事件对应的时间处理器。

2.register_handler:该方法调用事件多路分发器的register_event方法来往事件多路分发器中注册一个事件。

3.remove_handler:该方法调用事件多路分发器的remove_event方法来删除事件多路分发器中的一个事件。

下图为i/o框架库的工作时序图:



reactor具有如下优点:

1.响应快,不必为单个同步事件所阻塞;

2.编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;

3.可扩展性,可以方便的通过增加reactor实例个数来充分利用CPU资源;

4.可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性。

libevent库的主要逻辑:

1.调用event_init函数创建event_base对象。一个event_base相当于一个reactor实例。

2.创建具体的事件处理器,并设置它们所从属的reactor实例。evsignal_new和evtimer_new分别用于创建信号事件处理器和定时事件处理器,它们的统一入口是event_new函数,event_new函数成功时返回一个event类型的对象,也就是libevent的事件处理器


3.调用event_add函数,将事件处理器添加到注册事件队列中,并将该事件处理器对应的事件添加到事件多路分发器中。

4.调用event_base_dispatch函数来执行事件循环。

5.事件循环结束后,使用*_free系列函数来释放系统资源。

源代码组织结构

1)头文主要就是 event.h:事件宏定义、接口函数声明,主要结构体 event 的声明;


2)内部头文件
xxx-internal.h:内部数据结构和函数,对外不可见,以达到信息隐藏的目的;
3) libevent 框架
event.c: event 整体框架的代码实现;
4)对系统 I/O 多路复用机制的封装
epoll.c:对 epoll 的封装;
select.c:对 select 的封装;
devpoll.c:对 dev/poll 的封装;
kqueue.c:对 kqueue 的封装;
5)定时事件管理
min-heap.h:其实就是一个以时间作为 key 的小根堆结构;
6)信号管理
signal.c:对信号事件的处理;
7)辅助功能函数
evutil.h 和 evutil.c:一些辅助功能函数,包括创建 socket pair 和一些时间操作函数:加、减
和比较等。
8)日志
log.h 和 log.c: log 日志函数
9)缓冲区管理
evbuffer.c 和 buffer.c: libevent 对缓冲区的封装;
10)基本数据结构
compat\sys 下的两个源文件: queue.h 是 libevent 基本数据结构的实现,包括链表,双向链表,
队列等; _libevent_time.h:一些用于时间操作的结构体定义、函数和宏定义;
11)实用网络库


http 和 evdns:是基于 libevent 实现的 http 服务器和异步 dns 查询库;

event结构体

libevent中的事件处理器是event结构类型。event结构体封装了句柄、事件类型、回调函数、以及其他必要的标志和数据,源代码如下

struct event {TAILQ_ENTRY(event) ev_active_next;TAILQ_ENTRY(event) ev_next;/* for managing timeouts */union {TAILQ_ENTRY(event) ev_next_with_common_timeout;int min_heap_idx;} ev_timeout_pos;evutil_socket_t ev_fd;struct event_base *ev_base;union {/* used for io events */struct {TAILQ_ENTRY(event) ev_io_next; struct timeval ev_timeout;} ev_io;/* used by signal events */struct {TAILQ_ENTRY(event) ev_signal_next;short ev_ncalls;/* Allows deletes in callback */short *ev_pncalls;} ev_signal;} _ev;short ev_events;short ev_res;        /* result passed to event callback */short ev_flags;ev_uint8_t ev_pri;    /* smaller numbers are higher priority */ev_uint8_t ev_closure;struct timeval ev_timeout;/* allows us to adopt for different types of events */void (*ev_callback)(evutil_socket_t, short, void *arg);void *ev_arg;
};
ev_active_next: 表示就绪状态的事件链表指针,当关注的事件就绪后,会把
对应的event放入active的队列里。表示该事件在active队列里的位置
ev_next:表示所有事件队列链表的指针。表示该事件在所有时间列表的位置。
ev_timeout_pos:用于管理超时
ev_fd:event绑定的socket描述符
ev_events:
event关注的事件类型,它可以是以下3种类型:
I/O事件: EV_WRITE和EV_READ
定时事件: EV_TIMEOUT
信号: EV_SIGNAL
辅助选项: EV_PERSIST,表明是一个永久事件
Libevent中的定义为:
#define EV_TIMEOUT 0x01
#define EV_READ 0x02
#define EV_WRITE 0x04
#define EV_SIGNAL 0x08
#define EV_PERSIST 0x10 /* Persistant event */
ev_res:记录了当前激活事件的类型;
ev_flags: libevent 用于标记 event 信息的字段,表明其当前的状态,可能的值有:
#define EVLIST_TIMEOUT 0x01 // event在time堆中
#define EVLIST_INSERTED 0x02 // event在已注册事件链表中
#define EVLIST_SIGNAL 0x04 // 未见使用
#define EVLIST_ACTIVE 0x08 // event在激活链表中
#define EVLIST_INTERNAL 0x10 // 内部使用标记
#define EVLIST_INIT 0x80 // event 已被初始化
ev_pri:当前事件的优先级
ev_timeout:超时时间设置
ev_callback:该事件对应的回调函数,和cb类型一样
ev_arg:回调函数用到参数
ev_ncalls:事件就绪执行时,调用 ev_callback 的次数,通常为 1;
ev_pncalls:指针,通常指向 ev_ncalls 或者为 NULL;


往注册事件队列中添加事件处理器

创建一个event对象的函数是event_new,创建好之后应用程序调用event_add函数将其添加到注册事件队列中,并将对应的事件注册到事件多路分发器上,event_add函数主要是调用一个内部函数event_add_internal来实现的。

eventop结构体

eventop结构体封装了i/o复用机制必要的一些操作,比如注册事件、等待事件等,它为event_base支持的所有后端i/o复用机制提供了一个统一的接口,libevent默认选择的后端i/o复用技术是epoll。

event_base结构体

结构体event_base是libevent的reactor,源码如下:

struct event_base {/** Function pointers and other data to describe this event_base's* backend. */const struct eventop *evsel;/** Pointer to backend-specific data. */void *evbase;/** List of changes to tell backend about at next dispatch.  Only used* by the O(1) backends. */struct event_changelist changelist;/** Function pointers used to describe the backend that this event_base* uses for signals */const struct eventop *evsigsel;/** Data to implement the common signal handelr code. */struct evsig_info sig;/** Number of virtual events */int virtual_event_count;/** Number of total events added to this event_base */int event_count;/** Number of total events active in this event_base */int event_count_active;/** Set if we should terminate the loop once we're done processing* events. */int event_gotterm;/** Set if we should terminate the loop immediately */int event_break;/** Set if we should start a new instance of the loop immediately. */int event_continue;/** The currently running priority of events */int event_running_priority;/** Set if we're running the event_base_loop function, to prevent* reentrant invocation. */int running_loop;/* Active event management. *//** An array of nactivequeues queues for active events (ones that* have triggered, and whose callbacks need to be called).  Low* priority numbers are more important, and stall higher ones.*/struct event_list *activequeues;/** The length of the activequeues array */int nactivequeues;/* common timeout logic *//** An array of common_timeout_list* for all of the common timeout* values we know. */struct common_timeout_list **common_timeout_queues;/** The number of entries used in common_timeout_queues */int n_common_timeouts;/** The total size of common_timeout_queues. */int n_common_timeouts_allocated;/** List of defered_cb that are active.  We run these after the active* events. */struct deferred_cb_queue defer_queue;/** Mapping from file descriptors to enabled (added) events */struct event_io_map io;/** Mapping from signal numbers to enabled (added) events. */struct event_signal_map sigmap;/** All events that have been enabled (added) in this event_base */struct event_list eventqueue;/** Stored timeval; used to detect when time is running backwards. */struct timeval event_tv;/** Priority queue of events with timeouts. */struct min_heap timeheap;/** Stored timeval: used to avoid calling gettimeofday/clock_gettime* too often. */struct timeval tv_cache;#if defined(_EVENT_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)/** Difference between internal time (maybe from clock_gettime) and* gettimeofday. */struct timeval tv_clock_diff;/** Second in which we last updated tv_clock_diff, in monotonic time. */time_t last_updated_clock_diff;
#endif#ifndef _EVENT_DISABLE_THREAD_SUPPORT/* threading support *//** The thread currently running the event_loop for this base */unsigned long th_owner_id;/** A lock to prevent conflicting accesses to this event_base */void *th_base_lock;/** The event whose callback is executing right now */struct event *current_event;/** A condition that gets signalled when we're done processing an* event with waiters on it. */void *current_event_cond;/** Number of threads blocking on current_event_cond. */int current_event_waiters;
#endif#ifdef WIN32/** IOCP support structure, if IOCP is enabled. */struct event_iocp_port *iocp;
#endif/** Flags that this base was configured with */enum event_base_config_flag flags;/* Notify main thread to wake up break, etc. *//** True if the base already has a pending notify, and we don't need* to add any more. */int is_notify_pending;/** A socketpair used by some th_notify functions to wake up the main* thread. */evutil_socket_t th_notify_fd[2];/** An event used by some th_notify functions to wake up the main* thread. */struct event th_notify;/** A function used to wake up the main thread from another thread. */int (*th_notify_fn)(struct event_base *base);
};

事件循环

libevent中实现事件循环的函数是event_base_loop,该函数首先调用i/o事件多路分发器的事件监听函数,以等待事件,当有事件发生时,就依次处理之。

参考博客:点击打开链接


 

http://chatgpt.dhexx.cn/article/ppwdqb9Y.shtml

相关文章

Libevent库的介绍与应用

Libevent库 Libevent概述Libevent使用模型Libevent库使用示例Libevent事件类型和框架结构使用Libevent完成tcp服务端 Libevent概述 Libevent是开源社区的一款高性能的I/O框架库,使用Libevent的著名案例有:高性能的分布式内存对象缓存软件memcached,Goog…

Linux c 开发 - libevent

目录 一、event_base 1. 创建event_base 2. 查看IO模型 3. 销毁event_base 4. 事件循环 event loop 5. event_base的例子 二、event 事件 1. 创建一个事件event 2. 释放event_free 3. 注册event 4.event_assign 5. 信号事件 6. event细节 三、Socket实例 四、Bu…

安装svn客户端

下载地址 下载 TortoiseSVN 我的网盘地址: 百度网盘 请输入提取码 提取码: em9s 1、安装客户端 双击运行: 点击【next】 点击【next】 选择好路径后,点击【next】 点击【install】安装 点击【finish】完成安装。安装完成后重…

SVN客户端配置--客户端

一、使用客户端软件连接SVN服务器 在项目文件夹中单击右键–>TortoiseSVN–>Repo-browser,并在弹出框中贴入URL(svn://服务器IP) 在图中指定的位置单击右键选择checkput 点击OK点击OK SVN的三大指令 指令名称Checkout①连接到SVN服务器②更新服务…

SVN客户端(TortoiseSVN)安装及使用说明

😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: SVN客户端(TortoiseSVN)安装及使用说明 ⏱️ 创作时间: 20…

ubuntu搭建SVN客户端,右击提交或更新

有时候我们会在Linux系统上搞开发,项目在SVN上,不搭建SVN环境搞起来比较麻烦,不用其他软件为载体实现右击提交更新等其他操作,不使用VsCode,IDE全家桶等为载体搭建插件形式的SVN,完全独立搭建 1:安装SVN客…

SVN客户端下载及安装

SVN客户端地址:https://osdn.net/projects/tortoisesvn/# 方法/步骤 官网下载tortoisesvn,下载完成之后,如下图所示: 点击安装进入安装界面,点击接受协议,如下图所示: 选择安装的地址&…

【转】Ubuntu中SVN客户端安装+使用

转自:Ubuntu中SVN客户端安装使用_三少GG-CSDN博客 1、 安装 svn客户端: apt-get install subversion,然后根据提示一步一步,就完成了 svn的安装。当然,也可以源码安装 svn,下载 subversion 一个最新版本的源…

SVN客户端

SVN是Subversion的简称,是一个开源的代码版本控制系统 SVN客户端操作 checkout 检出:初次下载-第一次连接svn服务器时候需要下载对应仓库的数据(如果仓库中有数据的话)add 新增:新增数据到svn服务器update 更新&#x…

【SVN】windows下的SVN客户端访问ubuntu下的SVN服务器

目录 第一部分 windows创建本地版本库、连接ubuntu的SVN服务器 步骤0: 步骤一:创建windows本地版本库 步骤二:checkout检测 步骤三:输入之前配置的用户名和密码 第二部分 windows上传文件至SVN服务器 步骤一:添加…

SVN 客户端下载与安装

SVN 客户端下载与安装 svn 客户端下载地址:https://tortoisesvn.net/downloads.zh.html 1. 网址截图 2. 汉化包下载安装 下载完毕,双击安装,下一步即可(可根据需要进行安装路径选择)

windows环境下的svn客户端(VisualSVN Server),服务端(TortoiseSVN),中文化(TortoiseSVN LanguagePack_1.9.7.2)安装和使用(超详细)

一、下载安装包 1.VisualSVN server 服务端下载:VisualSVN Server 2.svn客户端下载:TortoiseSVN 3.中文化包下载:TortoiseSVN LanguagePack_1.9.7.27907-x64-zh_CN中文包 二、安装软件 1.安装VisualSVN server 服务端: &#xf…

SVN客户端安装及操作文档

第一部分:客户端安装 1 在D盘创建svnclient文件夹,并将svn安装包复制到svnclient文件夹中 2 客户端安装 双击文件“TortoiseSVN-1.14.1.29085-x64-svn-1.14.1.msi” 点击“Next” 点击“Next” 点击“Browse”选择安装路径,这里将安装路径…

12306图片验证码效果实现

效果如下: 原理:从服务器获取的图片上,我们画上自己的图片,然后再显示出来。 核心代码如下在处理imageview点击事件前做如下操作: Bitmap bitmap BitmapFactory.decodeResource(getResources(), R.mipmap.yanzheng)…

利用神经网络识别12306验证码—(六)模型应用以及12306实战测试

模型训练好之后,就可以应用于新图片的预测了。比如现在有下面这么一张12306的验证码,预测工作也分为两部分:上半部分的文字预测、下半部分的图片预测,将两部分划分开之后分别加载各自的模型进行预测。 文字预测:需要把…

php实现12306验证码,PHP仿12306图片验证码

生成验证码的demo使用模型model读取图库,有需要对接框架的朋友可以自己修改,如下: # 引入测试的数据库model require_once dirname(__FILE__)./Model.php; # 引入验证码核心类库 require_once dirname(dirname(__FILE__))./vendor/Vif.php; $…

python 爬取12306验证码

一个简单的验证码爬取程序 本文介绍了在Python2.7环境下爬取网站验证码: 思路就是获取验证码对应的url,然后发起requst请求,读取该URL对应的内容,然后写入到一个本地文件,实现一个验证码的保存。大量下载可以把以上程…

利用百度AI平台识别12306验证码

简单的利用百度AI平台做一个12306的验证码识别。 第一步:先进行图片预处理 提取文字部分 import numpy as np#分割文字 def get_img_text(img,offset0):return img[3:22,120offset:177offset]#分割图片 def _get_imgs(img):interval 5length 66img_array np.em…

12306验证码为什么那么变态?都是这项深度学习应用给逼的

导读:12306为什么要设置那么复杂的验证码机制呢?就是因为OCR。 今天聊OCR。 OCR是人工智能、机器学习特别是深度学习,在图像识别方向最为重要的应用之一。OCR全称Optical Chararcter Recogition,中文翻译为光学字符识别&#xff0…

12306验证码的一些思考

12306的验证码长这个样子: 让选择图片.看起来非常完美的图片验证码.比那些简单又没有实用的字母数字验证码组合强太多了.那些字母数字组合直接获取图片光学识别然后填进表单就可以攻破. 我也想实现这样的. 怎么去实现呢? 设计一个简单点的吧. 1.我先收集图片.收集200张.分…