libevent源码剖析

合集下载

libevent源码深度剖析十三libevent信号处理注意点

libevent源码深度剖析十三libevent信号处理注意点

libevent源码深度剖析十三libevent信号处理注意点系列目录(1)libevent源码深度剖析一序(2)libevent源码深度剖析二 Reactor模式(3)libevent源码深度剖析三 libevent基本使用场景和事件流程(4)libevent源码深度剖析四 libevent源代码文件组织(5)libevent源码深度剖析五 libevent的核心:事件event(6)libevent源码深度剖析六初见事件处理框架(7)libevent源码深度剖析七事件主循环(8)libevent源码深度剖析八集成信号处理(9)libevent源码深度剖析九集成定时器事件(10)libevent源码深度剖析十支持I/O多路复用技术(11)libevent源码深度剖析十一时间管理(12)libevent源码深度剖析十二让libevent支持多线程(13)libevent源码深度剖析十三 libevent信号处理注意点前面讲到了 libevent 实现多线程的方法,然而在多线程的环境中注册信号事件,还是有一些情况需要小心处理,那就是不能在多个 libevent 实例上注册信号事件。

依然冠名追加到 libevent 系列。

以 2 个线程为例,做简单的场景分析。

1 首先是创建并初始化线程 1 的 libevent 实例 base1 ,线程 1 的 libevent 实例 base2 ;2 在 base1 上注册 SIGALRM 信号;在 base2 上注册 SIGINT 信号;3 假设当前 base1 和 base2 上都没有注册其他的事件;4 线程 1 和 2 都进入 event_base_loop 事件循环:5 假设线程 1 先进入 event_base_loop ,并设置 evsignal_base = base1 ;并等待;6 接着线程 2 也进入 event_base_loop ,并设置 evsignal_base = base2 ;并等待;于是 evsignal_base 就指向了 base2 ;7 信号 ALARM 触发,调用服务例程:1static void evsignal_handler(int sig){2 ...3 evsignal_base->sig.evsigcaught[sig]++;4 evsignal_base->sig.evsignal_caught = 1;5 /* Wake up our notification mechanism */6 send(evsignal_base->sig.ev_signal_pair[0], 'a', 1, 0);7 ...8}于是 base2 得到通知 ALARM 信号发生了,而实际上 ALARM 是注册在 base1 上的, base2 上的 ALARM 注册 event 是空的,于是处理函数将不能得到调用;因此在 libevent 中,如果需要处理信号,只能将信号注册到一个 libevent 实例上。

libevent evthread_use_pthreads -回复

libevent evthread_use_pthreads -回复

libevent evthread_use_pthreads -回复libevent是一个开源的事件驱动网络库,它提供了一个高效的跨平台的事件驱动模型,用于构建可扩展的网络应用程序。

evthread_use_pthreads 是libevent库中的一个函数,它用于设置使用pthread线程库作为底层的多线程实现。

本文将深入探讨libevent库及其事件驱动模型以及evthread_use_pthreads函数的作用和用法。

一、libevent库和事件驱动模型简介libevent是一个轻量级、高性能、事件驱动的网络库,最初由Nick Mathewson于2000年开发,并在2002年发布。

它的设计目标是提供一个统一的、跨平台的接口,用于处理网络事件和I/O操作,以支持高并发的网络应用程序。

libevent库可以在多个操作系统上运行,包括Windows、Linux、BSD等。

libevent采用了事件驱动的编程模型,通过使用异步的、非阻塞的I/O操作和事件回调机制来处理网络事件。

在传统的阻塞式I/O模型中,每个连接都需要一个独立的线程或进程来处理,当同时有大量的连接时,会消耗大量的系统资源。

而在事件驱动模型中,通过一个主循环不断监听和分发事件,将连接的处理交给事件回调函数,可以大大提高系统的吞吐量和性能。

二、libevent库的特性和用途1. 高性能:libevent采用非阻塞I/O和事件回调机制,能够处理大量的并发连接,实现高性能的网络应用程序。

2. 跨平台:libevent可以在多个操作系统上运行,包括Windows、Linux、BSD、macOS等。

3. 支持多种网络协议:libevent支持多种常用的网络协议,如TCP、UDP、HTTP等,能够满足不同类型的网络应用需求。

4. 支持定时器:libevent提供了定时器功能,可以方便地实现定时任务的调度和执行。

5. 可扩展性:libevent的设计模式允许用户自定义事件源和事件处理器,以满足复杂应用的需求。

qt libevent编译

qt libevent编译

qt libevent编译Qt和libevent是两个不同的库,分别用于不同的领域。

Qt是一个跨平台的C++应用程序开发框架,而libevent是一个事件驱动的网络编程库。

下面将分别介绍它们的特点和用途。

一、Qt库Qt是由挪威Trolltech公司(现已被诺基亚收购)开发的,是一个跨平台的应用程序开发框架。

它提供了丰富的功能和工具,使开发者可以快速创建高性能的图形用户界面(GUI)应用程序。

Qt具有以下特点:1. 跨平台性:Qt可以在多个操作系统上运行,包括Windows、macOS、Linux等,大大简化了跨平台开发的难度。

2. 强大的图形界面设计工具:Qt提供了Qt Designer,一个直观易用的界面设计工具,开发者可以通过拖拽和放置组件的方式设计用户界面。

3. 丰富的组件库:Qt拥有丰富的组件库,包括按钮、文本框、列表框等,开发者可以直接使用这些组件来构建用户界面。

4. 高性能:Qt使用了一些优化技术,如信号槽机制和事件循环,以实现高效的事件处理和界面更新。

5. 支持多种编程语言:除了C++,Qt还支持其他编程语言,如Python和JavaScript,使开发者可以根据自己的喜好选择编程语言。

二、libevent库libevent是一个事件驱动的网络编程库,它提供了一种高效的方式来处理网络连接和事件。

libevent可以用于开发服务器程序、网络代理、网络爬虫等应用。

libevent具有以下特点:1. 轻量级:libevent是一个轻量级的库,仅依赖于标准C库,不需要其他第三方库的支持。

2. 高性能:libevent使用了事件驱动的方式来处理网络连接和事件,可以实现高并发和低延迟的网络通信。

3. 跨平台性:libevent可以在多个操作系统上运行,包括Windows、Linux、FreeBSD等。

4. 支持多种网络协议:libevent支持TCP、UDP、HTTP等多种网络协议,开发者可以根据需要选择合适的协议。

黑马程序员C语言教程:libevent

黑马程序员C语言教程:libevent

