(转)Libevent(1)— 简介、编译、配置

转自:http://name5566.com/4190.html

参考文献列表:
http://www.wangafu.net/~nickm/libevent-book/

此文编写的时候,使用到的 Libevent 为 2.0.21

Libevent 之跨平台

在处理大量 SOCKET 连接时,使用 select 并不高效。各个系统都提供了处理大量 SOCKET 连接时的解决方案:

  1. Linux 下的 epoll()
  2. BSD 下的 kqueue()
  3. Solaris 下的 evports
  4. Windows 下的 IOCP

由于各个平台使用了不同的接口,那么我们需要编写跨平台的高性能异步程序时就需要做一层跨平台封装。
这个时候 Libevent 就成为一个较好的选择,其最底层 API(event 和 event_base API)为各个平台实现高性能异步程序提供了一致的接口。

Libevent 2 提供的 bufferevent 接口,一方面简化了编程的难度,另一方面保证了在 Windows 和 Unix 上都很高效。

一些基本的概念

  1. event 会绑定文件描述符、回调函数并表示一个或者多个条件(例如,文件描述符可以读或者写了、发生了超时等)。event 表示的条件如果被触发了,那么 event 会变为活跃的,它绑定的回调函数就会被执行
  2. event_base 用于持有一组 event 并进行事件循环,event_base 会存在一个后端(也叫做方法),常见的后端包括 epoll、kqueue 等

Libevent 的结构

组件:

  1. evutil 用于抽象不同的平台的网络(基础的)实现
  2. event、event_base 为 Libevent 的核心,为不同的平台下基于事件的非阻塞 I/O 提供了一套抽象的接口
  3. bufferevent 对 Libevent 的基于事件的核心的封装。应用程序的读写请求是基于缓冲区的
  4. evbuffer 为 bufferevent 实现的缓冲区
  5. evhttp 一个简单的 HTTP client/server 的实现
  6. evdns 一个简单的 DNS client/server 的实现
  7. evrpc 一个简单的 RPC 实现

库:

  1. libevent_core 包括 util、event_base、evbuffer、bufferevent
  2. libevent_extra 包括 HTTP、DNS、RPC
  3. libevent 此库由于历史原因而存在,不要使用它
  4. libevent_pthreads 此库为基于 pthread 的线程和锁的实现
  5. libevent_openssl 此库通过 openssl 和 bufferevent 提供了加密通讯

头文件:
所有的公用头文件位于 event2 目录中。

编译 Libevent 库

Linux 下编译的方式为(详细见 README):

  1. $ ./configure
  2. $ make

常用的 configure 标志有:

  1. --disable-shared 只编译静态库
  2. --disable-openssl 关闭 OpenSSL 加密支持

Windows 下编译的方式为:

  1. nmake /f Makefile.nmake

需要注意的是,虽然官方提供了此 makefile,但是此文件尚未编写完善(详见 Makefile.nmake 的注释)
编译完成之后,需要将 WIN32-Code 目录加入到 VS 的 include paths 中去

设置 Libevent 库

在具体的介绍之前,这里首先需要明确的一点是,我们总是先设置 Libevent,然后才去使用 Libevent。

关于输出日志的设置

Libevent 的日志信息默认被写入 stderr(标准错误),我们可以提供自己的日志处理函数给 Libevent:

  1. // 日志的类型
  2. #define EVENT_LOG_DEBUG 0
  3. #define EVENT_LOG_MSG 1
  4. #define EVENT_LOG_WARN 2
  5. #define EVENT_LOG_ERR 3
  6. // 日志处理函数原型
  7. // severity 参数对应了上面的各种日志类型
  8. typedef void (*event_log_cb)(int severity, const char *msg);
  9. // 设置一个新的日志处理函数
  10. void event_set_log_callback(event_log_cb cb);

