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

目录

答案

深入说明

在 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 中的应用

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 必须为非阻塞模式。

拓展

1、将socket设置为非阻塞模式的方法。(socket设置为非阻塞的,recv 和 send 要设置为非阻塞的)

int flags = fcntl(sockfd, F_GETFL, 0);    //获取文件的flags值。

fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);     //设置成非阻塞模式;
int n = recv(fd, pbuff, kBuffLen, MSG_DONTWAIT);

 2、将socket设置为阻塞模式的方法。

int flags = fcntl(sockfd, F_GETFL, 0);    //获取文件的flags值。

fcntl(sockfd, F_SETFL, flags | ~O_NONBLOCK);     //设置成阻塞模式;
int n = recv(fd, pbuff, kBuffLen, 0); // flag = 0,默认是阻塞的。

 

(SAW:Game Over!)

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值