标题:深入浅出-服务器高并发库libevent (一)1安装libevent是一个开源的高并发服务器开发包,官方地址/ libevent目前有两个版本一个是1.4系列版本,一个是2.0系列版本。

我们可以在官方网站上看到类似有个stable表示稳定版本。

libevent-1.4.15-stable.tar.gz对于初学者学习,建议从1.4版本学起。

在安装libevent之前先判断本电脑是否已经安装了通过指令ls -al /usr/lib|grep libevent如果没有任何信息则表示没有安装,有的话如果发现libevent是1.3以下版本,则可以同过执行rpm -e libevent —nodeps 进行卸载。

如果是其他操作系统使用其他对应卸载指令即可。

对于下好的tar包,通过tar -zxvf libevent-release-1.4.15-stable.tar.gz指令解压。

然后执行./configure命令,但是有的包可能没有configure文件,却存在一个autogen.sh 脚本,运行这个脚本。

(如果运行不起来请安装autoconf包)然后./configure–prefix=/usrmakesudo make install安装完之后执行ls -al /usr/lib/|grep libevent如果发现有libevent文件库存在就代表安装完毕。

2 简单的libevent服务器我们通过连接libevent库来进行管理libevent库,所以在使用gcc或者g++编译的时候最后需要加上-levent下面是一个简单的libevent服务器。

#include <stdio.h>#include <string.h>#include <iostream>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <unistd.h>#include <event.h>using namespace std;#define SERVER_ADDR "127.0.0.1"#define SERVER_PORT 8888// 事件basestruct event_base* base;// 读事件回调函数void onRead(int iCliFd, short iEvent, void *arg) {int iLen;char buf[1500];iLen = recv(iCliFd, buf, 1500, 0);if (iLen <= 0) {cout << "Client Close" << endl;// 连接结束(=0)或连接错误(<0),将事件删除并释放内存空间 struct event *pEvRead = (struct event*)arg; event_del(pEvRead);delete pEvRead;close(iCliFd);return;}buf[iLen] = 0;cout << "Client Info:" << buf << endl;struct bufferevent* buf_ev;buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL);buf_ev->wm_read.high = 4096;char MESSAGE[]="welcome to server..";bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));}// 连接请求事件回调函数void onAccept(int iSvrFd, short iEvent, void *arg){int iCliFd;struct sockaddr_in sCliAddr;socklen_t iSinSize = sizeof(sCliAddr);iCliFd = accept(iSvrFd, (struct sockaddr*)&sCliAddr,&iSinSize);// 连接注册为新事件 (EV_PERSIST为事件触发后不默认删除)struct event *pEvRead = new event;event_set(pEvRead, iCliFd, EV_READ|EV_PERSIST, onRead, pEvRead);event_base_set(base, pEvRead);event_add(pEvRead, NULL);struct bufferevent* buf_ev;buf_ev = bufferevent_new(iCliFd, NULL, NULL, NULL, NULL); buf_ev->wm_read.high = 4096;char MESSAGE[]="welcome to server..";bufferevent_write(buf_ev, MESSAGE, strlen(MESSAGE));cout<<"a client connect:"<<iCliFd<<endl;}int main(){int iSvrFd;struct sockaddr_in sSvrAddr;memset(&sSvrAddr, 0, sizeof(sSvrAddr));sSvrAddr.sin_family = AF_INET;sSvrAddr.sin_addr.s_addr = inet_addr(SERVER_ADDR); sSvrAddr.sin_port = htons(SERVER_PORT);// 创建tcpSocket(iSvrFd),监听本机8888端口iSvrFd = socket(AF_INET, SOCK_STREAM, 0);bind(iSvrFd, (struct sockaddr*)&sSvrAddr,sizeof(sSvrAddr));listen(iSvrFd, 10);// 初始化basebase = (struct event_base*)event_init();struct event evListen;// 设置事件event_set(&evListen, iSvrFd, EV_READ|EV_PERSIST, onAccept, NULL);// 设置为base事件event_base_set(base, &evListen);// 添加事件event_add(&evListen, NULL);// 事件循环event_base_dispatch(base);return 0;}通过编译指令g++ server.cpp -o server -Wall -g -I ./ -levent得到可执行程序./server启动。

libevent 定时器工作原理

libevent 定时器工作原理

libevent定时器工作原理1. 简介libevent是一个事件驱动的网络编程库,它提供了对I/O多路复用、定时器和信号处理等功能的封装。

其中,定时器是libevent中非常重要的一个组件,它可以用于实现各种定时任务,比如定时执行某个函数或发送心跳包等。

本文将详细介绍libevent定时器的工作原理,包括定时器的创建、设置回调函数、启动和停止定时器等过程。

同时,我们还会讨论libevent定时器的底层实现原理,以及如何处理定时器事件。

2. libevent定时器的创建在使用libevent定时器之前,我们首先需要创建一个定时器对象。

libevent提供了event_new函数来创建定时器对象,其函数原型如下:struct event *event_new(struct event_base *base, evutil_socket_t fd, short eve nts, event_callback_fn callback, void *arg);参数说明: - base:事件的基础结构体,表示事件所属的事件处理器。

- fd:定时器的文件描述符,由于定时器不与具体的文件描述符关联,因此可以传入-1。

- events:事件类型,定时器的事件类型为EV_TIMEOUT,表示定时器超时事件。

- callback:事件回调函数,当定时器超时时会调用该函数。

- arg:回调函数的参数。

通过调用event_new函数,我们可以得到一个定时器对象,接下来我们需要设置定时器的超时时间和回调函数。

3. libevent定时器的设置在创建定时器对象后,我们需要使用event_add函数来设置定时器的超时时间和回调函数,将定时器添加到事件处理器中。

int event_add(struct event *ev, const struct timeval *timeout);参数说明: - ev:定时器对象。

libevent源码分析

libevent源码分析

libevent源码深度剖析张亮Email: sparling.liang@回想刚开始写时,就冠以“深度剖析”的名称,也是为了给自己一些压力,以期能写好这一系列文章,对libevent源代码的各方面作详细的分析;现在看来也算是达到了最初的目的。

希望能给学习和使用libevent的朋友们有所帮助。

