socket阻塞与非阻塞(socket阻塞和非阻塞的区别)
导语:socket在阻塞和非阻塞下send / receive的区别
发送
TCP(send):
阻塞 - 会等待所有数据拷贝到发送缓冲区才会返回。也就是说在阻塞模式下,send函数的返回值一定是参数中的发送长度的大小。
非阻塞 - 会立即返回,尽可能多的拷贝数据到缓冲区,但不保证全部拷贝后就会返回,也就是说在非阻塞模式下,send函数的返回值可能会比参数中的长度来的小,当然如果缓冲区满的话就会立即返回
UDP(sendto):
即使在阻塞模式下,sendto()也不会阻塞,因为UDP没有真正的发送缓冲区。他只是把应用缓冲区数据拷贝到下层协议栈,然后加上UDP头和IP头,因此他的行为在阻塞和非阻塞下是一样的。
接收
TCP(recv):
阻塞 - recv会阻塞,直到缓冲区里至少有一个字节才会返回。当没有数据到来的时候,recv会一直阻塞或者直到超时
非阻塞 - recv不会阻塞,如果有任何一个字节就会立即返回,如果没有字节,就会返回EWOULDBLOCK或者EAGAIN
UDP(recvfrom):
阻塞 - recvfrom会阻塞,知道缓冲区至少有一个完整的UDP数据包才会返回
非阻塞 - recvfrom会立即返回,如果有完整数据包就返回数据报大小,如果没有,就返回EWOULDBLOCK或者EAGAIN
总结几个比较关键的点:
UDP的sendto()不非阻塞还是非阻塞,因为他没有发送缓冲区,所以对应用层来说,都是直接发送的UDP的recvfrom()区分阻塞和非阻塞,界定大小不是像TCP的一个字节,而是必须一个完整包,否则会返回EWOULDBLOCK / EAGAINTCP的send()在非阻塞模式下,返回的字节数会比参数中的数据长度小或者相等,因为他只能尽可能的保证拷贝到发送缓冲区PS:
附上设置socket为非阻塞 - NONBLOCK的几个代码片段:
1.socket()默认创建是阻塞的,可以通过追加flag让其成为非阻塞
int s = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
2.使用fcntl设置为非阻塞
if ((nFlags = fcntl (nSock, F_GETFL, 0)) < 0)
return 0;
nFlags = nFlags | O_NONBLOCK;
if (fcntl (nSock, F_SETFL, nFlags) < 0)
return 0;
3.使用fcntl设置为阻塞
if ((nFlags = fcntl (nSock, F_GETFL, 0)) < 0)
return 0;
nFlags = nFlags & (~O_NONBLOCK);
if (fcntl (nSock, F_SETFL, nFlags) < 0)
return 0;
本文内容由快快网络小媛创作整理编辑!