网络编程 - 阻塞和非阻塞

说明

  • 网络编程中有两种模式:阻塞和非阻塞,默认是采用阻塞方式。

什么是阻塞和非阻塞

  • 阻塞和非阻塞是对操作请求者在等待返回结果时的状态描述,阻塞时,在操作请求结果返回前,当前线程会被挂起,得到结果之后返回;非阻塞时,如果不能立刻得到结果,系统不会挂起当前线程,而是直接返回错误信息,因此对应非阻塞的情况,调用者需要定时轮询查看处理状态。
  • 本质:阻塞和非阻塞本质上是本地系统对socket的不同处理方式,并不影响socket链接,也不会影响通信对方,通信双方可以自由选择阻塞还是非阻塞,例如:客户端设置成阻塞,服务器端accept 后可以设置成非阻塞都是可以的。
  • 非阻塞是阻塞方式的改进方案,在大部分情况下可以获得更好的性能。

阻塞模式下什么情况下会阻塞

  • 不管是TCP还是UDP,accept,connect,send,recv等操作都可以分类为发送数据和接收数据,connect和accept本质上也是发送和接收数据。
  • 对于接收数据,当然需要对方有发送数据,自己能接收到数据,不然就会阻塞。
  • 对于发送数据,数据的发送是由系统管理的,应用层操作只是将数据写入内存缓冲区,因此大部分情况下是不阻塞的,只有当缓冲区满,才会阻塞,(缓冲区不足以保存当前请求发送的数据,不确定是否会阻塞,还是只拷贝内存空闲大小数据)。

阻塞可能导致的问题

  • 阻塞会导致线程挂起,如果是单线程处理,其它操作会被中断,得不到响应。
  • 一直阻塞会导致程序无法使用,例如:如果对端未发送数据,接收端会一直阻塞在recv函数,导致接收端也无法发送数据了,除非使用多线程处理。

阻塞的改进方法

设置超时时间

  • socket支持设置选项:
  1. SO_RCVTIMEO :接收超时时间
  2. SO_SNDTIMEO :发送超时时间
  • 这两个选项对send, sendmsg, recv, recvmsg, accept, connect等都有效,特别注意对accept 和connect同样有效。
  • 这两个选项设置后,若执行超时,函数返回-1,并设置errno为EAGAIN或EWOULDBLOCK;如果是connect超时,返回-1,但errno设置为EINPROGRESS。
  • connect超时: 读Linux内核源码的时候偶然发现其connect的超时参数竟然和用SO_SNDTIMO操作的参数一致,如下:
File: net/ipv4/af_inet.c
 
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
    /* Error code is set above */
    if (!timeo || !inet_wait_for_connect(sk, timeo))
        goto out;
    err = sock_intr_errno(timeo);
    if (signal_pending(current))
        goto out;
}

非阻塞

  • 设置超时时间虽然可以解决阻塞导致的问题,但是需要占用一定的时长,并且时间并不好设置,时间设置过小,容易导致操作中止,设置过长又没太大意义;因此系统实现了非阻塞方式,配合异步编程,效率得到了很大的提升。
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值