首页 > 其他分享 >深入理解协议栈的内部结构——收发和断开

深入理解协议栈的内部结构——收发和断开

时间:2024-06-23 15:00:12浏览次数:26  
标签:断开 ACK 应用程序 发送 收发 内部结构 接收 数据 服务端

1.上期问题的答案

如果客户端connect操作时,服务端对应的端口号不接受连接,在这种情况下不会设置SYN的值,而是会把RST比特设为1

2.本期主题

上一期讲解了在TCP下协议栈的socket操作和connect操作,那么本期我们会讲解TCP协议栈的write操作,read操作和close操作。

3.网络包的大小

3.1 包太小怎么办
3.1.1 MTU和MSS

在控制流程从connect回到应用程序后,应用程序会调用write操作把要发送的数据交给协议栈,并且应用程序还会把要发送数据的长度也一并告诉协议栈。协议栈在收到数据后并不会马上发送出去,而是会把数据放在内部的发送缓冲区中,并等待应用程序的下一段数据。因为如果应用程序发送的是逐行的数据,甚至发送一个个字节,那么如果协议栈一接收到数据就发送出去,那么会发送大量的小包,这会降低网络的效率。因此协议栈要判断是否可以发送数据。

第一个判断依据就是MTU,即一个网络包的最大长度,它包含了头部的总长度。如果要得到网络包中所能容纳的最大数据长度,即MSS,也就是要减去头部的总长度。那么协议栈在发送数据时,如果数据长度一直很接近MSS的值,那么就可以避免发送小包的问题了。

3.1.2 时间

还有一个依据是时间。如果应用程序发送的数据本来就很小,那么如果一直没有达到接近MSS的长度,协议栈就会一直陷入等待,这会造成发送延迟。因此,协议栈内部有一个计时器,在一定的时间里,就算网络包的数据没有达到MSS的大小,它还是会把数据发送出去。

这两个条件是相互矛盾的,因此协议栈的开发者会自己来定一个值来保持平衡,不同种类和版本的操作系统也就会有些差异。

3.2 包太大怎么办

如果HTTP请求的消息太大,长度已经超过了一个网络包可以容纳的最大长度,那么发送缓冲区的数据会被以MSS的长度分成若干个网络包,然后根据套接字中记录的控制信息所对应的IP地址和端口号,然后交给IP模块来发送数据。

4.确认网络包收到

在接收方收到发送方发送的数据后,需要进行确认操作,来告诉发送方已经成功接收到数据。在发送方发送数据时,发送方会把发送数据的长度,和所对应的序号一起告诉接收方。就比如发送方和接收方说:我现在要发送从xxx开始的数据,一共有xxx字节。如果接收方上次接收到第1000字节,如果发送方发送了从1001开始的包,那么说明没有遗漏,那么发送方会把序号加上数据的总长度再加上1,这个值就储存在ACK号中。就相当于对发送方说:xxx前的数据我已经收到了。

然后在收发数据阶段,序号的起始值不是1,而是一个随机的数。这样做的目的是为了防止被有心之人抓到机会发动进攻。而随机出来的序号会在执行连接操作的时候一并发送给通信对象。

上面讲到的操作是单向操作的时候要做的事,那如果是双向操作呢?其实很简单,在连接阶段客户端会先发起连接并把序号初始值告诉服务端,服务端在接收到数据后会返回ACK号,并把自己的序号初始值告诉客户端。客户端在收到服务端发来的数据后也会生成ACK号并返回给服务端。之后收发数据,客户端和服务端各发各的,在收到数据后也会根据对方的序号和长度发送对应的ACK号。

5.TCP通信的补救措施

在收到接收方发回的ACK号之前,发送方发送的数据会保存在发送缓存区中。这是为了防止如果接收方没有收到对应的数据,发送方可以重新发送这种包。这样一来,无论什么错误,如果数据丢失,发送方会重新发送包。如果数据出现错误,接收方会丢弃这些包,并等待发送方重新发送包。但是如果发送方在发送几次数据后仍然无效,那么发送方会强制结束通信,并向应用程序报错。

5.1 ACK号的等待时间

