网络库-libevent介绍

17 阅读4分钟

1.简介

libevent是一个事件驱动的网络库,主要用于构建可扩展的网络服务器。它提供了跨平台的API,支持多种事件通知机制,如select、poll、epoll、kqueue等。

主要组件

  • event: 表示一个具体的事件,包括事件类型、事件回调等。
  • event_base: 用于管理所有的事件,负责事件的添加、删除和分发。
  • buffer: 提供缓冲区操作,用于网络数据的读写。
  • evbuffer: 提供增强的缓冲区操作,支持链式缓冲区。
  • bufferevent: 基于buffer和evbuffer的更高层次的抽象,用于简化网络数据的读写。

2.工作原理

libevent的工作原理基于事件驱动模型。

事件循环(Event Loop) libevent的核心是一个事件循环,它不断地检查是否有事件发生,并在事件发生时调用相应的回调函数。这个循环是由event_base_dispatch()函数启动的,它会一直运行直到被明确地要求退出。

事件(Events) 在libevent中,事件可以是多种类型,包括:

  • I/O事件:文件描述符变得可读、可写或发生异常。
  • 定时器事件:在指定的时间间隔后触发。
  • 信号事件:当特定的信号发生时触发。
  • 持续事件:定期触发,用于执行周期性的任务。

事件驱动模型(Event-Driven Model) libevent使用事件驱动模型来管理事件。它将事件与回调函数关联起来,当事件发生时,libevent会调用相应的回调函数来处理事件。

事件处理器(Event Handler)

事件处理器是libevent中用于管理事件的内部结构。它包含了事件的信息,如文件描述符、事件类型、回调函数和用户数据。libevent提供了event和bufferevent两种主要的事件处理器:

  • event:用于处理基本的I/O事件、定时器和信号。
  • bufferevent:提供了更高层次的抽象,用于处理带缓冲的I/O操作,简化了读写操作。

3.常用接口介绍

event_base 相关接口:

  • struct event_base *event_base_new(void); 创建一个新的event_base结构,这是使用libevent的第一步。

  • int event_base_dispatch(struct event_base *base); 开始event_base的事件循环,这个函数会一直运行,直到没有活动的事件或者调用了event_base_loopbreak()或event_base_loopexit()。

  • void event_base_free(struct event_base *base); 释放event_base结构及其所有关联的资源。

  • int event_base_set(struct event_base *base, struct event *ev); 设置event使用的event_base。

event 相关接口:

  • struct event *event_new(struct event_base *base, evutil_socket_t fd, short events,event_callback_fn callback, void *callback_arg); 创建一个新的event,指定事件base、文件描述符、事件类型、回调函数和用户数据。

  • int event_add(struct event*ev, const struct timeval *tv);
    将event添加到其event_base中,可以指定一个timeval结构来设置事件的超时时间。

  • int event_del(structevent *ev); 从event_base中删除一个event。

  • void event_free(struct event *ev); 释放event结构及其所有关联的资源。

bufferevent 相关接口:

  • struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options); 创建一个新的bufferevent,它封装了socket操作,可以用于读写网络数据。

  • int bufferevent_setcb(struct bufferevent *bev, bufferevent_data_cb
    readcb, bufferevent_data_cb writecb, bufferevent_event_cb eventcb,
    void *cbarg);
    设置bufferevent的回调函数,包括读回调、写回调和事件回调。

  • int bufferevent_enable(struct bufferevent *bev, short event);
    启用bufferevent的特定事件,如读事件、写事件。

  • int bufferevent_disable(struct bufferevent *bev, short event);
    禁用bufferevent的特定事件。

  • int bufferevent_free(struct bufferevent *bev);
    释放bufferevent及其所有关联的资源。

HTTP服务器相关接口:

  • struct evhttp *evhttp_new(struct event_base *base); 创建一个新的HTTP服务器。

  • void evhttp_set_gencb(struct evhttp *http, void (*cb)(struct evhttp_request *, void *), void *arg); 设置HTTP服务器的通用请求回调函数。

  • struct evhttp_bound_socket *evhttp_bind_socket_with_handle(struct evhttp *http, const char *address, ev_uint16_t port); 将HTTP服务器绑定到指定的地址和端口。

  • void evhttp_free(struct evhttp *http); 释放HTTP服务器及其所有关联的资源。

4.环境搭建

下载地址:github.com/libevent/li… 在这里插入图片描述 下载完成,进行解压,然后使用cmake编译。 在这里插入图片描述 生成库如下图所示: 在这里插入图片描述 拷贝如下文件和lib文件到我们的demo工程中。 源码目录的下的include目录和编译后的include目录,以及lib、dll库。 在这里插入图片描述 配置visual studio环境,请看Jsoncpp介绍。如何配置include、lib目录。

5.示例

下面是一个简单的libevent服务器示例,监听TCP连接,接收客户端数据并回显。

#include <stdio.h>
#include <string.h>
#include <event.h>
#include <evhttp.h>

void request_handler(struct evhttp_request *req, void *arg) 
{
	struct evbuffer *buf;
	const char *uri = evhttp_request_get_uri(req);
	printf("Received a request: %s\n", uri);

	buf = evbuffer_new();
	evbuffer_add_printf(buf, "Hello, World! Your request uri is: %s", uri);
	evhttp_send_reply(req, HTTP_OK, "OK", buf);
	evbuffer_free(buf);
}


int main()
{
	struct event_base *base;
	struct evhttp *http;
	struct evhttp_bound_socket *handle;

	base = event_base_new();
	if (!base) {
		fprintf(stderr, "Failed to create event base\n");
		return 1;
	}

	http = evhttp_new(base);
	if (!http) {
		fprintf(stderr, "Failed to create evhttp\n");
		return 1;
	}

	evhttp_set_gencb(http, request_handler, NULL);

	handle = evhttp_bind_socket_with_handle(http, "127.0.0.1", 8080);
	if (!handle) {
		fprintf(stderr, "Failed to bind socket\n");
		return 1;
	}
	
	printf("Listening on 8080\n");
	event_base_dispatch(base);

	evhttp_free(http);
	event_base_free(base);

	return 0;
}