本文共 4376 字,大约阅读时间需要 14 分钟。
Libevent 是一个用 C 语言编写的、轻量级、高性能的开源网络库,广泛应用于网络服务器、客户端和其他网络相关的开发。它基于事件驱动模型,支持多种 I/O 多路复用技术,包括 epoll、poll、select 和 kqueue 等,适用于高并发网络场景。相比ACE,Libevent 的代码更简洁、易读,支持跨平台,适用于 Windows、Linux、*BSD 和 Mac OS 等操作系统。
本文将详细介绍如何在 Windows 环境下编译和使用 Libevent,提供完整的hands-on 实验过程。
将下载的 tar.gz 文件解压,得到 libevent-2.0.22-stable
文件夹。
在 libevent-2.0.22-stable
文件夹中,找到以下文件并在开头添加宏定义 #define _WIN32_WINNT 0x0500
:
event_iocp.c
evthread_win32.c
listener.c
使用 Visual Studio 的命令行工具(nmake
),从项目根目录执行以下命令:
nmake /f Makefile.nmake
这将生成三个静态库:
libevent_core.lib
libevent_extras.lib
libevent.lib
libevent
文件夹。libevent
中创建 lib
和 include
文件夹,将编译生成的三个库和相关头文件复制到 lib
文件夹中。libevent-2.0.22-stable\include
文件夹下的所有内容复制到 include
文件夹。lib
和 include
文件夹添加到库和包含目录中。/MT
(Release)或 /MTd
(Debug)。ws2_32.lib
、wsock32.lib
、以及生成的三个 Libevent 库。#include#include #include #include #define MSG "Hello, World!\n"#define PORT 9995static void write handler(struct bufferevent * bev, void * user_data) { struct evbuffer * output = bufferevent_get_output(bev); if (evbuffer_get_length(output) == 0) { printf("flushed\n"); bufferevent_free(bev); }}static void connection handler(struct bufferevent * bev, short events, void * user_data) { if (events & BEV_EVENT_EOF) { printf("Connection closed\n"); } else if (events & BEV_EVENT_ERROR) { printf("Error on connection: %s\n", strerror(errno)); } bufferevent_free(bev);}static void signal handler(int sig) { static struct event_base * base = (struct event_base *) user_data; struct timeval delay = {2, 0}; printf("Caught signal\n"); event_base_loopexit(base, &delay);}static void listener handler(struct evconnlistener * listener, int fd, struct sockaddr * sa, void * user_data) { struct event_base * base = (struct event_base *) user_data; struct bufferevent * bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); if (!bev) { fprintf(stderr, "Error creating bufferevent\n"); return; } bufferevent_setcb(bev, write handler, connection handler, NULL); bufferevent_enable(bev, EV_WRITE); bufferevent_write(bev, MSG, strlen(MSG));}int main(int argc, char ** argv) { struct event_base * base = event_base_new(); if (!base) { return 1; } struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(PORT); struct evconnlistener * listener = evconnlistener_new_bind(base, listener handler, base, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr *)&sin, sizeof(sin)); if (!listener) { return 1; } signal(SIGINT, signal handler); event_base_dispatch(base); evconnlistener_free(listener); event_base_free(base); printf("Done\n"); return 0;}
#include#include #include static bool startHttpServer(const char * ip, int port, void (* cb)(struct evhttp_request *, void *), void * arg) { struct event_base * base = event_base_new(); struct evhttp * http = evhttp_new(base); if (!http) { return false; } int ret = evhttp_bind_socket(http, ip, port); if (ret != 0) { return false; } evhttp_set_gencb(http, cb, arg); event_base_dispatch(base); evhttp_free(http); return true;}void MyHttpServerHandler(struct evhttp_request * req, void * arg) { struct evbuffer * buf = evbuffer_new(); evbuffer_add_printf(buf, "Hello, world"); evhttp_send_reply(req, HTTP_OK, "Response", buf); evbuffer_free(buf);}int main() { WSADATA wsaData; WSAStartup(SOCKET_VERSION_ANY, &wsaData); startHttpServer("127.0.0.1", 8080, MyHttpServerHandler, NULL); WSACleanup(); return 0;}
在使用 Libevent 时,可能会遇到以下错误:
C: "void *" 到 "event_base *" 的初始化:无法从 "void *" 转换为 "event_base *"
这通常是由于 event_base *
的初始化没有正确传递用户数据。可以通过在定义 event_base *
时强制转换来解决。
确保已加载 Ws2_32.lib
和 wsock32.lib
,这对于 Windows 执行网络通信是必不可少的。
通过以上步骤,可以在 Windows 环境下成功编译并使用 Libevent 进行网络通信开发。Libevent 提供了便捷的事件驱动 API,使得开发高性能网络服务器变得更加简单。通过上述示例,可以快速开始项目开发,并根据具体需求进行扩展和优化。
转载地址:http://tggyk.baihongyu.com/