【网络编程实践】2.1.3 阻塞IO下的 echo实验

本文通过一个echo服务端与客户端的阻塞IO实验,阐述了在TCP协议中,当接收端处理速度慢于发送端时,可能导致双方的send函数阻塞。实验显示,当接收缓冲区接近满载时,新的数据无法被接收,发送缓冲区也随之填满,从而造成客户端的send阻塞。解决办法是在应用层协议设计时,预知数据大小并合理分配缓冲区。此外,介绍了查看TCP缓冲区大小的系统文件,并提出了优化建议。
摘要由CSDN通过智能技术生成

下面使用 echo.cc、echo_client.cc 演示一个阻塞IO实验。

实验在发送 20M 数据时,程序发生了阻塞。
在这里插入图片描述
在执行 netstat 命令后可以看到它们各自的收发队列的情况.。

其主要原因在于:当接收端(echo服务端)不接收数据,或者处理速率比发送方的发送速率低导致其接收缓冲区已满(接收窗口win=0),进而导致数据发送方的发送缓冲区的数据不断堆积进而缓冲区满,此时调用send()将阻塞等待(send等待发送缓冲区有空间,系统在等待对端接收缓冲区有空间以便将发送缓冲区的数据通过网卡发到网络)。

TCP协议的原理 引用:TCP Send函数的阻塞和非阻塞,以及TCP发送数据的异常情况

  1. 每个Tcp socket连接在内核(kernal space)中都有一个发送缓冲区和接收缓冲区)

阻塞模式与非阻塞模式:

  1. 阻塞模式下, send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送就返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;否则,send会等待接收端对之前发送数据的确认,以便腾出缓存空间容纳新的待发送数据,再返回(接收端协议栈只要将数据收到接收缓存中,就会确认,并不一定要等待应用程序调用recv),如果一直没有空间能容纳待发送的数据,则一直阻塞;
  2. 在非阻塞模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区而已,如果缓存区可用空间不够,则尽能力的拷贝,立即返回成功拷贝的大小;如缓存区可用空间为0,则返回-1,同时设置errno为EAGAIN.

ocket缓冲区 引用:谈谈socket缓冲区

  1. socket缓冲区在每个套接字中单独存在;
  2. socket缓冲区在创建套接字时自动生成;
  3. 即使关闭套接字也会继续传送发送缓冲区中遗留的数据;
  4. 关闭套接字将丢失接收缓冲区中的数据

在阻塞IO中,send()调用时,如果发送缓冲区没有足够的空间容纳数据,就会发生阻塞。而恰恰服务段(echo)与客户端(echo_client)都处于这样一种发送阻塞的状态。
在这里插入图片描述

而以上过程发生阻塞的具体过程为:

  • C(客户端):客户端send() 大量数据堆积在发送缓冲区,而对端没有及时的读取导致数据堆积,致使发送缓冲区可用空间不足,send() 发生阻塞。
  • S(服务端):服务端recv() 之后立刻发送数据到对端,但由于对端流程处于send()阻塞状态 ,无法及时recv(),导致服务端也阻塞在 send() 处。

这里我们看以查看一下tcp默认的缓冲区打下。
/proc/sys/net/ipv4/目录下有三个tcp缓冲区配置文件 tcp_mem tcp_wmem tcp_rmem
在这里插入图片描述
这里tcp默认的接收缓冲区为 6M 左右,因此在 echo 的接收缓冲区接近这个阈值时,再来数据就不收了。而由于服务端没有及时处理接收缓冲区的消息,使得客户端的发送缓冲区也满了。因此,客户端就阻塞在send()不再发送数据了。

在echo程序的设计上,服务端每次读4K数据,就向客户端发送一次消息,而客户端是一次发送完所有消息后,才接收服务端的消息。导致服务端向客户端发送的消息,没有及时的读取。

从程序的设计考虑,客户端发送一个20MB的数据是合法的,而服务端预先不知客户端请求数据的大小,采用了读取4K就响应一次的方式,最后导致的阻塞。因此我们在设计应用层协议时,应采取客户端先发送一个 header,告诉客户端请求的大小,然后服务端这边收到 header 后,准备一个符合请求大小的buffer,准备接收请求。然后客户端再发送请求至服务端,服务端这边接收到请求后,计算出一个响应,再按照相同的方式发送回客户端。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫RT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值