Email:sparkling.liang@张亮目录libevent源码深度剖析 (1)目录 (3)一序幕 (5)1 前言 (5)2 Libevent简介 (5)3 学习的好处 (5)二Reactor模式 (6)1 Reactor的事件处理机制 (6)2 Reactor模式的优点 (6)3 Reactor模式框架 (6)4 Reactor事件处理流程 (8)5 小结 (9)三基本使用场景和事件流程 (10)1 前言 (10)2 基本应用场景 (10)3 实例代码 (11)4 事件处理流程 (11)5 小结 (12)四 libevent源代码文件组织 (13)1 前言 (13)2 源代码组织结构 (13)3 小结 (14)五 libevent的核心:事件event (15)1 libevent的核心-event (15)2 libevent对event的管理 (16)3 事件设置的接口函数 (17)4 小结 (18)六初见事件处理框架 (19)1 事件处理框架-event_base (19)2 创建和初始化event_base (20)3 接口函数 (20)4 小节 (23)七事件主循环 (24)1 阶段性的胜利 (24)2 事件处理主循环 (24)3 I/O和Timer事件的统一 (27)4 I/O和Signal事件的统一 (27)5 小节 (27)八集成信号处理 (28)1 集成策略——使用socket pair (28)2 集成到事件主循环——通知event_base (29)4 evsignal_info结构体 (30)5 注册、注销signal事件 (30)5 小节 (31)九集成定时器事件 (32)1 集成到事件主循环 (32)2 Timer小根堆 (33)3 小节 (34)十支持I/O多路复用技术 (35)1 统一的关键 (35)2 设置I/O demultiplex机制 (35)3 小节 (37)十一时间管理 (38)1 初始化检测 (38)2 时间缓存 (38)3 时间校正 (40)4 小节 (41)十二让libevent支持多线程 (42)1 错误使用示例 (42)2 支持多线程的几种模式 (42)3 例子——memcached (43)4 小节 (44)一序幕1 前言Libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少。

libevent evthread_use_pthreads

libevent evthread_use_pthreads

libevent evthread_use_pthreads题目:深入探究libevent中的evthread_use_pthreads引言:在计算机领域中,多线程编程是一种常见且重要的技术,在提高程序并发性、提升计算效率方面发挥着关键作用。

libevent是一款广泛应用于网络编程的开源软件库,通过提供事件驱动、可移植的网络服务器和客户端功能,简化了开发者的工作。

本文将着重深入探究libevent中的evthread_use_pthreads函数,这个函数用于在多线程环境中利用pthreads库实现线程并发。

第一部分:libevent概述1.1 何为libevent?libevent是一个开源软件库,为网络应用提供了一个事件驱动编程接口,可用于基于事件的网络服务器和客户端的开发。

它支持多种事件类型,包括套接字、文件、时间以及信号等。

通过使用libevent,开发者可以编写高度并发性的网络服务器,充分利用计算机资源,提高服务器性能。

1.2 libevent的优势- 事件驱动:libevent基于事件回调机制,即在特定事件发生时,自动调用相应函数进行处理。

- 可移植性:libevent采用了模块化设计,并提供了平台无关的API,因此可以轻松移植到不同的操作系统上。

- 高性能:利用事件驱动的方式,libevent可以高效处理大量并发连接,提供了高性能的网络编程能力。

第二部分:evthread_use_pthreads函数介绍2.1 函数定义在libevent中,evthread_use_pthreads函数用于在多线程环境中利用pthreads库实现线程并发。

其定义如下:cint evthread_use_pthreads(void)2.2 函数功能evthread_use_pthreads函数的主要功能是使libevent能够在多线程环境中使用pthreads库提供的线程功能。

通过调用该函数,开发者可以在libevent中使用线程相关的函数和特性。

libevent交叉编译详细过程

libevent交叉编译详细过程

libevent交叉编译详细过程libevent是一个轻量级的事件通知库,常用于网络编程中。

对于嵌入式系统,需要将libevent进行交叉编译。

本文将详细介绍libevent交叉编译的过程。

1. 准备交叉编译工具链首先需要准备交叉编译工具链,可以从官网下载或者使用第三方工具链。

这里以arm-none-linux-gnueabi为例。

2. 准备libevent源码从libevent官网下载最新的源码包。

3. 配置环境变量设置交叉编译工具链的环境变量,例如:export CC=arm-none-linux-gnueabi-gccexport CXX=arm-none-linux-gnueabi-g++export AR=arm-none-linux-gnueabi-arexport LD=arm-none-linux-gnueabi-ld4. 配置libevent进入libevent源码目录,执行以下命令进行配置:./configure --host=arm-none-linux-gnueabi如果需要开启SSL支持,可以添加以下参数:./configure --host=arm-none-linux-gnueabi--enable-openssl5. 编译libevent执行make命令进行编译:make6. 安装libevent执行make install命令进行安装:make install7. 交叉编译完成至此,libevent的交叉编译过程完成。

可以将生成的库文件和头文件拷贝到目标系统中使用。

总结libevent交叉编译需要准备交叉编译工具链、libevent源码,配置环境变量、配置libevent、编译libevent、安装libevent。

在交叉编译过程中需要注意平台的区别,例如开启SSL支持需要添加相应的参数。

libevent使用例子从简单到复杂libevent例子

libevent使用例子从简单到复杂libevent例子

Libevent使用例子,从简单到复杂,libevent例子Libevent使用例子,从简单到复杂,libevent例子转载请注明出处:/luotuo44/article/details/39670221本文从简单到复杂,展示怎么使用Libevent。

另外网上的很多例子都是只有服务器端的,本文里面客户端和服务器端都有。

不说这么多了,直接上代码。

