C语言笔记-27-网络-多路复用epoll
文章目录
- C语言笔记-27-网络-多路复用epoll
- 前言
- 一、epoll 函数
- 创建epoll实例(epoll例程)
- 控制epoll
- 等待检测epoll事件
- 二、epoll 代码示例(结合TCP服务端)
- 总结
前言
自学笔记,没有历史知识铺垫(省略百度部分)C语言笔记-27-网络-多路复用epoll
一、epoll 函数
注意 epoll在linux、unix中存在,macOS中没有,平替函数kqueue
创建epoll实例(epoll例程)
#include// 创建一个epoll实例,返回该实例的文件描述符.close()可以关闭文件描述符. int epoll_create(int size);
参数
size 实例大小(必须大于0)
返回值
成功 文件描述符
错误 -1 errno被设置
控制epoll
#include// 控制epoll文件描述符 int epoll_ctl(int epfd,int op, int fd, struct epoll_event *event);
参数
epfd 指定了要操作的epoll设备的文件描述符
op 改变fd相关事件
- EPOLL_CTL_ADD 新增fd相关的事件到epoll实例
- EPOLL_CTL_MOD 修改epoll实例中的fd相关的事件
- EPOLL_CTL_DEL 删除epoll实例中的fd
fd 指定了要代理的文件描述符
event 指定了跟fd相关的事件struct epoll_event { uint32_t events; epoll_data_t data; }; typedef union epoll_data { void *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t;
返回值
成功 0
错误 -1 errno被设置
等待检测epoll事件
#include// 等待epoll实例代理检测的I/O事件 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
参数
epfd 指定epoll实例
events 将检测到的事件保存到events中
maxevents 设置最大检测事件数
timeout 设置等待的毫秒数(-1 一直等待到有事件)
返回值
成功 返回可用的文件描述符的最大个数(如果指定时间内没有I/O请求,0)
错误 -1 errno被设置
二、epoll 代码示例(结合TCP服务端)
#include#include #include #include #include #include #include #include // 校验错误工具 void check_err(int fd, char *title) { if (fd == -1) { perror(title); } } // 启动服务函数 int start_server(short port) { printf("服务器端启动中...n"); // 使用sockaddr_in 替换 sockaddr struct sockaddr_in server_addr; // 家族簇 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 创建socket设备 int sfd = socket(PF_INET, SOCK_STREAM, 0); check_err(sfd, "创建socket设备失败"); // 绑定socket设备到ip、端口 int bindResult = bind(sfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); check_err(bindResult, "绑定socket设备失败"); // 监听客户端消息到 链接未决队列 int listenResult = listen(sfd, 10); check_err(listenResult, "监听socket设备失败"); printf("服务器端启动成功,开始监听客户端消息...n"); return sfd; } int main(int argc, char *argv[]) { // 启动服务 int sfd = start_server(8089); // 1. 创建容量为2的epoll实例 int efd = epoll_create(2); check_err(efd, "创建epoll实例失败"); // 2. 将socket服务添加到epoll实例中,且指定模式为只读 struct epoll_event e_event; // 只读 e_event.events = EPOLLIN; // tcp服务端文件描述符 e_event.data.fd = sfd; // 3. 控制epoll文件描述符 将sfd以e_event事件,加入到epoll实例中 int ctl_result = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &e_event); check_err(ctl_result, "将socket服务添加到epoll实例失败"); // 创建未决链接事件、IO事件容器 struct epoll_event ew_event[100]; while (1) { // 4. 等待检测epoll代理事件发生(此处存放未决链接事件和IO事件) 将接收的事件放入指定事件数量容器,且指定同时存储最大事件数 int ewfd = epoll_wait(efd, ew_event, 90, -1); check_err(ewfd, "等待epoll链接失败"); // 循环epoll事件容器 0时表示没有事件 for (int i = 0; i < ewfd; i++) { // 链接事件描述符时,表示未决链接事件发生 if (ew_event[i].data.fd == sfd) { // 从链接未决队列中取出未决链接 int accept_result = accept(sfd, NULL, NULL); check_err(accept_result, "接收客户端消息失败"); // 5. 将客户端链接的io读操作存入epoll实例 e_event.events = EPOLLIN; e_event.data.fd = accept_result; int ctl_result2 = epoll_ctl(efd, EPOLL_CTL_ADD, accept_result, &e_event); check_err(ctl_result2, "将accept_result加到epoll实例失败"); } else { // 客户端io读操作(在第5步加入到epoll进行管理的事件) char buf[128]; // 读取客户端消息 int r = read(ew_event[i].data.fd, buf, 128); // 处理客户端消息,返回给客户端 write(ew_event[i].data.fd, buf, r); // 写入控制台展示 write(1, buf, r); // 6. 移除客户端io读操作事件 int ctl_result3 = epoll_ctl(efd, EPOLL_CTL_DEL, ew_event[i].data.fd, &e_event); check_err(ctl_result3, "将accept_result从epoll实例移除失败"); // 结束客户端IO读写操作 close(ew_event[i].data.fd); } } } return 0; }
总结
本章主要为C语言笔记-27-网络-多路复用epoll