转自: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 被创建前调用。

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

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

    原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...

  2. 转载:Centos7 从零编译配置Memcached

    序言 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度. Memca ...

  3. [原创]Centos7 从零编译配置Memcached

    序言 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度. Memca ...

  4. Nginx 反向代理工作原理简介与配置详解

    Nginx反向代理工作原理简介与配置详解   by:授客  QQ:1033553122   测试环境 CentOS 6.5-x86_64 nginx-1.10.0 下载地址:http://nginx. ...

  5. 【内核】linux2.6版本内核编译配置选项(一)

    Linux 2.6.19.x 内核编译配置选项简介 作者:金步国 版权声明 本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布.任何人都可以自由使用.转载.复制和再分发, ...

  6. Linux防火墙简介 – iptables配置策略

    Linux防火墙简介 – iptables配置策略 Netfilter/iptables简介 要想真正掌握Linux防火墙体系,首先要搞清楚Netfilter和iptables的关系,Netfilte ...

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

    上篇文章<深入浅出Mybatis系列(五)---TypeHandler简介及配置(mybatis源码篇)>简单看了一下TypeHandler, 本次将结束对于mybatis的配置文件的学习 ...

  8. MyBatis学习(一)、MyBatis简介与配置MyBatis+Spring+MySql

    一.MyBatis简介与配置MyBatis+Spring+MySql 1.1MyBatis简介 MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的J ...

  9. Fast RCNN 训练自己数据集 (1编译配置)

    FastRCNN 训练自己数据集 (1编译配置) 转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ https:/ ...

  10. MyBatis学习 之 一、MyBatis简介与配置MyBatis+Spring+MySql

    目录(?)[-] 一MyBatis简介与配置MyBatisSpringMySql MyBatis简介 MyBatisSpringMySql简单配置 搭建Spring环境 建立MySql数据库 搭建My ...

随机推荐

  1. POJ2752 - Seek the Name, Seek the Fame(KMP)

    题目大意 给定一个字符串S,求出所有既是S的前缀又是S的后缀的子串长度 题解 从末尾位置倒推,经过的失配函数值就是题目要求求的 代码: #include <iostream> #inclu ...

  2. vim 设置 swap file, 防止 同一个文件同时被多次打开,而且有恢复的功效

    在.vimrc里加入:   set swapfile   即可以使能swap file, swapfile的名字一般是      .filename.swp    (如     .doc.txt.sw ...

  3. mysql 中文乱码的解决办法

    I would not suggest Richies answer, because you are screwing up the data inside the database. You wo ...

  4. Storm与Hadoop的角色和组件比较

    Storm与Hadoop的角色和组件比较 Storm 集群和 Hadoop 集群表面上看很类似.但是 Hadoop 上运行的是 MapReduce 作业,而在 Storm 上运行的是拓扑 Topolo ...

  5. JavaScript- The Good Parts Chapter 6

    Thee(你) I’ll chase(追逐:追捕) hence(因此:今后), thou(你:尔,汝) wolf in sheep’s array.—William Shakespeare, The ...

  6. SpringMVC学习系列 之 表单标签

    http://www.cnblogs.com/liukemng/p/3754211.html 本篇我们来学习Spring MVC表单标签的使用,借助于Spring MVC提供的表单标签可以让我们在视图 ...

  7. 【02】尽量以const,enum,inline替换#define

    1.考虑为什么? 首先,#define不是语言的一部分,而是预编译过程.也就是在编译器编译之前,进行文本替换.考虑#define Pi 3.1425:在编译之前,Pi都会被文本替换为3.1415,因此 ...

  8. Java凝视Override、Deprecated、SuppressWarnings具体解释

    一.什么是凝视     说起凝视,得先提一提什么是元数据(metadata).所谓元数据就是数据的数据.也就是说,元数据是描写叙述数据的.就象数据表中的字段一样,每一个字段描写叙述了这个字段下的数据的 ...

  9. 标准I/O库之临时文件

    ISO C标准I/O库提供了两个函数以帮助创建临时文件. #include <stdio.h> char *tmpnam( char *ptr ); 返回值:指向唯一路径名的指针 FILE ...

  10. 使用HttpURLConnection实现在android客户端和服务器之间传递对象

    一般情况下,客户端和服务端的数据交互都是使用json和XML,相比于XML,json更加轻量级,并且省流量,但是,无论我们用json还是用xml,都需要我们先将数据封装成json字符串或者是一个xml ...