设置日志处理函数的范例:

  1. #include <event2/event.h>
  2. #include <stdio.h>
  3. static void discard_cb(int severity, const char *msg)
  4. {
  5. // 此函数不做任何事情
  6. }
  7. static FILE *logfile = NULL;
  8. static void write_to_file_cb(int severity, const char *msg)
  9. {
  10. const char *s;
  11. if (!logfile)
  12. return;
  13. switch (severity) {
  14. case _EVENT_LOG_DEBUG: s = "debug"; break;
  15. case _EVENT_LOG_MSG: s = "msg"; break;
  16. case _EVENT_LOG_WARN: s = "warn"; break;
  17. case _EVENT_LOG_ERR: s = "error"; break;
  18. default: s = "?"; break; /* never reached */
  19. }
  20. fprintf(logfile, "[%s] %s\n", s, msg);
  21. }
  22. // 关闭 Libevent 的日志信息的输出
  23. void suppress_logging(void)
  24. {
  25. event_set_log_callback(discard_cb);
  26. }
  27. // 设置 Libevent 的日志信息输出到特定文件
  28. void set_logfile(FILE *f)
  29. {
  30. logfile = f;
  31. event_set_log_callback(write_to_file_cb);
  32. }

关于日志的注意事项:

  1. 日志处理函数中不要调用任何的 Libevent 函数
  2. Debug 日志信息默认不会被输出,一般也不需要

Libevent 处理致命错误的做法是调用 exit() 或者 abort() 函数,你可以修改此行为(例如,你希望此时输出调用栈信息):

  1. typedef void (*event_fatal_cb)(int err);
  2. void event_set_fatal_callback(event_fatal_cb cb);

注意事项:

  1. 我们定义的 event_fatal_cb 函数不要将控制权再返回给 Libevent
  2. 不要在 event_fatal_cb 函数中调用任何的 Libevent 函数
为 Libevent 定义自己的内存管理器

默认的情况下 Libevent 使用 C 库的内存管理函数从堆上分配内存。替换 Libevent 默认内存管理函数主要有以下几个目的:

  1. 更加高效的分配内存
  2. 检测内存泄漏

设置自己定义的内存管理函数:

  1. void event_set_mem_functions(void *(*malloc_fn)(size_t sz),
  2. void *(*realloc_fn)(void *ptr, size_t sz),
  3. void (*free_fn)(void *ptr));

替换 Libevent 内存管理函数时需要注意的地方:

  1. 正如前面说到的,所有设置应该在 Libevent 被使用之前完成,对于内存管理的配置来说更加是如此,否则可能引起崩溃
  2. 你设定的内存管理函数必须是线程安全的
  3. 你设定的 malloc 和 realloc 返回的内存地址的对齐需要和 C 库一致
  4. 你设定的 realloc 需要能够处理 realloc(NULL, sz)
  5. 你设定的 realloc 需要能够处理 realloc(ptr, 0)
关闭和清理

我们关闭程序的时候,需要完成一些清理工作:

  1. void libevent_global_shutdown(void);

此函数在 2.1.1-alpha 才被引入。

Libevent 多线程的问题

如果你希望 Libevent 函数分配的结构能够被多个线程共享,那么首先需要告知 Libevent 我们使用的锁定函数。如果使用 pthreads 库或者使用 Windows 线程,可以调用以下函数来进行设置:

  1. // 这两个函数成功返回 0 失败返回 -1
  2. #ifdef WIN32
  3. int evthread_use_windows_threads(void);
  4. #define EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
  5. #endif
  6. #ifdef _EVENT_HAVE_PTHREADS
  7. int evthread_use_pthreads(void);
  8. #define EVTHREAD_USE_PTHREADS_IMPLEMENTED
  9. #endif

void evthread_enable_lock_debuging(void) 函数可以让 Libevent 通过 assert 告知我们关于锁的一些错误信息,主要是告知我们解锁了一个未持有的锁。我们需要在任意一个锁被创建或使用之前调用此函数。

void event_enable_debug_mode(void) 函数可以让 Libevent 检测 event 使用上的一些错误:

  1. 认为一个未初始化的 event 已经初始化了
  2. 尝试重新初始化一个 pending event(pending event 为一个术语,之后的文章会谈到)

注意的是,开启 debug 模式(也就是调用 event_enable_debug_mode)后,会有额外的内存和 CPU 开销,所以应该在真正调试的时候再开启。event_enable_debug_mode 函数需要在任意的 event_base 被创建前调用。

时间: 2024-10-26 17:08:12

(转)Libevent(1)— 简介、编译、配置的相关文章

Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装

原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底,同时在博文中如果那些地方有问题还请各位大神为我讲解. 今天我们会分析到以下内容: 1.      Linux体系结构简介 2.      Linux内核源码简介 3.      Linux内核配置.编译.安装 l  Linux体系结构简介 1.       Linux体系结构(linux系统构成)

