面试题答案
一键面试libevent库中事件驱动模型基本原理
- 事件注册:应用程序向libevent库注册感兴趣的事件,如文件描述符(socket等)上的读、写事件,定时器事件等。这些事件与对应的回调函数相关联。
- 事件分发器:libevent库内部维护一个事件分发器(通常基于操作系统的I/O多路复用机制,如select、poll、epoll等,根据不同操作系统自动选择最优的)。事件分发器负责监控所有注册的事件源,当事件发生时,将事件通知给应用程序。
- 事件循环:应用程序进入一个事件循环,不断检查事件分发器是否有事件发生。当有事件发生时,事件循环调用相应的回调函数来处理该事件。处理完成后,继续等待下一个事件。
使用libevent库创建简单事件监听机制处理网络连接事件示例
以下是基于C语言的简单示例代码:
#include <event2/event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define PORT 8080
#define BACKLOG 10
// 处理连接事件的回调函数
void accept_conn_cb(evutil_socket_t listen_fd, short event, void *arg) {
struct event_base *base = (struct event_base *)arg;
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
evutil_socket_t client_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_addr_len);
if (client_fd < 0) {
perror("accept");
return;
}
printf("Accepted connection from client: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 这里可以继续处理与客户端的通信等操作,例如创建读事件处理接收到的数据
}
int main() {
struct event_base *base;
struct event *listen_event;
evutil_socket_t listen_fd;
// 创建event_base
base = event_base_new();
if (!base) {
perror("event_base_new");
return 1;
}
// 创建监听socket
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror("socket");
event_base_free(base);
return 1;
}
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind");
close(listen_fd);
event_base_free(base);
return 1;
}
if (listen(listen_fd, BACKLOG) < 0) {
perror("listen");
close(listen_fd);
event_base_free(base);
return 1;
}
// 创建监听事件
listen_event = event_new(base, listen_fd, EV_READ | EV_PERSIST, accept_conn_cb, (void *)base);
if (!listen_event) {
perror("event_new");
close(listen_fd);
event_base_free(base);
return 1;
}
// 添加事件到event_base
if (event_add(listen_event, NULL) < 0) {
perror("event_add");
event_free(listen_event);
close(listen_fd);
event_base_free(base);
return 1;
}
// 进入事件循环
event_base_dispatch(base);
// 清理资源
event_free(listen_event);
close(listen_fd);
event_base_free(base);
return 0;
}
- 初始化:首先调用
event_base_new
创建一个event_base
实例,这是libevent库的核心数据结构,用于管理事件。 - 创建监听socket:使用系统调用
socket
、bind
和listen
创建一个监听指定端口的socket。 - 创建事件:通过
event_new
创建一个事件,指定事件关联的文件描述符(这里是监听socket)、事件类型(读事件且持续有效)以及事件发生时调用的回调函数accept_conn_cb
,并将event_base
指针作为参数传递给回调函数。 - 添加事件:调用
event_add
将创建的事件添加到event_base
中。 - 事件循环:调用
event_base_dispatch
进入事件循环,等待事件发生并处理。 - 清理资源:程序结束时,释放事件、关闭socket并释放
event_base
。