初等:客户端代码:#include&lt;sys/types.h&gt;#include&lt;sys/socket.h&gt;#include&lt;netinet/in.h&gt;#include&lt;arpa/inet.h&gt;#include&lt;errno.h&gt;#include&lt;unistd.h&gt;#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;stdlib.h&gt;#include&lt;event.h&gt;#include&lt;event2/util.h&gt;int tcp_connect_server(const char* server_ip, int port);void cmd_msg_cb(int fd, short events, void* arg);void socket_read_cb(int fd, short events, void *arg);int main(int argc, char** argv){if( argc &lt; 3 ){printf("please input 2 parameter\n");return -1;}//两个参数依次是服务器端的IP地址、端口号int sockfd = tcp_connect_server(argv[1], atoi(argv[2]));if( sockfd == -1){perror("tcp_connect error ");return -1;}printf("connect to server successful\n");struct event_base* base = event_base_new();struct event *ev_sockfd = event_new(base, sockfd,EV_READ | EV_PERSIST,socket_read_cb, NULL);event_add(ev_sockfd, NULL);//监听终端输入事件struct event* ev_cmd = event_new(base,STDIN_FILENO,EV_READ | EV_PERSIST, cmd_msg_cb,(void*)&amp;sockfd);event_add(ev_cmd, NULL);event_base_dispatch(base);printf("finished \n");return 0;}void cmd_msg_cb(int fd, short events, void* arg) {char msg[1024];int ret = read(fd, msg, sizeof(msg));if( ret &lt;= 0 ){perror("read fail ");exit(1);}int sockfd = *((int*)arg);//把终端的消息发送给服务器端//为了简单起见,不考虑写一半数据的情况write(sockfd, msg, ret);}void socket_read_cb(int fd, short events, void *arg) {char msg[1024];//为了简单起见,不考虑读一半数据的情况int len = read(fd, msg, sizeof(msg)-1);if( len &lt;= 0 ){perror("read fail ");exit(1);}msg[len] = '\0';printf("recv %s from server\n", msg);}typedef struct sockaddr SA;int tcp_connect_server(const char* server_ip, int port) {int sockfd, status, save_errno;struct sockaddr_in server_addr;memset(&amp;server_addr, 0, sizeof(server_addr) );server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);status = inet_aton(server_ip,&amp;server_addr.sin_addr);if( status == 0 ) //the server_ip is not valid value{errno = EINVAL;return -1;}sockfd = ::socket(PF_INET, SOCK_STREAM, 0);if( sockfd == -1 )return sockfd;status = ::connect(sockfd, (SA*)&amp;server_addr,sizeof(server_addr) );if( status == -1 ){save_errno = errno;::close(sockfd);errno = save_errno; //the close may be errorreturn -1;}evutil_make_socket_nonblocking(sockfd);return sockfd;}服务器端代码:#include&lt;stdio.h&gt;#include&lt;string.h&gt;#include&lt;errno.h&gt;#include&lt;unistd.h&gt;#include&lt;event.h&gt;void accept_cb(int fd, short events, void* arg);void socket_read_cb(int fd, short events, void *arg);int tcp_server_init(int port, int listen_num);int main(int argc, char** argv){int listener = tcp_server_init(9999, 10);if( listener == -1 ){perror(" tcp_server_init error ");return -1;}struct event_base* base = event_base_new();//添加监听客户端请求连接事件struct event* ev_listen = event_new(base, listener, EV_READ | EV_PERSIST,accept_cb, base);event_add(ev_listen, NULL);event_base_dispatch(base);return 0;}void accept_cb(int fd, short events, void* arg){evutil_socket_t sockfd;struct sockaddr_in client;socklen_t len;sockfd = ::accept(fd, (struct sockaddr*)&amp;client, &amp;len );evutil_make_socket_nonblocking(sockfd);printf("accept a client %d\n", sockfd);struct event_base* base = (event_base*)arg;//仅仅是为了动态创建一个event结构体struct event *ev = event_new(NULL, -1, 0, NULL,NULL);//将动态创建的结构体作为event的回调参数event_assign(ev, base, sockfd, EV_READ |EV_PERSIST,socket_read_cb, (void*)ev);event_add(ev, NULL);}void socket_read_cb(int fd, short events, void *arg){char msg[4096];struct event *ev = (struct event*)arg;int len = read(fd, msg, sizeof(msg) - 1); if( len &lt;= 0 ){printf("some error happen when read\n");close(event_get_fd(ev));event_free(ev);return ;}msg[len] = '\0';printf("recv the client msg: %s", msg);char reply_msg[4096] = "I have recvieced the msg: ";strcat(reply_msg + strlen(reply_msg), msg);write(fd, reply_msg, strlen(reply_msg) );}typedef struct sockaddr SA;int tcp_server_init(int port, int listen_num){int errno_save;evutil_socket_t listener;listener = ::socket(AF_INET, SOCK_STREAM, 0);if( listener == -1 )return -1;//允许多次绑定同一个地址。

libevent和基于libevent的网络编程

libevent和基于libevent的网络编程

libevent和基于libevent的⽹络编程1 libevent介绍和安装介绍libevent是⼀个轻量级的基于事件驱动的⾼性能的开源⽹络库,并且⽀持多个平台,对多个平台的I/O复⽤技术进⾏了封装,当我们编译库的代码时,编译的脚本将会根据OS⽀持的处理事件机制,来编译相应的代码,从⽽在libevent接⼝上保持⼀致。

在当前的服务器上,⾯对的主要问题就是要能处理⼤量的连接。

⽽通过libevent这个⽹络库,我们就可以调⽤它的API来很好的解决上⾯的问题。

⾸先,可以来回顾⼀下,对这个问题的传统解决⽅法。

问题:如何处理多个客户端连接解决⽅案1:I/O复⽤技术这⼏种⽅式都是同步I/O,即当读写事件就绪,他们⾃⼰需要负责进⾏读写,这个读写过程是阻塞的,⽽异步I/O则不需要⾃⼰负责读写,只需要通知负责读写的程序就可以了。

循环假设当前我服务器有多个⽹络连接需要看管,那么我就循环遍历打开的⽹络连接的列表,来判断是否有要读取的数据。

这种⽅法的缺点很明显,那就是 1.速度缓慢(必须遍历所有的⽹络连接) 2.效率低(处理⼀个连接时可能发⽣阻塞,妨碍其他⽹络连接的检查和处理)select⽅式select对应于内核中的sys_select调⽤,sys_select⾸先将第⼆三四个参数指向的fd_set拷贝到内核,然后对每个被SET的描述符调⽤进⾏poll,并记录在临时结果中(fdset),如果有事件发⽣,select会将临时结果写到⽤户空间并返回;当轮询⼀遍后没有任何事件发⽣时,如果指定了超时时间,则select会睡眠到超时,睡眠结束后再进⾏⼀次轮询,并将临时结果写到⽤户空间,然后返回。

select返回后,需要逐⼀检查关注的描述符是否被SET(事件是否发⽣)。

(select⽀持的⽂件描述符数量太⼩了,默认是1024)。

poll⽅式poll与select不同,通过⼀个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,pollfd中的events字段和revents分别⽤于标⽰关注的事件和发⽣的事件,故pollfd数组只需要被初始化⼀次。

libevent源码解析

libevent源码解析

libevent源码解析libevent是一个事件触发型的网络通信库,它主要用于实现高效、可扩展、高并发的网络通信,广泛应用于服务器程序的开发中。

libevent源码可运行于Windows、Linux等操作系统,并提供了C、C++、Python等多种语言接口,被广泛应用于各种网络通信场景。

libevent源码的主要结构及功能libevent的设计基于事件驱动的思想,实现了高效的异步非阻塞I/O模型。

它能够有效地处理大量的并发连接请求,支持多种协议、多路复用、定时器、信号处理等功能,是一个功能强大、易于扩展的网络通信库。

