1. I/O复用概念
I/O复用是指,在进程指定的一个或多个I/O条件就绪时,内核就能通知进程;
《UNIX网络编程》中使用这样一个例子:
大致代码流程如下,client端:
{
socket(...);
........//设置服务器地址、端口号等;
connect(...);
........
str_cli(stdin, sockfd);
}
void str_cli(...)
{
while(fgets()//从标准输入读数据)
{
write();//向服务器发送数据
if(EOF == readline())//从sockfd接收数据;
{
挂掉;
}
}
}
server端:
socket();
bind();
listen();
accept();
之后,从客户端收发数据;
启动客户/服务器对,然后kill掉服务器子进程;
客户端从标准输入读取数据之后,发送给服务器端,并从服务器端接收数据输出;kill掉服务器子进程时,会想client发送FIN报文,client端会回应一个ACK,此时client阻塞在fgets()调用上,暂时看不到这个EOF;此时输入一串字符串,client从fges()返回,并向服务器端发送数据,但是此时服务器端已经挂了,于是服务器端会直接回应一个RST,但是client端再向服务器端发送数据之后就调用了readline()读取服务器发送来的数据,由于前面接收到了服务器端发来的FIN,所以直接返回EOF,客户端就直接挂掉了;
这里client应该阻塞在套接字和标准输入的任何一个上面,而不只是阻塞在标准输入上;
2. 几种I/O模型
2.1 阻塞式I/O
默认情况下,所有套接字都是阻塞的;
对于阻塞式I/O而言,输入操作的两个阶段都是被阻塞的;
2.2 非阻塞式I/O
非阻塞式I/O一般采用轮询的方式,不断尝试读取,这种方式比较耗CPU;
2.3 I/O复用模型
select()允许指定等待多个事件,当其中的一个或多个发送或到达超时事件后才唤醒;
2.4 信号驱动式I/O模型
设置SIGIO的信号处理程序,在信号处理程序中调用recvfrom读取数据;
2.5 异步I/O模型
调用aio_xxx开始的函数,如果数据没有准备好会立即返回,否则直到数据已复制到进程缓冲器后才产生信号并发送给进程;这一点和信号驱动式I/O不同,信号驱动式I/O是在数据报准备好后就通知进程,此时数据还未从内核复制到用户空间;