Linux下常用的IO模型:
1. 阻塞IO
fgets
read
getchar
fread
fgetc
recv
recvfrom
1. 让多个IO事件以同步方式处理,
2. 多个IO事件之间互相影响
3. CPU占有率低
2. 非阻塞IO
将IO对应的文件描述符设置成非阻塞方式。
O_NONBLOCK
fcntl
1.非阻塞一般搭配轮询方式同时监测多个IO
2.cpu占有率高
3. 信号驱动IO
SIGIO
1.实现异步IO操作,节省CPU开销
2.只能针对比较少的IO事件
4. IO多路复用(IO多路转接)*
在不创建新的进程和线程的前提下, 在一个进程中,同时监测多个IO
1. select
1. 文件描述符集合以数组(位图)的方式保存,最多监测1024个文件描述符。
2. 文件描述符集合创建在应用层,需要应用层和内核层反复拷贝
3. 内核层返回整个文件描述符集合,需要用户层遍历查找到达事件的文件描述符
4. 只能工作在水平触发模式(低速模式)
2. poll
1. 文件描述符集合以链表的方式保存,监测文件描述符可超过1024。
2. 文件描述符集合创建在应用层,需要应用层和内核层反复拷贝
3. 内核层返回整个文件描述符集合,需要用户层遍历查找到达事件的文件描述符
4. 只能工作在水平触发模式(低速模式)
3. epoll
1. 文件描述符集合以树型结构(红黑树)保存,监测文件描述符可超过1024, 提高了数据的查找速度。
2. 文件描述符集合创建在内核层;
3. 返回的是到达事件的文件描述符集合,无需遍历查找
4. 可以工作在水平触发模式(低速模式),也可以工作在边沿触发模式(高速模式)
使用select实现IO多路复用的步骤:
1. 创建文件描述符集合
2. 添加关注的文件描述符到集合
3. 传递给内核,内核开始监测IO事件 select
4. IO事件到达则返回结果
使用select实现IO多路复用的主要函数接口:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
功能:通知内核监测IO事件并返回事件结果
参数:
nfds:最大文件描述符+1
readfds: 文件描述符读事件集合
writefds:文件描述符写事件集合
exceptfds:其他
timeout : 超时时间
返回值:
成功:返回达到的事件的个数
失败:-1
设置超时:超时时间到,但没有事件到达:0
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
使用epoll实现IO多路复用的主要函数接口:
int epoll_create(int size);
功能:创建epoll的文件描述符集合
参数:
size:集合保存数据的最大个数
返回值:
成功:返回一个文件描述符(代表集合)
失败:-1
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:对集合中的文件描述符进行操作
参数:
epfd:文件描述符集合
op:操作
EPOLL_CTL_ADD : 添加
EPOLL_CTL_DEL : 删除
EPOLL_CTL_MOD:修改
fd : 要操作的文件描述符
event:文件描述符事件结构体地址
EPOLL_CTL_DEL : 删除----》NULL
返回值:
成功:0
失败:-1
int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
功能:开始监测IO事件
参数:
epfd:文件描述符集合
events: 保存返回的事件集合的地址
maxevents : 监测的文件描述符的个数
timeout:超时时间
-1 :不设置超时时间
返回值:
成功:返回实际到达的事件的个数
失败:-1
设置超时事件,超时没有事件到达:0
使用select实现TCP并发服务器: