2009年(41)
分类: LINUX
2009-04-17 09:38:06
在默认的情况下,socket是blocking的。也就是说,如果某进程请求的操作不能及时完成,则会去睡觉。可以将有可能block的socket操作分为以下4个类型:
1、输入
包括read、readv、recv、recvfrom和recvmsg函数。在blocking模式下调用它们时,如果接收缓存内没有满足要求的数据可读,则进程会睡觉。
在nonblocking模式下,如果读取请求不能立即完成,则以上几个函数会直接返回,并将errno置为EWOULDBLOCK。
2、输出
包括write、writev、send、sentto和sendmsg函数。在blocking模式下调用它们时,如果发送缓存没有空间,则它们会一直阻塞。注意,UDP没有流量控制,因此没有发送缓存这一说,发送数据时,内核直接把数据报发送出去,因此blocking模式下,UDP也永远不会阻塞。
在nonblocking模式下,如果发送缓存中没有足够的空间(TCP,和SO_SNDLOWAT有关),则以上几个函数会直接返回,errno置为EWOULDBLOCK。
3、接收到来的连接
blocking模式下,如果没有连接到达,则进程会一直睡觉。
在nonblocking模式下,如果没有连接到达,则函数直接返回,errno为EWOULDBLOCK。在某些系统上使用select对listening socket进行操作时需特别注意,最好将socket设置为nonblocking模式,否则有可能出问题,详见unpv13e 16.6。
4、connect
blocking模式下,对一个TCP socket调用connect,会一直阻塞直到“3次握手”的第二个数据包到达————SYN的ACK。
在nonblocking模式下,如果连接不能立即完成,则connect会立即返回,且errno为EPROGRESS。特别的,connect在nonblocking模式下返回的错误与前3种都不同。connect返回并不代表连接动作终止,相反,“3次握手”的过程会由底层完成。那么,如何知道nonblocking模式下连接是否成功?有2种情况:
·连接可以立即完成,connect成功返回
·连接不能立即完成,connect返回错误。则此时调用select,并注册connecting socket的读/写事件,那么,在连接完成或发生错误时,select返回并标记相应的事件。
以上4个分类中,除了connect外,将socket显式的设置为nonblocking模式(O_NONBLOCK)都不是必要条件。