下载 Libevent
官网地址:http://libevent.org/
编译 Libevent 库
1 解压libevent-2.1.11-stable.tar.gz
2 打开开始菜单,找到Vistual Studio 本机工具命令提示符(64位使用x64,32位使用x86)
3 cd进入解压后的ibevent-2.1.11-stable目录下
4 执行命令: nmake /f Makefile.nmake
如果报错:f:\lib\libevent-2.1.11-stable\minheap-internal.h(73): error C2065: “UINT32_MAX”: 未声明的标识符
在该文件(minheap-internal.h)中添加 #include “stdint.h”,再次编译,会有警告,没关系。
Visual Studio配置Libevent
上面Libevent 编译完成后,会在libevent-2.1.11-stable目录下生成三个 .lib 的文件,分别是 libevent.lib libevent_core.lib libevent_extras.lib。把他们拷贝出来待用。
使用 Visual Studio 建立一个 Win32 控制台空项目,建立完成后首先在项目目录下新建一个DEPS文件夹,DEPS下建include和lib文件夹,用来存放 .h 头文件和 .lib 库文件(熟悉的人目录结构你可以自己规划,我这样写只为新手入门准备,可以参考学习,后面熟悉了随便自己怎么改)。
随后,拷贝libevent-2.1.11-stable\include
和libevent-2.1.11-stable\WIN32-Code\nmake
所有文件,到 include 目录,此时会出现重名目录的情况,直接覆盖就可以了,实际里面的文件不会重复。
备注:是复制libevent-2.1.11-stable\WIN32-Code\nmake中的文件和目录而不是在libevent-2.1.11-stable\WIN32-Code中,这点非常重要,很多文章都是说的复制后者。
然后拷贝编译好的三个lib 文件到 lib 目录下。
需要的文件我们都放到项目目录下了,接下来就是在项目中引入这两个目录。在项目上 右键-属性。
点击 VC++目录,分别在包含目录中引入项目目录下的 include 文件夹、在库目录中引入 lib 文件夹。
备注:最好是在附加包含目录、附加库目录中加入目录,包含目录与附加包含目录、库目录与附件库目录的区别见VS2015 包含目录、库目录、附加包含目录、附加库目录、附加依赖项之详解
在 C/C++代码生成 中,将 运行库 在 Debug 模式下修改为 多线程调试 (/MTd),在 Release 模式下修改为 多线程调试 (/MT)。
在链接器-输入-附加依赖库中分别添加三个lib文件(libevent.lib、libevent_core.lib、libevent_extras.lib)和 socket 所需的库文件(ws2_32.lib、wsock32.lib)。
相应的打开路径如下:
- 附加包含目录:配置属性-》C/C++ -》常规 -》附加包含目录
- 附加库目录:配置属性-》链接器 -》常规 -》附加库目录
- 附加依赖项:配置属性-》链接器 -》输入 -》附加依赖项
以上环境我们就搭建好了,接下来就是下一段代码来测试一下了。在项目中新建一个 mian.c 文件,输入一下代码编译并运行。
使用 Libevent
采用 bufferevent 实现多线程架构,使用 libevent 网络库实现了一个游戏服务器引擎,在此记录下其中遇到的一个问题。
我在设计服务器上选择把逻辑和网络分线程,线程之间通信使用队列。但是这样做会有个问题,当逻辑线程想要主动的发一个数据包的时候,网络线程此时可能还阻塞在等待网络 IO 的系统调用上(比如说 epol l)。如果不做特殊处理的话,此时消息包就会一直积压在缓冲区中,直到下一次网络线程从挂起的系统调用返回(比如来了一个消息包)。因此,当逻辑线程发送消息包的时候(bufferevent_write)需要一种唤醒机制,让网络线程从 epoll 等系统调用中返回并处理发送消息包逻辑。
libevent 相关的 api 很简单并且只有一个:evthread_use_windows_threads() 。
函数 evthread_use_windows_threads() 的调用必须在初始化 event_base 之前。在此之后,无需再做别的事情,逻辑线程在执行 bufferevent_write 的时候,libevent 就会自动唤醒网络线程的事件循环,并执行发送数据。
#ifdef WIN32
evthread_use_windows_threads();
#endif
#ifdef _EVENT_HAVE_PTHREADS
evthread_use_pthreads();
#endif
struct event_base* base = event_base_new();