Unix网络编程之socket阻塞与非阻塞模式下函数调用结果分析

套接字默认状态是阻塞的,这就意味着当发出一个不能立刻完成的套接字调用时,其进程将被投入睡眠,等待相应操作完成。

可能阻塞的套接字调用可分为四类:

(1)输入操作:read,readv,recv,recvfrom,recvmsg,如果某个进程对一个 阻塞的TCP套接字调用这些输入函数之一,而套接字的接收缓冲区中没有数据可读,该进程将被投入睡眠中,直到有些数据到达。TCP是字节流协议,该唤醒就是要有数据到达,可能是单个字节也可能是完整TCP分节数据,想等到某个固定数目数据可读,可用readn或者指定MSG_WAITALL.UDP是数据报协议,如果一个阻塞的UDP套接字的接收缓冲区为空,对调用输入函数的进程投入到睡眠中
(2)输出操作:write,writev,send,sendto,sendmsg这5个函数。对一个tcp套接字,内核将从 应用进程的缓冲区该套接字的发送缓冲区复制数据对于阻塞的套接字,如果其发送缓冲区没有空间,进程投入睡眠,直到有空间为止.UDP套接字不存在真正意义上的发送缓冲区,内核只复制应用程序数据并把它沿协议栈向下传送,渐次加上UDP首部和IP首部
(3)接受外来连接,accept函数,对于一个阻塞套接字调用accept,并且无新的连接到达,调用进程睡眠
(4)发起外来连接,tcp的connect函数,tcp连接涉及三路握手过程,而且connect函数一直要等到客户收到对于自己的SYN的ACK为止才返回,意味着TCP的每个connect函数总会阻塞其调用进程至少一个 rtt时间

设置套接字为非阻塞模式,以上四种情况函数调用的返回如下:
(1) 对于非阻塞套接字,如果输入操作不能被满足,对于TCP套接字至少有一个字节的数据可读,对于UDP有一个完整数据报可读,相应调用立刻返回一个 EWOULDBLOCK
(errno.h中定义)错误
(2) 对于一个非阻塞的tcp套接字,如果其发送缓冲区中根本没有空间,输出函数(write,writev,send,sendto,sendmsg)调用立刻返回一个EWOULDBLOCK错误,如果其发送缓冲区中有一些空间,返回值将是内核能够复制到该缓冲区的字节数,这个字节也称为 不足计数
(3) 对于一个非阻塞的套接字调用accept函数,无新连接到达,accept立刻返回一个EWOULDBLOCK错误
(4) 非阻塞套接字发起外出连接,调用TCP的connect函数,情况一,连接不能立刻建立,那么连接能照样发起(例如送出TCP三路握手的第一个分组syn),不过会立刻返回一个 EINPROGRESS错误。注意这个错误不同于(1)\(2)\(3)三种情况,情况二、另外请注意,有些连接通常发生在服务器和客户处于一个主机的情况下,因此即使对于一个非阻塞的connect,我们也得预备connect成功返回的情况发生
个人理解:

套接字的阻塞模式,意味着IO操作无法完成时,阻塞进程,涉及到socket的可读可写条件与tcp三路握手机制,socket的接收缓冲区有个标记位,当接收缓冲区的数据大于该标记位时,socket可读,阻塞进程的IO操作返回,否则进程休眠。socket的发送缓冲区同样有个标记位,当发送缓冲区可发送数据小于该标记位,表示仍有内存可发送数据,socket可写,阻塞进程的IO操作返回,否则进程需等发送缓冲区的数据通过底层协议传输给对端socket之后,才会返回。accept函数,在阻塞socket及无新连接时阻塞,connect函数,如果连接对端成功,至少需要一个rtt时间。

通常我们采用非阻塞模式处理socket,设置函数setsockopt,ioctl.非阻塞模式下,对I/O操作的各种返回值进行合理处理,若协议为tcp,设置监听套接字非阻塞,则其accept返回的socket也是非阻塞的

你可能感兴趣的:(Unix网络编程卷一学习记录)