UNIX网络编程----非阻塞式I/O(十六)

UNIX网络编程-----非阻塞式I/O

一、概述

套接字的默认状态是阻塞的。这就意味着放发出一个不能立即完成的套接字调用时,其进程被投入睡眠,等待相应操作完成,可能阻塞的套接字调用可分为以下四类:

1)             输入操作:包括read、readv、readmsg、readfrom、recv共5个函数。如果某个进程对一个阻塞的TCP套接字(默认设置)调用这些输入函数之一,而且该套接字的接受缓冲区中没有数据可读,该进程将被投入睡眠,直到一些数据到达。既然TCP是字节流协议,该进程的唤醒就是只要有一些数据到达,这些数据既可能是单个字节,也可以是一个完整的TCP分节中的数据,如果想等到某个固定数据的数据可读为止,那么可以调用我们的readn函数或者指定MSG_WAITALL标志。

如果一个阻塞的UDP套接字的接受缓冲区为空,对它调用输入函数的进程将被投入睡眠,直到有UDP数据报到达。

对于非阻塞的套接字,如果输入操作不能被满足(对于TCP套接字既至少有一个字节的数据可读,对于UDP套接字既有一个完整的数据报可读),相应调用将立即返回一个EWOULDBLOCK错误。

2)             输出操作,包括write、writev、sendmsg、senfto、send共5个函数。对于一个TCP套接字,内核将从应用进程的缓冲区到该套接字的发送缓冲区复制数据。对于阻塞的套接字,如果其发送缓冲区中没有空间,进程将被投入睡眠,直到有空间为止。

对于一个非阻塞的TCP套接字,如果其发送缓冲区中根本没有空间,输出函数调用将立即返回一个EWOULDBLOCK错误。如果其发送缓冲区中有一些空间,返回值将是内核能够复制到数据缓冲区的字节数。这个字节数也称为不足计数。

其实UDP套接字不存在真正的发送缓冲区。内核只是复制应用进程数据并把它沿协议栈向下传递,渐渐冠以UDP首部和IP首部。因此对一个阻塞的UDP套接字(默认设置),输出函数调用将不会因与TCP套接字一样的原因而阻塞,不过有可能会因其他的原因而阻塞。

3)      接受外来链接,即accept函数。如果对一个阻塞的套接字调用accept函数,并             且商无新的链接到达,调用进程将被投入睡眠。

       如果对于一个非阻塞的套接字调用accept函数,并且尚无新的链接到达,accept调用将立即返回一个EWOULDBLOCK。

4)         发起外出链接,即用于TCP的connect函数。(connect同样可用于UDP,不过它不能使一个“真正”的链接建立起来,它只是使内核保存对端的IP地址和端口号)TCP链接建立设计一个三路握手过程,而且connect函数一直要等到客户收到对于自己的SYN的ACK为止才返回。这意味着TCP的每个connect总会阻塞其调用进程至少一个到服务器的RTT时间

二、非阻塞connect

         当在一个非阻塞的TCP套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的TCP三路握手继续进行。非阻塞的connect有三个用途

1)  我们可以把三路握手叠加在其他处理上。完成一个connect要花一个RTT时间,其波动范围很大,从局域网上的几个毫秒到几百个毫秒甚至是广域网的几秒。这段时间可以处理其他工作。

2)  可以使用这个技术同时建立多个连接。

3)  使用select等待连接的建立,我们可以给select指定一个时间限制,使得我们能够缩短connect的超时。许多实现有着从75毫秒到数分钟的connect超时时间。应用程序有时想要一个更短的超时时间,可以使用非阻塞的connect.

你可能感兴趣的:(linux网络编程)