那么发送方等待ACK号的等待时间要设置成多久呢?如果ACK号的等待时间太短,在接收方的ACK号到达之前再一次发送相同的包,那势必会造成网络的拥堵。如果ACK号的等待时间太长,那么如果真的出现了错误,网络包的重传就要经过很久。

因此ACK号的等待时间会被动态调整,如果ACK号的返回很快会缩短等待时间,反之,ACK号的返回时间很慢会延长等待时间。虽然说缩短等待时间,但是这个值是有最小值的,一般在0.5秒到1秒之间。

5.2 滑动窗口

如果每次发送一次数据,就等待对应的ACK号返回,这样的效率其实是很低的。因此协议栈在发送数据的时候会使用滑动窗口来管理发送数据和ACK号。在发送一个网络包后,不会等待ACK号返回,而是继续发送之后的包。

但是这样又引出了别的问题,如果数据一股脑全部发送给接收方,接收方来不及处理,那就只能丢弃新发送过来的包了,这种浪费肯定也是不允许的。

接收方收到包后,会把数据存到接收缓存区中。然后接收方要计算ACK号,然后把数据还原再交给应用程序。因此如果发送方一直发送数据的话,接收方的缓存区是有可能溢出的。因此在连接阶段,接收方其实也会把自己接受缓存区的大小告诉发送方,发送方在每次发送完数据后都会计算接收方还有多少缓存区,如果要溢出了,那么就会更改发送包的速率。如果缓存区越来越多,说明接收方处理数据的速度很快,那么发送方也会提升发送包的速率。

接收方也会一直处理数据,所以在返回ACK值的时候,接收方也会把现在缓存区的大小告诉发送方,好让发送方调整发送数据的策略。这就是TCP调优参数中非常有名的一个。

5.3 ACK与滑动窗口

那么ACK和滑动窗口不可能一直保持同步出现,如果先计算完ACK准备发送,或者先处理好数据并把准备把剩余的缓存区的大小告诉发送方。那么一方一定会等待另一方,比如在发送缓存区还有3000字节的消息的时候,其实最新的消息是缓存区还有5000字节,那不是会影响滑动窗口吗?

TCP做了这样一个优化,如果在计算滑动窗口的时候,ACK号更新了两次,如果ACK号是连续的,那么就可以直接发送那个最新的ACK号。滑动窗口也是一样的,发送最新的缓存区的大小给发送方就可以了。

5.4 接收响应消息

浏览器在发送请求消息之后,会调用read程序来获取响应的消息。协议栈会从接受数据的缓冲区中取出数据,如果里面有数据的话就会直接给浏览器。如果没有数据,协议栈会把这个read操作挂起等到之后再执行。

6.断开连接

在发送方发送完数据后,应用程序会调用close程序,我们假设现在是服务端发送完数据调用了close程序。服务端的协议栈会生成控制位中FIN比特为1的TCP头部,服务端的套接字会记录下断开操作的相关消息。客户端接受到服务端的断开操作消息后,会将自己的套接字标记为断开操作状态,然后客户端会返回ACK号给服务端,之后协议栈就可以等待应用程序来取数据。

应用程序调用read来读取数据,如果有已经被应用程序接受部分的数据,这些数据会被传递给应用程序。否则会告知应用程序数据已经全部结束了。在收到了服务端的所有数据后,客户端也会调用close并发送一个FIN比特为1的包,收到服务端的ACK号后,服务端和客户端的通信就结束了。

7.删除套接字

在和服务端发送FIN比特为1的包后,客户端不会立刻删除套接字。这是因为如果这个FIN比特为1的包如果没有发送到服务端,那么客户端还要进行重发。如果这个时候已经没有套接字了,而这个时候又创建了一个新的套接字,端口号正好就是刚刚删除的那个端口号,那么重发的包就会发送给这个刚刚创建的那个套接字。因此套接字一般会等待几分钟再删除,如果重传了几次依然没有响应,就会停止重传。

8.下期预告

本章就不出思考题了,因为协议栈的内部结构的部分比较多,我分成了上下两部分,因此我在下一期会带大家把创建套接字,连接,收发数据,断开连接这部分内容,从头到尾的串起来讲一遍。

往期内容

用通俗易懂的话理解HTTP

DNS与IP地址的那些事


协议栈发送数据


深入理解协议栈的内部结构——创建和连接
 

