做的网站电脑上跟手机上不一样,定西网页设计,北京建设工程交易网,佛山网站建设服务文章目录 I/O多路复用select()select()缺点 poll()poll()缺点 epoll()LT(水平触发模式)ET(边缘触发模式)具体函数 I/O多路复用
多进程和多线程实现并发会消耗大量的资源#xff0c;主进程/线程用于监听和接受连接#xff0c;再创建多个子进程/子线程来完成与连接的各个客户端… 文章目录 I/O多路复用select()select()缺点 poll()poll()缺点 epoll()LT(水平触发模式)ET(边缘触发模式)具体函数 I/O多路复用
多进程和多线程实现并发会消耗大量的资源主进程/线程用于监听和接受连接再创建多个子进程/子线程来完成与连接的各个客户端的通信。I/O多路复用使程序能够同时监听多个文件描述符能够提高程序的性能Linux下实现I/O多路复用的系统调用主要有select、poll、epoll。监听文件描述符的I/O请求实际上是检测其相应的I/O缓冲区是否有数据
select()
构造一个文件描述符列表限制1024个将指定的需要被监听的文件描述符添加到该列表中采用位视图法。调用一个系统函数监听列表中的文件描述符直到这些描述符中的一个或者多个进行I/O操作时该函数返回该函数是阻塞的且由内核完成对文件描述符的检测操作将用户态的文件描述符列表拷贝到内核态进行检测。返回时会通知进程有几个文件描述符要进行I/O操作将内核态检测的文件描述符列表更新再拷贝到用户态具体是哪些文件描述符还需要从监听的文件描述符开始再次遍历更新后的文件描述符列表。因为内核会改变原本的文件描述符列表所以需要设置两个列表一个记录需要监听的文件描述符仅在添加或删除文件描述符时改变另一个负责送入内核进行检测并进行交互。
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
//成功时返回准备好的文件描述符数量。被信号打断时返回-1超时时返回0。//nfds: 需要监控的文件描述符集合中最大的文件描述符加1即监控多少个文件描述符。//readfds: 指向一个fd_set文件描述符列表结构的指针用于存放需要检查可读性的文件描述符集合由内核完成对文件描述符的检测操作。//writefds: 同上但用于存放需要检查可写性的文件描述符集合。//exceptfds: 同上用于存放需要检查异常事件如错误状态的文件描述符集合。//timeout: 指定select调用的最长等待时间。如果为NULLselect将一直阻塞直到有描述符准备好如果指向一个非零超时时间则等待指定的时间到期后无论是否有描述符准备好都将返回。fd_set read;//创建文件描述符列表判断读
FD_ZERO(read);//初始化列表
FD_SET(3,read);//将文件描述符3添加到列表中
FD_SET(5,read);//将文件描述符5添加到列表中
FD_SET(100,read);//将文件描述符100添加到列表中
select(101,read,NULL,NULL,NULL);//送入内核检测文件描述符的IO操作并返回个数
FD_ISSET(3,read);//判断文件描述符3是否在列表中
FD_CLR(100,read);//将文件描述符100从列表中清除select()缺点
每次调用select都需要将文件描述符列表从用户态复制到内核态开销较大在内核中每次都要遍历这个文件描述符列表开销较大select的文件描述符列表大小仅有1024个个数较少文件描述符列表每次都要重置需要两个文件描述符列表一个用于记录需要监听的另一个则和内核交互。
poll()
使用pollfd结构体数组来记录需要监听的文件描述符和相应的事件改进了select限制1024个文件描述符的大小可以自行指定。结构体中还有events以及revents表示监听的事件和返回时触发的事件不需要像select一样重置文件描述符列表。结构体数组需要拷贝到内核中由内核对需要进行I/O操作的文件描述符进行检测返回时会通知进程有几个文件描述符要进行I/O操作具体是哪些文件描述符还需要遍历数组。
struct pollfd {int fd; /* 文件描述符 */short events;/* 监视的事件可以是 POLLIN读、POLLOUT写、POLLERR错误等 */short revents;/* 返回时被触发的事件 */
};#include poll.hint poll(struct pollfd *fds, nfds_t nfds, int timeout);
//fds: 指向pollfd结构体数组的指针每个结构体代表一个要监控的文件描述符及其相关的事件。//nfds: 数组fds中元素的个数即要监控的文件描述符的数量。//timeout: 指定poll()函数的等待时间单位为毫秒。可以是正值等待指定的毫秒数后返回、0立即返回不管文件描述符是否就绪、-1无限等待直到至少有一个文件描述符就绪poll()缺点
在处理文件描述符时仍需要将结构体数组拷贝到内核且仍需遍历整个pollfd数组。返回值依然是需要执行I/O操作的文件描述符的个数还需要遍历具体是哪些文件描述符。与select()一样当监控的文件描述符数量巨大时poll()需要维护一个较大的数组这会消耗较多的内存
epoll()
epoll与poll大致相同但是epoll更为高效采用红黑树作为底层的数据结构通过epoll对象来监听处理多个文件描述符epoll不仅会返回需要进行IO的文件描述符个数也会直接返回具体的需要进行I/O的文件描述符存储在epoll_event结构体数组中。创建对象后内核维护的eventpoll结构体存储与epoll对象相关的信息包括但不限于 一个红黑树rb_root用于快速插入和删除文件描述符通过文件描述符的值作为键。 一个双向链表rdlist用于维护就绪事件epoll_event的列表以供epoll_wait快速检索。 一个等待队列头wq用于存放等待epoll_wait调用的进程。epoll_event结构体
struct epoll_event {uint32_t events; // 指定的和发生的事件掩码epoll_data_t data; // 用户定义的数据可以存储文件描述符或其他信息
};//events字段可以是如下标志的组合
/*
EPOLLIN可读事件。
EPOLLOUT可写事件。
EPOLLERR错误事件。
EPOLLHUP挂起事件。
EPOLLET边缘触发和EPOLLLEVEL水平触发等。
*/LT(水平触发模式)
在这种模式下只要文件描述符上的事件如可读、可写保持激活状态每次调用epoll_wait时都会报告该事件。即使应用程序未完全处理完缓冲区中的数据下次调用epoll_wait时只要数据仍然可读或可写事件还会被触发。可能导致同一事件被多次报告因此应用程序需要能够处理重复的事件通知。
ET(边缘触发模式)
在这种模式下epoll_wait仅在文件描述符的就绪状态发生变化时报告一次事件之后不会重复报告除非该事件状态再次改变。一旦某个事件被消费比如读取了新到的数据直到又有新的数据到达或状态再次改变之前epoll_wait不会再报告相同的事件。需要应用程序一次性完全处理事件否则可能会错过后续的通知。例如如果缓冲区中有数据可读但应用程序没有读完下次调用epoll_wait可能不会再次通知直到有新的数据到来。需要使用非阻塞的接口避免把处理多个文件描述符的任务饿死。
fcntl(fd, F_SETFL, fcntl(fd,F_GETFL,0)| O_NONBLOCK)//获取并设置非阻塞更节省资源减少不必要的唤醒和上下文切换适合处理高负载和高吞吐量的场景。
具体函数
int epoll epoll_create(1); // 创建epoll对象参数通常设为1成功时返回新的epoll文件描述符同时内核会生成一个eventpoll结构体用来负责维护一个高效的事件等待列表以及处理文件描述符的添加、修改、删除和事件的等待与通知epoll文件描述符用来标识该eventpoll结构体。struct epoll_event event;
event.events EPOLLIN | EPOLLET; // 监听读事件使用边缘触发模式event.data.fd socket_fd; // 监听的socket描述符int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
//控制epoll对象上的文件描述符监控事件可以添加、修改或删除监控。
//成功时返回0失败时返回-1并设置errno。
//epfd由epoll_create返回的epoll文件描述符标识eventpoll。
//op操作类型可以是
/*
EPOLL_CTL_ADD添加、EPOLL_CTL_MOD修改、EPOLL_CTL_DEL删除。
*/
//fd要操作的文件描述符。
//event指向epoll_event结构体的指针指定了要监控的事件类型。int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
//等待一个或多个epoll事件的发生获取准备就绪的epoll_enent事件。
//成功时返回就绪的文件描述符数量0表示超时-1表示出错。
//epfdepoll文件描述符。
//events指向epoll_event结构体数组的指针用于存放发生的事件信息。
//maxeventsevents数组的最大容量即最多可以返回的事件数量。
//timeout等待超时时间单位为毫秒-1表示无限等待0表示立即返回正值为等待的最长时间。