欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

recv 和 send 阻塞和非阻塞的区别和联系

程序员文章站 2022-06-29 23:44:14
...

 

目录

答案

深入说明

在 epoll 中的应用

总结


答案

  1. 阻塞,事情干不完就不要回来了!
  2. 非阻塞,能干多少就是多少,赶紧回来!

深入说明

// 将内核接收缓冲区中的数据 copy 到应用层中用户的 buffer 中。
int recv(int sockfd, void *buf, size_t len, int flag); 

// 将应用层中用户的 buffer 中的数据 copy 到内核发送缓冲区中。
int send(int sockfd, void *buf, size_t len, int flag);

1、recv 

阻塞模式下,如果内核的接收缓冲区中没有数据时,该函数就会阻塞。

非阻塞模式下,如果内核的接收缓冲区中没有数据时,该函数就会返回。

2、send

阻塞模式下,如果发送缓冲区剩余的空间小于要发送的数据的大小,那么该函数会阻塞。

非阻塞模式下,如果发送缓冲区剩余的空间大于要发送的数据的大小,那么该函数会返回。

在 epoll 中的应用

在 epoll 中,“可读” 和 “可写” 分别对应的选项是 “EPOLLIN” 和 “EPOLLOUT”。

1、水平触发模式(LT)

在该模式下,recv 和 send 为阻塞和非阻塞,结果是一样的。

举 recv 栗子来说,因为在该触发模式下,只要内核的接收缓冲区中有数据,epoll_wait() 函数都会返回,这就导致了虽然 recv 是阻塞模式的,但是每次调用时,内核缓冲区都是有数据的,所以不会导致 recv 阻塞。当然了,当 recv 时是阻塞的,就更不会造成阻塞情况了。同理,对于 send 也是一样的。

2、边沿触发模式(LT)

在该模式下,recv 和 send 需要为非阻塞模式,不然就会有问题。

还是举 recv 栗子来说,因为在该模式下,内核的接收缓冲区来数据了,那么 epoll_wait() 函数就会返回,但是仅仅返回一次,它可不管你是否在该次中是否完全取走了内核接收缓冲区中的数据。

在上述的前提下,recv 需要一个 while (true) 循环,保证将缓冲区中的数据取空。这就产生了一个问题,因为假如 recv 是阻塞的,那么当内核缓冲区中没有数据时,该函数就会阻塞,这是致命的,所以 recv 必须是非阻塞的。

同理,对于 send 也是一样的。理想情况时,终于有机会向对端发送数据了,一定要将想发的数据发尽。这就有问题了,如果是阻塞的,如果发到一半,发送缓冲区满了,那么该函数就阻塞了,实际上要避免这种情况,所以要将该 send 设置为非阻塞的。

总结

  1. 在水平触发模式下,recv 和 send 阻塞和非阻塞模式均可。

  2. 在边沿触发模式下,recv 和 send 必须为非阻塞模式。

(SAW:Game Over!)

相关标签: 通信