文档章节

libevent在windows下使用步骤详解

mickelfeng
 mickelfeng
发布于 2017/08/17 11:06
字数 1807
阅读 237
收藏 0

Libevent 是一个用C语言编写的、轻量级的开源高性能网络库,主要有以下几个亮点:

(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、 Vomit、 Nylon、 Netchat等等。

 

组成和功能

libevent包含如下部分:

  • evutil

它抽象了一组辅助功能,并屏蔽了操作系统平台的不同。

  • event 及 event_base

这是libevent的核心,提供了一组不依赖于操作系统平台的基于事件的非阻塞IO操作。

  • bufferevent

这个功能基于libevent的事件驱动,提供了非常方便的IO读写,它也可以有多个后端支持,以充分利用操作系统的功能,例如Windows的IOCP API。

  • evbuffer

这个模块是bufferevent的基础,提供了高效的读写方法。

  • evhttp

一个简单的HTTP client/server实现。

  • evdns

一个简单的DNS client/server实现。

  • evrpc

一个简单的RPC实现。

libevent是一个常用的网络库,下面就看看在windows下面编译测试的过程吧。
 

一 环境

系统:win8.1
编译器:VS2008
官方下载地址:http://libevent.org/
版本:2.0.22-stable
 

二 编译静态库

1 解压
把上面下载到libevent-2.0.22-stable.tar.gz解压,得到libevent-2.0.22-stable文件夹


2 添加宏定义
在libevent-2.0.22-stable文件夹下找到下面三个文件:
event_iocp.c
evthread_win32.c
listener.c
打开并在开头加上宏定义:
#define _WIN32_WINNT 0x0500

因为event_iocp.c里用到<winbase.h>头文件里的函数定义,如InitializeCriticalSectionAndSpinCount,
<windows.h>会包含<winbase.h>,而<winbase.h>这个头文件里这个函数是这样定义的:
#if (_WIN32_WINNT >= 0x0403)
 WINBASEAPI
 BOOL WINAPI
 InitializeCriticalSectionAndSpinCount(
     __out LPCRITICAL_SECTION lpCriticalSection,
     __in  DWORD dwSpinCount
     );

 WINBASEAPI
 DWORD
 WINAPI
 SetCriticalSectionSpinCount(
     __inout LPCRITICAL_SECTION lpCriticalSection,
     __in    DWORD dwSpinCount
     );
 #endif

所以要定义_WIN32_WINNT这个宏,而且值要大于0x0403。
如果没有这个宏或不满足条件,编译器会假定这个函数没有定义,
等到链接时再寻找它,这样这个函数的符号就假定返回一个int,
而显示标准库文件里这个函数不是返回int,所以在链接时就会找不到这个函数符号。

注意:宏一定要定义在#include <windows.h>之前,不然还是没有作用。

3 编译
使用vs的命令行工具,cd到libevent-2.0.22-stable目录,执行脚本makefile.nmake,命令如下:
nmake /f Makefile.nmake
这样就会生成三个静态库:
libevent_core.lib
libevent_extras.lib
libevent.lib
 

三 使用示例

1 新建项目

新建一个控制台“空”项目

2 拷贝文件

2.1 在项目目录下建一个libevent文件夹
2.2 在libevent中新建一个lib文件夹,将上面三个lib文件copy到该目录下。
2.3 在libevent中再新建一个include文件夹,
将libevent-2.0.22-stable\include下的文件和文件夹copy到该目录下,
将libevent-2.0.22-stable\WIN32-Code下的文件和文件夹copy到该目录下,
2个event2目录下的文件合并一起。
 

3 项目配置

VC++目录:
包含目录,添加刚刚新建的include目录
库目录,添加刚刚的lib目录;


C/C++:
代码生成-->运行库:
Debug模式下选:多线程调试 (/MTd),
Release下模式下选:多线程 (/MT)


连接器:
输入->附加依赖项:
ws2_32.lib
wsock32.lib
libevent.lib
libevent_core.lib
libevent_extras.lib
另外两个库ws2_32.lib和wsock32.lib是用来编译Windows网络相关的程序库。
 

4 测试代码

4.1 新建一个main.c文件
4.2 从libevent-2.0.22-stable\sample目录下拷贝time-test.c文件中的代码到main中,代码如下:

#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>

#pragma comment (lib,”Advapi32.lib”)

#ifndef WIN32
#include <netinet/in.h>
# ifdef _XOPEN_SOURCE_EXTENDED
#  include <arpa/inet.h>
# endif
#include <sys/socket.h>
#endif

#include "event2/bufferevent.h"
#include "event2/buffer.h"
#include "event2/listener.h"
#include "event2/util.h"
#include "event2/event.h"

#include <WinSock2.h>

static const char MESSAGE[] = "Hello, World!\n";

static const int PORT = 9995;


static void conn_writecb(struct bufferevent *bev, void *user_data)
{
    struct evbuffer *output = bufferevent_get_output(bev);
    if (evbuffer_get_length(output) == 0) 
    {
        printf("flushed answer\n");
        bufferevent_free(bev);
    }
}

static void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
    if (events & BEV_EVENT_EOF) 
    {
        printf("Connection closed.\n");
    } 
    else if (events & BEV_EVENT_ERROR) 
    {
        printf("Got an error on the connection: %s\n",
            strerror(errno));/*XXX win32*/
    }
    /* None of the other events can happen here, since we haven't enabled
     * timeouts */
    bufferevent_free(bev);
}