其源码主要包括以下几个重要的结构和功能:1. event_base:这是libevent的核心结构,他负责管理和调度所有事件,包括I/O事件、信号事件、定时器事件等。

event_base可以同时处理多个不同类型的事件,并且支持事件优先级和超时事件的处理。

libevent库中所有其他的结构都需要与event_base关联才能生效。

2. event:event是事件处理的最小单位,它代表一个被监视的文件描述符或是一个信号等。

当文件描述符有数据可读写或者信号触发时,就会触发相应的事件处理程序。

每个event都需要与一个event_base关联,以便能够得到正确的事件调度。

3. evutil:evutil是libevent的基本工具库,主要提供了跨平台的网络编程接口,如字符串操作、字符串解析、socket地址解析等。

evutil是libevent实现的基础库,所有其他高层次的实现都依赖于它。

4. bufferevent:这是一个对I/O进行封装的结构,用于处理基于缓存的I/O通信、数据包的发送和接收等功能。

它可以自动处理TCP流的拆分和合并,同时实现了读写缓冲区管理、超时和错误处理等功能。

5. timeval:这是一个时间相关的结构,主要用于管理事件的超时处理和事件的定时器操作。

libevent中事件操作的时间精度为微秒级。

libevent evthread_use_pthreads -回复

libevent evthread_use_pthreads -回复

libevent evthread_use_pthreads -回复libevent是一个开源的事件驱动编程库,用于在网络应用中处理并发事件。

它提供了跨平台的、高性能的事件处理机制,可以用于开发高效的网络服务器和客户端应用程序。

其中的evthread_use_pthreads函数是libevent 库中的一个函数,用于指定使用pthreads作为并发处理的线程模型。

本文将详细介绍libevent和evthread_use_pthreads函数,以及如何使用它来构建高并发的网络应用程序。

一、libevent简介libevent是一个基于事件驱动的编程库,最初由Niels Provos和Nick Mathewson于2000年开发。

它提供了跨平台的API,可以在各种操作系统上运行。

libevent的目标是提供一种简单、高效的方式来处理并发事件,无论是网络应用还是其他类型的应用,都可以通过libevent来实现高性能和可伸缩性。

libevent的核心概念是事件循环(event loop)机制。

在libevent中,所有的I/O操作都被转化为事件,应用程序通过注册回调函数来处理这些事件。

当一个事件发生时,libevent会将其分发给相应的回调函数进行处理。

这种事件驱动的方式使得应用程序可以同时处理多个并发事件,而不需要为每个事件创建一个独立的线程。

libevent提供了一系列的函数和数据结构来支持事件处理。

它可以处理各种类型的事件,包括网络I/O事件、定时器事件、信号事件等。

通过注册合适的回调函数,应用程序可以根据需要处理不同类型的事件。

二、evthread_use_pthreads函数evthread_use_pthreads函数是libevent库中的一个函数,用于指定使用pthreads作为并发处理的线程模型。

具体来说,它将libevent的并发处理模型设置为使用pthread线程库来创建和管理线程。

libevent源码分析event_base_dispatch,event_base_lo。。。

libevent源码分析event_base_dispatch,event_base_lo。。。

libevent源码分析event_base_dispatch,event_base_lo。

