Linux I/O模型详解(6)
导读:Linux,链表用于存储所有的事件, 当监听的事件发生后, 内核会回调 ep_poll_callback 函数把这个事件添加到 rdllist 这个双向链表中。一旦有事件发生,epoll 就会将该
Linux
链表用于存储所有的事件, 当监听的事件发生后, 内核会回调 ep_poll_callback 函数把这个事件添加到 rdllist 这个双向链表中。一旦有事件发生,epoll 就会将该事件添加到双向链表中。那么当我们调用 epoll_wait 时,epoll_wait 只需要检查 rdlist 双向链表中是否有存在注册的事件,效率非常可观。这里也需要将发生了的事件复制到用户态内存中即可。下面看下 epoll 的相关函数
#include <sys/epoll.h>
// 该 size 已经没有意义, epoll 早期实现中, 对于监控文件描述符的组织并不是使用红黑树,而是hash表
int epoll_create ( int size );
// epfd: epoll的描述符, epoll_create 的返回值
// fd:要操作的文件描述符
// op:指定操作类型
// EPOLL_CTL_ADD:往事件表中注册fd上的事件
// EPOLL_CTL_MOD:修改fd上的注册事件
// EPOLL_CTL_DEL:删除fd上的注册事件
// event:指定事件 可读,可写及异常等事件
int epoll_ctl ( int epfd, int op, int fd, struct epoll_event *event );
// epfd: epoll的描述符, epoll_create 的返回值
// events:检测到事件,将所有就绪的事件从内核事件表中复制到它的第二个参数events指向的数组中。
// maxevents:指定最多监听多少个事件
// timeout:指定epoll的超时时间,单位是毫秒。当timeout为-1是,epoll_wait调用将永远阻塞,直到某个时间发生。当timeout为0时,epoll_wait调用将立即返回。
// 返回:成功时返回就绪的文件描述符的个数,失败时返回-1并设置errno
int epoll_wait ( int epfd, struct epoll_event* events, int maxevents, int timeout );
因为 epoll 是 Linux 特有的,在 Java 中,要使用 epoll 机制,通常需要通过 JNI(Java Native Interface)来调用操作系统特定的 epoll 函数。
以下为 基于 C++ 实现的 epoll 示例:
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <fcntl.h>
int create_and_bind(int port) {
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
// 设置 socket 属性
struct sockaddr_in server_addr{};
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(port);
// 绑定端口
bind(listen_fd, (struct sockaddr*)&server_addr, sizeof(server_addr))
return listen_fd;
}
int main() {
// 创建服务端
int listen_fd = create_and_bind(8080);
listen(listen_fd, 10)
// 创建 epoll
int epoll_fd = epoll_create1(0);
// 初始化epoll结构并将服务端 fd 加入 epoll
struct epoll_event event{};
event.data.fd = listen_fd;
event.events = EPOLLIN;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event) == -1) {
perror("epoll_ctl");
exit(EXIT_FAILURE);
}
struct epoll_event events[64];
while (true) {
// 等待 epoll 返回事件
int num_events = epoll_wait(epoll_fd, events, 64, -1);
// 处理事件
for (int i = 0; i < num_events; ++i) {
// 如果是服务端监听的 fd, 那么表示新的客户端连接进来
if (events[i].data.fd == listen_fd) {
// 调用 accept, 接受客户端连接
int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, &addr_len);
// 将新的连接也加入到 epoll 中
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event);
} else {
// 如果不是服务端监听的 fd, 那么就是与客户端的连接有数据进来
// read 方法读数据
ssize_t n = read(client_fd, buffer, sizeof(buffer));
if (n <= 0) {
// 客户端断开连接
} else {
// 数据读取成功, 处理业务
}
}
}
}
close(listen_fd);
return 0;
}
相关阅读
-
如何用u盘装系统win10 u盘装机大师怎么装win10
今天介绍u盘装机大师怎么装win10的相关话题,关于如何用u盘装系统win10 u盘装机大师怎么装win10,如有不对的地方欢迎指正! 在使用U盘装机大师安装win10系统的时候,很多的用户们发现不知道该
-
电脑高级选项怎么修复电脑蓝屏 win10开机强制进入高级选项教程
小编为大家讲一讲电脑高级选项怎么修复电脑蓝屏和win10开机强制进入高级选项教程的IT知识,接下来IT袋小编为大家介绍。 “高级启动选项”可以在高级疑难解答模式下启动Windows。高级启动选
-
win10剑灵掉帧解决方法 win10玩剑灵掉帧卡顿怎么解决
为大家说一说win10玩剑灵掉帧卡顿怎么解决的教程内容,关于win10剑灵掉帧解决方法 win10玩剑灵掉帧卡顿怎么解决,下面IT袋为您详细介绍 我们在使用win10系统电脑的时候,有的游戏玩家会发现
-
win10鼠标不能动 win10鼠标能动但点击无反应解决教程
本文导读:win10鼠标能动但点击无反应解决教程方面的知识,关于win10鼠标不能动 win10鼠标能动但点击无反应解决教程,接下来IT袋带大家一起了解。 如果遇到了鼠标可以移动但是就是不能单击