标签:断开,ACK,应用程序,发送,收发,内部结构,接收,数据,服务端
From: https://blog.csdn.net/2301_77664120/article/details/139898953

相关文章

  • 射频收发记录仪
    射频收发记录仪收发信号频率范围75MHz~6GHz支持2KHz~200MHz不同带宽的信号实时记录2GB/s持续流盘速率 基于RF-IC芯片的射频收发记录仪,提供双通道发射器和接收器、集成式频率合成器以及数字信号处理功能。广泛应用于卫星、雷达、导航、通信、遥测、对抗等多种环境下高速信号的......
  • 一文带你了解STM32F4中断的概念,串口的概念,DMA的转运,以及如何运用在串口的收发上,串口收
    本篇主要实现的是用UART的接收中断接收数据,用DMA接收不定长的数据并发送回给电脑,接收信息控制LED灯的亮灭,成为点灯大师。什么是中断(EXIT)EXIT 外部中断/事件控制器,管理了控制器的20个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下......
  • 对 websocket 进行封装 (心跳检测 断开重连 发送事件等等 支持断开重连后发送上次发
    代码封装:  //websocketService.jsimport{ref}from"vue";const{DEV,VITE_APP_PUSH_WS}=import.meta.env;const{push_ws}=window.WEB_CONFIG;constbaseWsUrl=DEV?VITE_APP_PUSH_WS:push_ws;classWebSocketService{constructor(ur......
  • 项目运维时,某用户通过RDP远程桌面连接服务器...任务管理器显示用户状态断开连接!记录运
    目录问题出现解决方式测试参考  今天处理项目运维问题,发现服务器任务管理器出现用户状态断开连接......问题出现项目运维时,某用户通过rdp远程桌面连接Windowsserver服务器时,出现服务器发布的进度计划无法执行,打开服务器任务管理界面出现用户状态断开连接标志,如下......
  • 串口收发UART(Verilog HDL)
    UART(UniversalAsynchronousReceiverTransmitter,通用异步收发器)是一种异步串行通信协议,主要用于计算机和嵌入式系统之间的数据交换。实现UART通信的接口规范和总线标准包括RS-232、RS449、RS423和RS485等,接口标准规定了通信标准的电气特性、传输速率、连接特性和机械特性。文......
  • MAX3160EAP 集成接口芯片 收发器 资料配置流程
    MAX3160EAP是一款集成电路(IC),它是一个全双工的RS-232/RS-485/422多协议收发器。这个器件可以通过编程来配置为不同的模式,包括两个RS-232接口或一个RS-485/422收发器。它具有许多高级特性,比如真正的安全接收器、保护传输和接收器不受线路故障的影响、低功耗待机模式以及能够在......
  • 提供高达 58 Gbps 的收发器速率、AGFA023R31C2E1VB/AGFA023R31C2I1V/AGFA023R31C2I2VB
    Agilex7FPGA产品系列包括业界最高性能的FPGA和SoC。英特尔Agilex7FPGA和SoC由高性能的F系列、I系列和M系列FPGA组成,为要求最高的应用提供了一系列的高级功能。•具有业界最高数据速率的收发器—高达116Gbps•业界首创的PCIExpress*(PCIe*)5.0和ComputeExpressLi......
  • STM32系列--串口收发+基本定时器
      if(myusart.reflag>0){Com_Handle();myusart.recount=0;myusart.reflag=0;}main #define_maxbuf100typedefstruct{u8myadd;u8......
  • udp的收发包的思考
      在测试radius性能时,想到一个问题,以前tcp报文在ip层处理时,涉及到路由查找,对于tcp协议报文;skb中没有路由缓存,没有关联的sock;且非分片报文;ip_early_demux设置为true;则调用early_demux函数提前在IP层做established状态的sock查找,并负责将sock结构体成员sk_rx_dst的路由缓存赋值......
  • xshell 自动断开连接的解决方法
    1.问题分析本文Xshell连接自动断开的原因是SSH配置文件的ClientAliveInterval字段设置的超时断开时间小于Xshell的检查断开连接时间。2.SSH配置文件中的字段详解在SSH配置文件/etc/ssh/sshd_config中加入以下配置ClientAliveInterval60#设置超时时间为60秒=>表......