接⼝:event_base_dispatch/**Event dispatching loop 事件分配循环This loop will run the event base until either there are no more pending oractive, or until something calls event_base_loopbreak() orevent_base_loopexit().这个循环将会运⾏event base,知道没有等待的或者活动的事件,或者其它的调⽤了event_base_loopbreak()或event_base_loopexit().@param base the event_base structure returned by event_base_new() orevent_base_new_with_config() event_base_new() 或者 event_base_new_with_config() 返回的event_base对象@return 0 if successful, -1 if an error occurred, or 1 if we exited becauseno events were pending or active. 成功返回0,错误返回-1,或者1(当没有等待的或者活动事件时退出,会返回1)@see event_base_loop()*/EVENT2_EXPORT_SYMBOLint event_base_dispatch(struct event_base *base);intevent_base_dispatch(struct event_base *event_base){return (event_base_loop(event_base, 0));}跟踪event_base_loop接⼝/**Wait for events to become active, and run their callbacks.等待events 变成活动的,并运⾏对应的回调函数。

libevent源码深度剖析

libevent源码深度剖析

libevent源码深度剖析第⼀章1,前⾔Libevent是⼀个轻量级的开源⾼性能⽹络库,使⽤者众多,研究者更甚,相关⽂章也不少。

写这⼀系列⽂章的⽤意在于,⼀则分享⼼得;⼆则对libevent代码和设计思想做系统的、更深层次的分析,写出来,也可供后来者参考。

附带⼀句:Libevent是⽤c语⾔编写的(MS⼤⽜们都偏爱c语⾔哪),⽽且⼏乎是⽆处不函数指针,学习其源代码也需要相当的c语⾔基础。

2,libevent简介上来当然要先夸奖啦,Libevent 有⼏个显著的亮点:=> 事件驱动(event-driven),⾼性能;=> 轻量级,专注于⽹络,不如ACE那么臃肿庞⼤;=> 源代码相当精炼、易读;=> 跨平台,⽀持Windows、Linux、*BSD和Mac Os;=> ⽀持多种I/O多路复⽤技术, epoll、poll、dev/poll、select和kqueue等;=> ⽀持I/O,定时器和信号等事件;=> 注册事件优先级;Libevent已经被⼴泛的应⽤,作为底层的⽹络库;⽐如memcached、Vomit、Nylon、Netchat等等。

Libevent当前的最新稳定版是1.4.13;这也是本⽂参照的版本。

3,学习的好处学习libevent有助于提升程序设计功⼒,除了⽹络程序设计⽅⾯外,Libevent的代码⾥有很多有⽤的设计技巧和基础数据结构,⽐如信息隐藏、函数指针、c语⾔的多态⽀持、链表和堆等等,都有助于提升⾃⾝的程序功⼒。

程序设计不⽌要了解框架,很多细节之处恰恰也是事关整个系统成败的关键。

只对libevent本⾝的框架⼤概了解,那或许仅仅是⼀知半解,不深⼊代码分析,就难以了解其设计的精巧之处,也就难以为⾃⼰所⽤。

事实上Libevent本⾝就是⼀个典型的Reactor模型,理解Reactor模式是理解libevent的基⽯;因此下⼀节将介绍典型的事件驱动设计模式——Reactor模式。

libevent源码event_config_new(),event_base_new_w。。。

libevent源码event_config_new(),event_base_new_w。。。

libevent源码event_config_new(),event_base_new_w。

struct event_config *event_config_new(void);/**Allocates a new event configuration object. 分配⼀个新的event_config对象The event configuration object can be used to change the behavior ofan event base. event_config对象可以⽤于更改event base的⾏为@return an event_config object that can be used to store configuration, orNULL if an error is encountered. 返回⼀个event_config 对象,由于存储配置,当发⽣错误返回NULL@see event_base_new_with_config(), event_config_free(), event_config*/struct event_base *event_base_new_with_config(const struct event_config *);/**Initialize the event API. 初始化event接⼝Use event_base_new_with_config() to initialize a new event base, takingthe specified configuration under consideration. The configuration objectcan currently be used to avoid certain event notification mechanisms. 通过event_base_new_with_config(),使⽤指定位置的配置来初始化⼀个新的event base.使⽤的配置对象可⽤于避免默写事件通知机制。

Libevent学习——事件主循环

Libevent学习——事件主循环

Libevent学习——事件主循环8.1、Libevent的事件主循环主要是通过event_base_loop ()函数完成的,其主要操作如下⾯的流程图所⽰,event_base_loop 所作的就是持续执⾏下⾯的循环。

来看下函数源码:intevent_base_loop(struct event_base *base, int flags){const struct eventop *evsel = base->evsel;//多路复⽤IOstruct timeval tv;struct timeval *tv_p;int res, done, retval = 0;EVBASE_ACQUIRE_LOCK(base, th_base_lock);if (base->running_loop) {//检测event_base_loop是否已经运⾏,每个event_base只有⼀个event_base_loopevent_warnx("%s: reentrant invocation. Only one event_base_loop"" can run on each event_base at once.", __func__);EVBASE_RELEASE_LOCK(base, th_base_lock);return -1;}base->running_loop = 1;clear_time_cache(base);//清空时间缓存if (base->sig.ev_signal_added && base->sig.ev_n_signals_added)evsig_set_base(base);// evsignal_base是全局变量,在处理signal时,⽤于指名signal所属的event_base实例done = 0;#ifndef _EVENT_DISABLE_THREAD_SUPPORTbase->th_owner_id = EVTHREAD_GET_ID();#endifbase->event_gotterm = base->event_break = 0;while (!done) {// 事件主循环base->event_continue = 0;if (base->event_gotterm) {break;// 查看是否需要跳出循环,程序可以调⽤event_loopexit_cb()设置event_gotterm标记}if (base->event_break) {break;// 调⽤event_base_loopbreak()设置event_break标记}// 校正系统时间,如果系统使⽤的是⾮MONOTONIC时间,⽤户可能会向后调整了系统时间// 在timeout_correct函数⾥,⽐较last wait time和当前时间,如果当前时间< last wait time// 表明时间有问题,这是需要更新timer_heap中所有定时事件的超时时间。

Libevent源码分析—event_add()

Libevent源码分析—event_add()

Libevent源码分析—event_add()接下来就是将已经初始化的event注册到libevent的事件链表上,通过event_add()来实现,源码位于event.c中。

event_add()这个函数主要完成了下⾯⼏件事:1.将event注册到event_base的I/O多路复⽤要监听的事件中2.将event注册到event_base的已注册事件链表中3.如果传⼊了超时时间,则删除旧的超时时间,重新设置,并将event添加到event_base的⼩根堆中;如果没有传⼊超时时间,则不会添加到⼩根堆中。

只有步骤1成功,才会执⾏步骤2和3;否则什么都没做,直接返回,保证不会改变event的状态。

从中还可以看到,将event添加到已注册事件链表、添加到⼩根堆、从活跃事件链表移除、从⼩根堆中移除,都是通过两个函数完成的:event_queue_insert()、event_queue_remove()intevent_add(struct event *ev, const struct timeval *tv){struct event_base *base = ev->ev_base; //event所属的event_baseconst struct eventop *evsel = base->evsel; //event_base的I/O多路复⽤机制void *evbase = base->evbase; //event_base的I/O多路复⽤机制int res = 0;//DEBUG log.hevent_debug(("event_add: event: %p, %s%s%scall %p",ev,ev->ev_events & EV_READ ? "EV_READ " : "",ev->ev_events & EV_WRITE ? "EV_WRITE " : "",tv ? "EV_TIMEOUT " : "",ev->ev_callback));assert(!(ev->ev_flags & ~EVLIST_ALL));/** prepare for timeout insertion further below, if we get a* failure on any step, we should not change any state.*///如果传⼊了超时时间并且event不再time⼩根堆上,则在⼩根堆上预留⼀个位置//以保证如果后⾯有步骤失败,不会改变初始状态,保证是个原⼦操作if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {if (min_heap_reserve(&base->timeheap, //min_heap.h1 + min_heap_size(&base->timeheap)) == -1)return (-1); /* ENOMEM == errno */}//如果event不在已注册链表或活跃链表中,//则调⽤evsel->add()注册event事件到I/O多路复⽤监听的事件上if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&!(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {res = evsel->add(evbase, ev); //将event注册到监听事件上//注册监听事件成功,则将event注册到已注册事件链表上if (res != -1)event_queue_insert(base, ev, EVLIST_INSERTED); //插⼊}/** we should change the timout state only if the previous event* addition succeeded.*///前⾯操作都成功情况下,才能执⾏下⾯步骤//改变超时状态if (res != -1 && tv != NULL) {struct timeval now;/** we already reserved memory above for the case where we* are not replacing an exisiting timeout.*///EVLIST_TIMEOUT表明event已在定时器堆中//则删除旧的定时器if (ev->ev_flags & EVLIST_TIMEOUT)event_queue_remove(base, ev, EVLIST_TIMEOUT); //移除/* Check if it is active due to a timeout. Rescheduling* this timeout before the callback can be executed* removes it from the active list. *///如果事件是由于超时⽽变成活跃事件//则从活跃事件链表中删除if ((ev->ev_flags & EVLIST_ACTIVE) &&(ev->ev_res & EV_TIMEOUT)) {/* See if we are just active executing thisif (ev->ev_ncalls && ev->ev_pncalls) {/* Abort loop */*ev->ev_pncalls = 0; //调⽤次数清0}//从活跃事件链表移除event_queue_remove(base, ev, EVLIST_ACTIVE); //移除}gettime(base, &now);evutil_timeradd(&now, tv, &ev->ev_timeout); //为event添加超时时间event_debug(("event_add: timeout in %ld seconds, call %p",tv->tv_sec, ev->ev_callback));//将event插⼊到⼩根堆中event_queue_insert(base, ev, EVLIST_TIMEOUT); //插⼊}return (res);}event_queue_insert()该函数根据不同的输⼊队列,即不同的事件,在不同的队列中插⼊,并增加相应的事件计数,更新event状态;EVLIST_INSERTED:在已注册事件链表event_base.eventqueue插⼊EVLIST_ACTIVE:根据event优先级,在活跃事件链表event_base.activequeues[event.ev_pri]插⼊EVLIST_TIMEOUT:在⼩根堆event_base.timeheap中插⼊voidevent_queue_insert(struct event_base *base, struct event *ev, int queue){//如果event已经在活跃链表中,则返回;否则,出错if (ev->ev_flags & queue) {/* Double insertion is possible for active events */if (queue & EVLIST_ACTIVE)return;event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,ev, ev->ev_fd, queue);}if (~ev->ev_flags & EVLIST_INTERNAL)base->event_count++; //增加注册事件数ev->ev_flags |= queue; //改变event状态switch (queue) { //根据不同的输⼊参数队列,选择在不同的事件集合中插⼊case EVLIST_INSERTED: //I/O或Signal事件TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next); //在已注册事件链表插⼊break;case EVLIST_ACTIVE: //活跃事件base->event_count_active++; //增加活跃事件数TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri], //在活跃事件链表插⼊ev,ev_active_next);break;case EVLIST_TIMEOUT: { //定时器事件min_heap_push(&base->timeheap, ev); //在⼩根堆插⼊break;}default:event_errx(1, "%s: unknown queue %x", __func__, queue);}}event_queue_remove()和event_queue_insert()相对应,这个函数主要根据不同的输⼊参数,从不同的事件集合中删除事件。