static void signal_cb(evutil_socket_t sig, short events, void *user_data)
{
    struct event_base *base = (struct event_base *)user_data;
    struct timeval delay = { 2, 0 };

    printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");

    event_base_loopexit(base, &delay);
}

static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
    struct sockaddr *sa, int socklen, void *user_data)
{
    struct event_base *base = (struct event_base *)user_data;
    struct bufferevent *bev;

    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    if (!bev) 
    {
        fprintf(stderr, "Error constructing bufferevent!");
        event_base_loopbreak(base);
        return;
    }
    bufferevent_setcb(bev, NULL, conn_writecb, conn_eventcb, NULL);
    bufferevent_enable(bev, EV_WRITE);
    bufferevent_disable(bev, EV_READ);

    bufferevent_write(bev, MESSAGE, strlen(MESSAGE));
}

int main(int argc, char **argv)
{
    struct event_base *base;
    struct evconnlistener *listener;
    struct event *signal_event;

    struct sockaddr_in sin;

#ifdef WIN32
    WSADATA wsa_data;
    WSAStartup(0x0201, &wsa_data);
#endif

    base = event_base_new();
    if (!base) 
    {
        fprintf(stderr, "Could not initialize libevent!\n");
        return 1;
    }

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);

    listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
        LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1,
        (struct sockaddr*)&sin,
        sizeof(sin));

    if (!listener) 
    {
        fprintf(stderr, "Could not create a listener!\n");
        return 1;
    }

    signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);

    if (!signal_event || event_add(signal_event, NULL)<0) 
    {
        fprintf(stderr, "Could not create/add a signal event!\n");
        return 1;
    }

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_free(signal_event);
    event_base_free(base);

    printf("done\n");
    return 0;
}

windows下socket通信需要加载Ws2_32.lib,这个大家都知道,至于为何需要Advapi32.lib,可以参考:LNK2019:无法解析的外部符号_imp_CryptAcquireContextA@20
然后将libevent自带的例子C:\Users\zhang\Desktop\libevent-2.0.22-stable\sample|h\ello-world.c拷贝到工程中并编译。

需要注意的是编译时有两处  C2440:“初始化”:无法从“void *”转换为“event_base *”  的错误,强制转换一下即可。

http server:

#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/http.h>

bool startHttpServer(const char* ip, int port, void (*cb)(struct evhttp_request *, void *), void *arg)
{
    //创建event_base和evhttp
    event_base* base = event_base_new();
    evhttp* http_server = evhttp_new(base);
    if (!http_server) {
        return false;
    }
    //绑定到指定地址上
    int ret = evhttp_bind_socket(http_server, ip, port & 0xFFFF);
    if (ret != 0) {
        return false;
    }
    //设置事件处理函数
    evhttp_set_gencb(http_server, cb, arg);
    //启动事件循环,当有http请求的时候会调用指定的回调
    event_base_dispatch(base);
    evhttp_free(http_server);
    return true;
}
void MyHttpServerHandler(struct evhttp_request* req, void* arg)
{
    //创建要使用的buffer对象
    evbuffer* buf = evbuffer_new();
    if (!buf) {
        return;
    }
    //获取请求的URI
    const char* uri = (char*)evhttp_request_get_uri(req);
    //添加对应的HTTP代码
    evbuffer_add_printf(buf,"Hello,world");

	/*
    evbuffer_add_printf(buf,"<head><title>MyHttpServer</title></head>");
    evbuffer_add_printf(buf, "<body>");
    //根据URI显示不同的页面
    if (strcmp(uri, "/") == 0) {
        evbuffer_add_printf(buf,"<p>Welcome to my http server</p>");
    } else if (strcmp(uri, "/about") == 0) {
        evbuffer_add_printf(buf,"<p>I love C++</p>");
    }
    evbuffer_add_printf(buf, "</body>");
    evbuffer_add_printf(buf,"</html>");
	*/
    //回复给客户端
    evhttp_send_reply(req, HTTP_OK, "OK", buf);
    evbuffer_free(buf);
}
int main(int argc, char** argv)
{
    //Windows 平台套接字库的初始化
#ifdef WIN32
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
    //启动服务在地址 127.0.0.1:9000 上
    startHttpServer("127.0.0.1", 9000, MyHttpServerHandler, NULL);
#ifdef WIN32
    WSACleanup();
#endif
    return 0;
}

