可能阻塞的套接字调用可分为以下四类:
1)输出操作:包括read、readv、recv、recvfrom和recvmsg共5个函数。
- 对于TCP协议而言,由于TCP是面向字节流的,因此被阻塞的进程被唤醒,是由于只要有一些数据到达,这些数据可能是单个字节,也可能是一个TCP的完整分节中的数据。因此如果想等到某个固定数目的数据可读为止,可以指定MSG_WAITALL标志。
- 对于UDP协议而言,由于UDP是数据报协议,如果一个阻塞的UDP套接字的接收缓冲区为空,对它调用输入函数的进程将被投入睡眠,直到有UDP数据报到达。
- 对于非阻塞的套接字,如果输入操作不能被满足(对于TCP套接字即至少有一个字节的数据可读,对于UDP套接字即有一个完整的数据报可读),相应调用将立即返回一个EWOULDBLOCK错误。
2)输出操作:包括write、writev、send、sendto和sendmsg共5个函数。
- 对于阻塞的TCP套接字,如果其发送缓冲区中没有空间,进程将被投入睡眠,直到有空间为止。
- 对于一个非阻塞的TCP套接字,如果其发送缓冲区中根本没有空间,输出函数调用将立即返回EWOULDBLOCK错误。如果其发送缓冲区中有一些空间,返回值将是内核能够复制到该缓冲区中的字节数。这个字数也称为不足计数。
- UDP不存在真正的缓冲区,因此对于一个阻塞的UDP套接字,输出函数将不会因与TCP套接字一样的原因而阻塞,但可能会因为其他原因而阻塞。
3)接受外来连接:accept函数。
4)发起外出连接:connect函数。
如果对一个非阻塞的TCP套接字调用connect,并且连接不能立即建立,那么连接的建立能照样发起(譬如TCP三路握手的第一个分组),不过会返回一个EINPROGRESS错误。
非阻塞的connect有三个用途
- 可以将三路握手叠加在其他操作上。
- 同时建立多个连接。
- 既然使用select等待连接的建立,则可以给select指定一个时间限制,使得我们能够缩短connect的超时。
如果连接到的服务器在同一个主机上,那么当我们调用connect时,连接通常立刻建立。
有关于select和非阻塞connect有以下两个规则:
- 当连接成功建立时,描述符变为可写。
- 当连接建立遇到错误时,描述符变为既可读又可写。