搜索
写经验 领红包
 > 旅游

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;

本文内容由快快网络小媛创作整理编辑!