半关闭
使用close(fd);
所对应的文件描述符写和读都关闭了。
端口复用
可以解决绑定失败的问题。
IO多路复用(IO多路转接)
socket通信
io多路复用就是操作缓冲区
IO多路复用 是的程序能够同时监听多个文件描述符,能够提高程序的性能。
Linux下实现IO多路复用的系统调用主要有select、poll和epoll。
模型
每次循环遍历一遍,浪费资源。
BIO模型和NIO模型的区别
BIO(Blocking I/O)模型和NIO(Non-blocking I/O)模型是两种不同的I/O(Input/Output)模型,用于处理输入输出操作。
BIO模型:
BIO模型是一种阻塞式的I/O模型。在BIO模型下,当应用程序发起一个I/O请求时,它会被阻塞,直到操作系统完成相应的I/O操作才能继续执行后续代码。也就是说,在进行I/O操作期间,应用程序处于等待状态,无法处理其他任务。这种模型适合于连接数较少、每个连接负载较重的情况。
NIO模型:
NIO模型是一种非阻塞式的I/O模型。在NIO模型下,应用程序可以通过轮询操作系统来获取已经就绪的I/O事件,而不需要等待。它使用了事件驱动的方式,当一个I/O事件就绪时,应用程序会得到通知,然后可以立即处理该事件,而不需要等待其他I/O操作的完成。这种模型适合于连接数较多、每个连接负载较轻的情况。
总结一下,BIO模型是一种阻塞式的I/O模型,适用于连接数较少且每个连接负载较重的情况;而NIO模型是一种非阻塞式的I/O模型,适用于连接数较多且每个连接负载较轻的情况
解决措施
遍历标志位,检查
sellect
fd_set:为1024bit的标志位寄存器,是一个传入传出参数,将需要检测的文件描述符位置1传入,内核负责判断需要检测的文件描述符是否有IO操作,若有标志位依然为1,若没有则标志位置0,检测完成传出。
readfds:检测读缓冲区有数据了,可以读了,置1
writefds:检测写缓冲区还有空余空间可以写,置1
timeout:如果为NULL,表示永久阻塞,直到检测到了文件描述符变化;如果都=0, 不阻塞;如果时间>0,阻塞对应的时间。
返回值:
-1表示调用失败
>0:表示有几个文件描述符发生了变化
socket监听之后,进行文件描述符集合设置;
设置完成进行select,有文件描述符发生变化会有返回值,否则阻塞
判断哪个文件描述符发生了变换,进行相应的处理;
socket文件描述符发生变化,获取客户端连接文件描述符,并添加到集合
客户端连接文件描述符发生变化,对数据进行处理。
判断socket文件描述符,是否有新连接:
判断其他描述符,是否有数据来:
注意 : 上面的代码的问题是,设置rdset后传入传出后被修改了,下次传入不是想要的了,可以定义一个传入传出的集合tmp,一个设置的集合rdset,每次需要select时将设置集合赋值给tmp,进行操作。
缺点
poll
timeout:阻塞时间,单位为ms。
返回值:
-1:失败
>0(n):n个检测到集合中有n个文件描述符发生变化。
事件设置举例(通过|实现多个事件值):
应用
判断返回值,判断事件:
增加文件描述符:
从最开始向后遍历,找到最前面没有使用的文件描述符。
遍历搜索是哪个文件描述符发生事件,要从lfd开始,到最大文件描述符,索引下标则从0开始,到最大有文件描述符的下标。
缺点
改善了3.4条缺点,但其他依然存在。
epoll
创建,在内核就存在一个eventpoll实例,并返回内核缓冲区中的文件描述符
操作
检测
返回值:
-1:调用失败
>0:文件描述符,操作epoll的实例
三个事件分别是读、写、错误。
应用
注意 :这个地方对epoll监听的事件如果有多种,就要对事件进行判断,防止出现错误判断应用;对其判断就是通过epevs[i].enents & EPOLL…进行判断(返回值与事件与)。
工作模式
LT模式和ET模式
上边缺省的工作方式就是默认工作方式。
读一次也算操作了,即使缓冲区里有数据也不重复通知,直到有新数据进来才会再进行新的通知。
两者区别:LT模式:
ET模式:
设置ET模式(在设置事件时或上EPOLLET):
再ET模式下数据读取可采用循环读取方式:
可以通过循环读取数据,直到读取结束,
read阻塞控制是由于文件描述符属性控制,所以可以通过设置文件描述符属性,改变为非阻塞:
需要头文件:
#include <fcntl.h>
#include <errno.h>
//设置cfd属性非阻塞
int flag = fcntl(cfd, F_GETFL);
flag |= O_NONBLOCK;
fcntl(cfd, F_SETFL, flag);
非阻塞情况,没有数据read会返回-1,错误号为EAGAIN,可通过判断处理
打印到终端的方式
write(STDOUT_FILENO, buf, len);
printf(“%s\n”, buf);
IO多路复用是同步还是异步?
epoll也是同步的
具体数据读取还是通过应用程序自己完成的
只有使用了特殊API调用才是异步