Libevent的使用介绍
libevent是一个事件驱动的网络编程库,用于高效地管理网络连接并处理I/O事件。下面是libevent库的一些常用函数接口介绍和例子:
常用函数接口介绍
event_init()
在程序初始化时,需要调用event_init()函数来初始化libevent库。
返回一个event_base指针,如果初始化失败则返回NULL
struct event_base *base = event_init();
if (!base) {
fprintf(stderr, "Could not initialize libevent!\n");
return -1;
}
event_new()
创建新事件并返回一个事件对象,用于监听文件描述符的I/O事件.该函数可能返回NULL指针,表示创建事件失败。
struct event *event_new(struct event_base *base, evutil_socket_t fd,
short events, event_callback_fn cb, void *arg);
base: 事件基础,重点是为了处理I/O多路复用等事件。
fd: 事件所关联的文件描述符,fd在被管理的时候会被设置成非阻塞模式。
events: 监听的事件类型,例如可读、可写等。
cb: 事件触发时的回调函数。
arg: 用于与回调函数进行通信的参数。回调函数的实参。可以在回调函数中强转成想要的类型
event_add()
将一个新的事件添加到事件管理器中,事件管理器在管理的文件描述符上等待事件发生。
int event_add(struct event *ev, const struct timeval *tv);
ev: 指向要添加的事件的指针。
tv: 如果非NULL,则指定事件最多允许阻塞的时间;如果该事件处于活动状态,则会重新计时。
event_base_dispatch()
启动事件处理循环,直到事件队列为空或事件管理器被释放。此函数是事件通知的基础,通常用于服务器和长期运行的客户端应用程序。
int event_base_dispatch(struct event_base *base);
自己实现的基于libevent框架的服务器端的例子
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include<sys/signal.h>
#include<event.h>
void on_accept(evutil_socket_t listener, short event, void *arg)
{
struct event_base *base = arg;
struct sockaddr_storage ss;
socklen_t slen = sizeof(ss);
int fd = accept(listener, (struct sockaddr*)&ss, &slen);
if (fd < 0) {
fprintf(stderr, "Failed to accept client connection: %s\n",
strerror(errno));
return;
}
char ip[INET6_ADDRSTRLEN];
void *addr;
if (ss.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&ss;
addr = &(s->sin_addr);
} else {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&ss;
addr = &(s->sin6_addr);
}
inet_ntop(ss.ss_family, addr, ip, sizeof(ip));
printf("Accepted connection from %s\n", ip);
// 将新连接加入事件循环,等待读取数据
struct event *ev = event_new(base, fd, EV_READ | EV_PERSIST, on_read, base);
event_add(ev, NULL);
}
void on_read(evutil_socket_t fd, short event, void *arg)
{
struct event_base *base = arg;
char buf[1024];
size_t n = recv(fd, buf, sizeof(buf), 0);
if (n == 0) {
printf("Connection closed.\n");
} else if (n < 0) {
fprintf(stderr, "Error on read: %s\n", strerror(errno));
} else {
printf("Received %zu bytes: %.*s\n", n, (int)n, buf);
// 回写给客户端
send(fd, buf, n, 0);
}
// 从事件循环中删除这个事件
event_del(event_get_struct_eventarg((struct event*)arg));
event_free((struct event*)arg);
close(fd);
}
int main()
{
//创建用于监听的文件描述符sockfd,并进行bind,listen
//这里我是伪代码
int sockfd=Sock_Init();
//创建libevent实例
struct event_base*base=event_init();
//为用于监听的文件描述创建事件对象,如果该文件描述符对应事件发生则会执行回调函数
//需要把base传入,发生事件(有客户端连接)在回调函数中需要接受该描述符并添加到base(libevent实例中)
struct event*p=event_new(base,sockfd,EV_READ||EV_PERSIST,on_accept,base);
event_add(p,0);
//启动事件循环
event_base_dispatch(base);
}