为什么Linux的IO多路复用技术需要用非堵塞IO

堵塞IO与非堵塞IO的区别

1、对于read操作。当缓冲区有数据时,堵塞IO与非堵塞IO都是能读多少数据就读多少数据读完立即返回,返回值为读取到的字节数。当缓冲区为空时,对于堵塞IO会堵塞住,CPU会切换给其他进程或者线程;对于非堵塞IO,read函数会返回-1并且设置错误码为EAGIAN或者EWOULDBLOCK。
2、对于write操作。当缓冲区足够容纳要写入数据时,堵塞与非堵塞IO都会把全部数据都写入缓冲区后立即返回,返回值为写入的大小。当缓冲区不足时,对于堵塞IO,write操作会堵塞住,CPU切换给其他进程或者线程,直到全部数据都写入为止,函数返回写入的大小,但是如果对端发送了RST报文关闭连接或者超时等错误,那么write函数立即返回,返回写入的数据大小,如果再次调用write函数,会返回-1,更新错误码;对于非堵塞IO,write函数会写入能写入的数据,返回写入的大小,如果缓冲区不能写入任何数据,则返回-1并且更新错误码为EAGAIN或者EWOLDBLOCK。
3、对于监听套接字。当已连接队列有连接的socket时,堵塞与非堵塞IO调用accept函数都会返回已连接的socket。当已连接队列为空时,对于堵塞IO会堵塞在accept函数,直到有新的连接建立,CPU切换给其他进程或者线程;对于非堵塞IO,accept函数会返回-1并且更新错误码为EAGAIN或者EWOLDBLOCK。
4、对于客户端的connect。对于堵塞IO会堵塞在connect函数的调用上,直到三次握手完成连接建立成功,connect返回0;对于非堵塞IO,connect函数会立即返回-1更新错误码为EINPROGRESS,linux内核会继续完成三次握手,应用程序可以用select,poll,epoll的IO复用技术获取连接成功事件。

为什么Linux的IO多路复用技术需要用非堵塞IO

场景一:客户端设置如下的选项:

struct linger ling;
ling.l_onoff = 1; 
ling.l_linger = 0;
setsockopt(socket_fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
close(socket_fd);

当客户端连接建立成功的时候,立即调用close函数(或者连接建立后可能core了),那么此时客户端会发送RST报文关闭连接;当服务端收到连接后,poll等IO复用技术检测到连接事件,但是服务端可能会过一会会才调用accept函数,在调用accept的时间间隔内,由于连接已经关闭了,linux会把连接从已连接队列删除。如果是堵塞IO,那么应用程序将堵塞在accept函数上面。
场景二:select检测到可写后,应用程序就可以调用write函数,往缓冲区里面写数据,但是缓冲区可能不足以存放要写的数据,那么非堵塞IO将堵塞在write函数上面。
故Linux的IO多路复用技术需要用非堵塞IO。

你可能感兴趣的:(linux,c++)