四 在线文档:

http://www.wangafu.net/~nickm/libevent-2.0/doxygen/html/

五 源码分析:

《Libevent源码分析》对Libevent这个网络库的一些源代码分析

http://blog.csdn.net/sparkliang/article/category/660506

http://blog.csdn.net/luotuo44/article/category/2435521

libevent介绍及示例 

处理大并发之五

windows下编译及使用libevent

libevent学习之二:Windows7(Win7)下编译libevent

事件注册与循环监听

快速理解libevent内在机制

【libevent】

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

libevent event_set函数与event_add函数解析 [SYM]

 

© 著作权归作者所有

mickelfeng

mickelfeng

粉丝 238
博文 2811
码字总数 607706
作品 0
成都
高级程序员
私信 提问
Nginx详解安装配置以及应用实例

Nginx详解安装配置以及应用实例 一、Nginx简介 Nginx(发音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗...

天涯悠客
2014/06/13
0
0
高性能网络编程(二):上一个10年,著名的C10K并发连接问题

1、前言 对于高性能即时通讯技术(或者说互联网编程)比较关注的开发者,对C10K问题(即单机1万个并发连接问题)应该都有所了解。“C10K”概念最早由Dan Kegel发布于其个人站点,即出自其经典...

JackJiang-
2016/10/21
1K
3
Windows 上静态编译 Libevent 2.0.10 并实现一个简单 HTTP 服务器

本文介绍了如何在 Windows 操作系统中,利用微软 Visual Studio 2005 编译生成Libevent 2.0.10 静态链接库,并利用 Libevent 静态链接库,实现一个简单的 HTTP Web服务器程序:httpd.exe 假设...

雅各宾
2013/07/23
1K
0
tomcat使用memcached完成集群

一.安装memcached 1.windows下安装memcached 需要到一个网站下载memcached的for win 32版本.在memcached的官方网站我是找不到的.我看了下,提供win版下载的是一个个人网站,老外的.应该是他自己...

quguoliang2013
2016/03/14
0
0
linux memcached 安装

1.下载包 1.1.到http://memcached.org/下载linux下的memcached的安装包. 1.2.到http://libevent.org/ 下载安装memcached前比需要的包libevent-2.0.22我安装的是这个版本. 2.安装libevent-2....

---張榮---
2016/01/13
69
0

没有更多内容

加载失败,请刷新页面

加载更多

测试定时

23/58

FalconChen
昨天
43
0
新海软件邮政市场监管综合信息平台

二、系统功能 该平台包括邮政普遍服务管理、快递管理两大系统,涵盖了地图定位、普服信息、快递信息、GIS管理、网格管理、视频监控、数据分析(BI)、系统设置等八大模块,全面反映了区域邮政...

neocean
昨天
165
0
【微记忆】用户隐私政策与条款

微记忆尊重并保护所有注册用户的个人隐私权。为了给您提供更准确、更贴心的服务,微记忆会按照本隐私权政策的规定储存并使用您的个人信息。微记忆承诺将以高度严格的审慎义务对待这些信息。除...

微记忆
昨天
69
0
两周自制脚本语言-第7天 添加函数功能

第7天 添加函数功能 基本的函数定义与调用执行、引入闭包使Stone语言可以将变量赋值为函数,或将函数作为参数传递给其他函数 有些函数将有返回值的归为函数,没有返回值的归为子程序 7.1 扩充...

果汁分你一半
昨天
105
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部