转载:Centos7 从零编译配置Memcached

序言 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度. Memcached基于一个存储键/值对的hashmap.其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信. 当然memcached分为服务端和客户端.服务端用来存放缓存,客户端用来操作缓存. 客户端有两种常见的实现方式. 第一种是用php代码根

Kernel 编译配置机制

编译kernel前需要一个配置相关的编译选项,最终的配置文件就是kernel根目录路下的 .config 文件 一:.config 这个文件里面保存的是kernel的配置选项,格式如下: CONFIG_XX_XX=y/n/m/0xFFFFFF/32/"XXXXXXX" 这个文件由/scripts/kconfig/mconf.c负责解析,然后解析该文件并将解析结果以宏定义的形式写入到/include/generated/autoconf.h中./include/generated/aut

深入浅出Mybatis系列(六)---objectFactory、plugins、mappers简介与配置[转]

上篇文章<深入浅出Mybatis系列(五)---TypeHandler简介及配置(mybatis源码篇)>简单看了一下TypeHandler, 本次将结束对于mybatis的配置文件的学习, 本次涉及到剩下没提及到的几个节点的配置:objectFactory.databaseIdProvider.plugins.mappers. 那么,接下来,就简单介绍一下这几个配置的作用吧: 1.objectFactory是干什么的? 需要配置吗? MyBatis 每次创建结果对象的新实例时,它都会使用一个

大型项目使用Automake/Autoconf完成编译配置

使用过开源C/C++项目的同学们都知道,标准的编译过程已经变成了简单的三部曲:configure/make/make install, 使用起来很方便,不像平时自己写代码,要手写一堆复杂的Makefile,而且换个编译环境,Makefile还需要修改(Eclipse也是这样). 这么好的东东当然要拿来用了,但GNU的Autotool系列博大精深,工具数量又多,涉及的语言也多,要是自己从头看到尾,黄花菜都凉了,项目估计早就结束了:上网搜样例倒是有一大堆,但都是“hello world”的样例,离真

第4阶段——制作根文件系统之编译配置安装busybox(3)

在上一节分析出制作一个最小的根文件系统至少需要: (1)/dev/console(终端控制台, 提供标准输入.标准输出以及标准错误) /dev/null  (为空的话就是/dev/null, 所有写到这个文件中的数据都会被丢弃掉.) (2)init进程的程序(也就是busybox,因为init程序位于busybox中) (3)/etc/inittab(用于init进程读取配置, 然后执行inittab里的指定应用程序) (4)应用程序(被inittab配置文件调用的应用程序) (5)C库(gli

SAP Web Service简介与配置方法

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 17.0000pt; margin-bottom: 16.5000pt; margin-left: 0.0000pt; text-indent: 21.0000pt; page-break-after: avoid; text-al

CentOS6.5 Nginx优化编译配置

说到Nginx,它真的算是我在运维工作中的好朋友,它优异的性能和极高的工作效率实在是让人大爱,来自internet的报告称其epoll模型能够支持高达50000个并发连接数. Epoll[维基百科]: epoll是Linux下 多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符 集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历

Linux Apache PHP编译配置

1.下载Apache Web服务器源码及相关依赖库 进入http://www.apache.org,选择一个服务器下载相关的源码.这里请注意:apache其实是一个基金会名称,旗下有很多开源项目,apache web服务器只是apache基金会其中一个项目而已,所以很多朋友在进入apache主页后,很难找到apache web server下载的地方,apache web server在其源码库中名称为httpd-xxx(xxx为版本).基本步骤是:首页点击download,进入下载页后,选择一

ADFS 2.0 配置简介 PartⅡ – 配置 ADFS 信任关系

ADFS 与应用程序间的各种验证是基于信任关系的,在 ADFS 服务器配置好要信赖的应用程序(以 URL 为标识)后,应用程序再通过指定认证服务器来将用户引导至 ADFS 登录页,登录完成后再将用户的信息使用 Cookie 加密发送到应用程序完成验证. 我们来配置一个应用程序试试,为了方便就使用 ASP.NET MVC 吧. 一 .配置应用程序 建立 ASP.NET MVC 应用程序,一路默认. 安装一个 Visual Studio 扩展插件,能帮助我们省很多功夫,如果你不想太深入ADFS配置文