libevent源码分析

libevent源码分析

libevent源码分析这两天没事,看了⼀下Memcached和libevent的源码,做个⼩总结。

1、⼊门1.1、概述Libevent是⼀个⽤于开发可扩展性⽹络服务器的基于事件驱动(event-driven)模型的⽹络库。

Libevent有⼏个显著的亮点:(1)事件驱动(event-driven),⾼性能;(2)轻量级,专注于⽹络,不如 ACE 那么臃肿庞⼤;(3)源代码相当精炼、易读;(4)跨平台,⽀持 Windows、Linux、*BSD和 Mac Os;(5)⽀持多种 I/O多路复⽤技术, epoll、poll、dev/poll、select 和kqueue 等;(6)⽀持 I/O,定时器和信号等事件;(7)注册事件优先级;Libevent 已经被⼴泛的应⽤,作为底层的⽹络库;⽐如 memcached、 Vomi t、 Nylon、 Netchat等等。

1.2、⼀个简单⽰例代码1int lasttime;23static void4 timeout_cb(int fd, short event, void *arg)5 {6struct timeval tv;7struct event *timeout = arg;8int newtime = time(NULL);910//printf("%s: called at %d: %d\n", __func__, newtime,11 printf("%s: called at %d: %d\n", "timeout_cb", newtime,12 newtime - lasttime);13 lasttime = newtime;1415 evutil_timerclear(&tv);16 _sec = 2;17//重新注册event18 event_add(timeout, &tv);19 }2021int22 main (int argc, char **argv)23 {24struct event timeout;25struct timeval tv;2627/* Initalize the event library */28//初始化event环境29 event_init();3031/* Initalize one event */32//设置事件33 evtimer_set(&timeout, timeout_cb, &timeout);3435 evutil_timerclear(&tv);36 _sec = 2;37//注册事件38 event_add(&timeout, &tv);3940 lasttime = time(NULL);4143 event_dispatch();4445return (0);46 }这是⼀个简单的基于libevent的定时器程序,运⾏结果:⽤libevent编程⾮常简单,只需要调⽤event_init初始化环境,然后调⽤event_add注册相应的事件,接着调⽤event_dispatch等待并处理相应的事件即可。

libevent 编译

libevent 编译

libevent 编译libevent 是一个开源的、轻量级的事件驱动库,被广泛用于网络服务器和应用程序开发中。

它提供了一个简单而高效的方式来处理并发网络连接和事件驱动编程。

本文将介绍libevent的基本概念、特性和使用方法。

一、libevent的基本概念1. 事件循环:libevent的核心是事件循环,它负责监听和分发事件。

事件循环可以理解为一个无限循环,不断地等待事件的发生并处理它们。

2. 事件:事件是指一个特定的操作或状态,可以是网络连接建立、数据可读、定时器到期等。

libevent可以监听多种类型的事件,并在事件发生时进行相应的处理。

3. 回调函数:libevent使用回调函数来处理事件。

当某个事件发生时,libevent会调用相应的回调函数来处理该事件。

开发者需要提供回调函数的实现,以定义事件发生时的具体行为。

4. 事件驱动:libevent采用事件驱动的编程模型,即程序通过监听和处理事件来驱动程序的执行。

相比于传统的顺序执行模型,事件驱动模型更加高效和灵活。

二、libevent的特性1. 跨平台:libevent可以在多种操作系统上运行,包括Linux、Windows、MacOS等,具有良好的跨平台性。

2. 高性能:libevent采用非阻塞的IO模型,能够处理大量并发连接,具有出色的性能表现。

3. 多种网络协议支持:libevent支持TCP、UDP、HTTP等多种网络协议,可以满足不同应用场景的需求。

4. 定时器支持:libevent提供了定时器功能,可以方便地实现定时任务的调度。

5. 可扩展性:libevent的设计非常灵活,可以方便地扩展和定制,满足各种复杂的需求。

三、使用libevent进行事件驱动编程1. 初始化libevent:使用event_base_new()函数初始化一个事件基础结构体,并通过event_base_dispatch()函数进入事件循环。

2. 创建事件:使用event_new()函数创建一个事件,并指定事件类型和相关的回调函数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
用“好莱坞原则”来形容 Reactor 再合适不过了:不要打电话给我们,我们会打电话通 知你。
举个例子:你去应聘某 xx 公司,面试结束后。 “普通函数调用机制”公司 HR 比较懒,不会记你的联系方式,那怎么办呢,你只能面试完 后自己打电话去问结果;有没有被录取啊,还是被据了;
“Reactor”公司 HR 就记下了你的联系方式,结果出来后会主动打电话通知你:有没有被录 取啊,还是被据了;你不用自己打电话去问结果,事实上也不能,你没有 HR 的留联系方式。
3 Reactor 模式框架
使用 Reactor 模型,必备的几个组件:事件源、Reactor 框架、多路复用机制和事件处理 程序,先来看看 Reactor 模型的整体框架,接下来再对每个组件做逐一说明。
1) 事件源 Linux 上是文件描述符,Windows 上就是 Socket 或者 Handle 了,这里统一称为“句柄集”; 程序在指定的句柄上注册关心的事件,比如 I/O 事件。
事实上 Libevent 本身就是一个典型的 Reactor 模型,理解 Reactor 模式是理解 libevent 的基石; 因此下一节将介绍典型的事件驱动设计模式——Reactor 模式。
参考资料: Libevent: /~provos/libevent/
Reactor 模式
件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。 对应到 libevent 中,就是 event_base 结构体。 一个典型的 Reactor 声明方式 view plaincopy to clipboardprint? class Reactor { public:
int register_handler(Event_Handler *pHandler, int event); int remove_handler(Event_Handler *pHandler, int event); void handle_events(timeval *ptv); // ... }; class Reactor
2) event demultiplexer——事件多路分发机制 由操作系统提供的 I/O 多路复用机制,比如 select 和 epoll。
程序首先将其关心的句柄(事件源)及其事件注册到 event demultiplexer 上; 当有事件到达时,event demultiplexer 会发出通知“在已经注册的句柄集中,一个或多个句 柄的事件已经就绪”;
2)初始化事件 event,设置回调函数和关注的事件 evtimer_set(&ev, timer_cb, NULL); 事实上这等价于调用 event_set(&ev, -1, 0, timer_cb, NULL); event_set 的函数原型是: void event_set(struct event *ev, int fd, short event, void (*cb)(int, short, void *), void *arg) ev:执行要初始化的 event 对象; fd:该 event 绑定的“句柄”,对于信号事件,它就是关注的信号; event:在该 fd 上关注的事件类型,它可以是 EV_READ, EV_WRITE, EV_SIGNAL; cb:这是一个函数指针,当 fd 上的事件 event 发生时,调用该函数执行处理,它有三个参数, 调用时由 event_base 负责传入,按顺序,实际上就是 event_set 时的 fd, event 和 arg; arg:传递给 cb 函数指针的参数; 由于定时事件不需要 fd,并且定时事件是根据添加时(event_add)的超时值设定的,因此 这里 event 也不需要设置。 这一步相当于初始化一个 event handler,在 libevent 中事件类型保存在 event 结构体中。 注意:libevent 并不会管理 event 事件集合,这需要应用程序自行管理;
{ public:
int register_handler(Event_Handler *pHandler, int event); int remove_handler(Event_Handler *pHandler, int event); void handle_events(timeval *ptv); // ... }; 4) Event Handler——事件处理程序 事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供 Reactor 在相应的 事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。 对应到 libevent 中,就是 event 结构体。 下面是两种典型的 Event Handler 类声明方式,二者互有优缺点。 view plaincopy to clipboardprint? class Event_Handler { public: virtual void handle_read() = 0; virtual void handle_write() = 0; virtual void handle_timeout() = 0; virtual void handle_close() = 0; virtual HANDLE get_handle() = 0; // ... }; class Event_Handler { public: // events maybe read/write/timeout/close .etc virtual void handle_events(int events) = 0; virtual HANDLE get_handle() = 0; // ... }; class Event_Handler { public: virtual void handle_read() = 0; virtual void handle_write() = 0; virtual void handle_timeout() = 0; virtual void handle_close() = 0; virtual HANDLE get_handle() = 0; // ... }; class Event_Handler { public:
程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。 对应到 libevent 中,依然是 select、poll、epoll 等,但是 libevent 使用结构体 eventop 进行了 封装,以统一的接口来支持这些 I/O 多路复用机制,达到了对外隐藏底层系统机制的目的。
3) Reactor——反应器 Reactor,是事件管理的接口,内部使用 event demultiplexer 注册、注销事件;并运行事
// events maybe read/write/timeout/close .etc virtual void handle_events(int events) = 0; virtual HANDLE get_handle() = 0; // ... };
4 Reactor 事件处理流程
前面说过 Reactor 将事件流“逆置”了,那么使用 Reactor 模式后,事件控制流是什么样子 呢? 可以参见下面的序列图。
Libevent 简介
上来当然要先夸奖啦,Libevent 有几个显著的亮点: 事件驱动(event-driven),高能; 轻量级,专注于网络,不如 ACE 那么臃肿庞大; 源代码相当精炼、易读; 跨平台,支持 Windows、Linux、*BSD 和 Mac Os; 支持多种 I/O 多路复用技术, epoll、poll、dev/poll、select 和 kqueue 等; 支持 I/O,定时器和信号等事件; 注册事件优先级;
5 小结
上面讲到了 Reactor 的基本概念、框架和处理流程,对 Reactor 有个基本清晰的了解后,再
来对比看 libevent 就会更容易理解了,接下来就正式进入到 libevent 的代码世界了,加油!
参考资料: Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects, Volume 2
前面讲到,整个 libevent 本身就是一个 Reactor,因此本节将专门对 Reactor 模式进行必要的 介绍,并列出 libevnet 中的几个重要组件和 Reactor 的对应关系,在后面的章节中可能还会 提到本节介绍的基本概念。
1 Reactor 的事件处理机制
首先来回想一下普通函数调用的机制:程序调用某函数?函数执行,程序等待?函数将结果和 控制权返回给程序?程序继续处理。 Reactor 释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用程序 不是主动的调用某个 API 完成处理,而是恰恰相反,Reactor 逆置了事件处理流程,应用程 序需要提供相应的接口并注册到 Reactor 上,如果相应的时间发生,Reactor 将主动调用应用 程序注册的接口,这些接口又称为“回调函数”。使用 Libevent 也是想 Libevent 框架注册相 应的事件和回调函数;当这些时间发声时,Libevent 会调用这些回调函数处理相应的事件(I/O 读写、定时和信号)。
Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、Vomit、Nylon、Netchat 等等。 Libevent 当前的最新稳定版是 1.4.13;这也是本文参照的版本。
学习的好处
学习 libevent 有助于提升程序设计功力,除了网络程序设计方面外,Libevent 的代码里有很 多有用的设计技巧和基础数据结构,比如信息隐藏、函数指针、c 语言的多态支持、链表和 堆等等,都有助于提升自身的程序功力。 程序设计不止要了解框架,很多细节之处恰恰也是事关整个系统成败的关键。只对 libevent 本身的框架大概了解,那或许仅仅是一知半解,不深入代码分析,就难以了解其设计的精巧 之处,也就难以为自己所用。
相关文档
最新文档