简要说明
在Linux/Unix上总共有五种IO模型,阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO。
阻塞IO
socket(int domain,int type,int protocol)
bind(int sockfd,const struct sockaddr*,socklen_t addrlen);
listen(int sockfd,int backlog);//TCP三次握手完成在listen阶段
accept(int sockfd,struct sockaddr *addr,socklen_t)//取出连接并不关心此时的连接处于何种状态
//程序一般会阻塞在读写函数上,一次只能处理一个事件,效率低且浪费资源
//一个形象的例子就是 我们烧水做饭,烧水假如需要5分钟,阻塞IO就是在这等
//上五分钟
非阻塞IO
int setnonblocking(int fd)
{
int old_option=fcntl(fd,F_GETFL);
int new_option=old_option | O_NONBLOCK;
fcntl(fd,F_SETFL,new_option);
return old_option;
}
//非阻塞IO 根据上面的例子就是在烧水的时候可能会选择做其他的事情例如洗 //菜
IO复用
IO复用一般有三种,分别是select、poll和epoll。
select(int nfds,fd_set* readfds,fd_set*writefds,fd_set*exceptfds,struct timeval* timeout);
poll(struct pollfd* fds,nfds_t nfds,int timeout);
//epoll的实现方式不同于前两者,epoll直接将文件描述符上的事件放在内核 //的一个事件表里,避免了每次调用都需要重复传入文件描述符集
epoll_create(int size);
epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
epoll_wait(int epfd,struct epoll_event* events,int maxevents,int timeout);
//IO复用目的就是为了能够同时处理更多连接
LT和ET模式
LT模式:当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序可以不立即处理该事件。当应用程序下一次调用epoll_wait时,epoll_wait还会再次向应用程序通告此事件,直到此事件被处理。
ET模式:当eopll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序必须立即处理该事件,因为后续的epoll_wait调用不会再向应用程序通知此事件。这很大程度上降低了同一个epoll事件被重复触发的次数,因此效率要比LT模式高。
信号驱动IO
套接字需要安装一个信号处理函数,当进程需要读取数据时会调用sigaction,内核接收完数据后会通知进程处理数据。
类比于烧水的时候开一个闹钟,闹钟响了来关火
异步IO
异步IO就是用户发起read操作后,内核会将数据拷贝到用户内存,然后内核发送信号告诉用户操作完毕。
相当于我告诉管家我要烧壶水,管家会帮我烧水并烧好水后告诉我,我可以直接用了。