网络协议-TCP

TCP协议头

在这里插入图片描述

序号生成规则:

ISN = M + F (localhost, localport, remotehost, remoteport)
M是一个整数,每隔4ms会加1,F一般是HASH函数。

首部长度

因为选项字段是变长的,需要告知对端TCP头的长度是多少。

常用的6个标志位:

• URG 紧急指针( urgent pointer)有效,配合紧急指针使用
• ACK 确认序号有效。
• PSH 接收方应该尽快将这个报文段交给应用层。
• RST 重建连接。
• SYN 同步序号用来发起一个连接。
• FIN 发端完成发送任务。

URG和PUSH的区别:
URG:通过紧急指针告诉接收端该报文中前多少位是紧急数据,该部分数据不存入接收端缓冲区Buffer,直接上送给上层应用,特别的情况是当通告窗口为0时,发送端依然可以发送紧急数据。
PSH:告知接收端将该报文以及当前缓冲区内的数据都尽快上报给应用层,窗口为0时不能发送。

在报文中,不会出现下面不合法的标志位:

  1. 所有标志位都为0。
  2. SYN和FIN同时被置1。
  3. SYN和RST同时被置1。
  4. FIN和RST同时被置1。
  5. FIN位被置1,但ACK位没有被置1。
  6. PSH位被置1,但ACK位没有被置1。
  7. URG位被置1,但ACK位没有被置1。

TCP选项在这里插入图片描述

EOP:告知选项结束

NOP:没有特殊含义,一般用于将TCP选项的总长度填充为4字节的整数倍。

MSS:TCP连接初始化时,通信双方使用该选项来协商最大报文段长度,防止IP分片。每一方都有用于通告它期望接收的MSS选项(MSS选项只能出现在SYN报文段中)。如果一方不接收来自另一方的MSS值,则MSS就定为默认值536字节(这个默认值允许2 0字节的IP首部和2 0字节的TCP首部以适合576字节IP数据报)。计算方法如下:
在这里插入图片描述
WSOPT:TCP连接初始化时,通信双方使用该选项来协商接收通告窗口的扩大因子,只能出现在同步报文段中,否则将被忽略。取值范围是0-14,由于默认窗口大小为16位,最大只能传输65535字节的数据,实际接收方能接收的字节数远大于65535,会出现如下情况,A、B均处于等待状态,65535字节的数据在网络中传输。
在这里插入图片描述
通过窗口扩大选项,可将窗口大小通知为256K,可以充分利用网络及A、B两边的缓冲区,如下图所示:
在这里插入图片描述
SACK-permitted:如果某个TCP报文段丢失,则TCP模块会重传最后被确认的TCP报文段后续的所有报文段,原先已经正确传输的TCP报文段也可能重复发送,降低了TCP性能,SACK技术使TCP模块只重新发送丢失的TCP报文段,不用发送所有未被确认的TCP报文段。通过修改/proc/sys/net/ipv4/tcp_sack内核变量来启用或关闭选择性确认选项。

SACK:该选项的参数告诉发送方本端已经收到并缓存的不连续的数据块,从而让发送端可以据此检查并重发丢失的数据块。因为一个块信息占用8字节,所以TCP头部选项中实际上最多可以包含4个这样的不连续数据块(考虑选项类型和长度占用的2字节)。
在这里插入图片描述
图片来源于网络

TSPOT:时间戳选项。该选项提供了较为准确的计算通信双方之间的回路时间(Round Trip Time,RTT)的方法和解决了编号回绕问题。可以通过修改/proc/sys/net/ipv4/tcp_timestamps内核变量来启用或关闭时间戳选项。

连接建立

又叫三次握手,通过三次握手,指定发送方和接收方收报文和发报文均没有没问题,在三次握手过程中会协商序号以及选项的支持情况。

发送端:发送端发送syn报文后,处于syn-sent状态,等待接收端返回ack,以及syn报文,然后再发送ack响应报文,处于established状态。

接收端:先启动监听,处于listen状态,等待发送端发送连接请求,收到连接请求后,向发送端发送ack、syn报文,处于syn-rcvd状态,待发送端发送ack后建立连接,处于established状态。

发送端和接收端的状态情况如下所示:
在这里插入图片描述

连接断开

又叫四次分手,当接收端收到fin报文时,也正好想断开连接,会将ack报文和fin报文一起发送,此时会是三次分手。

接收端:在接收端收到断开连接请求后,会直接向发送端发送ack报文,然后处于closed-wait状态,待上层应用处理完成后欲断开连接时,会向发送端发送fin报文,同时处于last-ack状态,等待发送端回ack报文,如果在超时时间内没有收到ack,会向发送端再发送一次fin报文。

发送端:向接收端发送fin报文,然后处于fin-wait-1 状态,等待接收端返回的ack报文,待收到接收端发送过来的ack报文后处于fin-wait-2状态,收到接收端发送过来的fin报文后,再想接收端发送ack报文,此时处于time-wait状态,最大等待时长一般为2倍的MSL(Maximum Segment Lifetime,最长报文生存时间),用于当出现ack丢包时,还能收到接收端超时重发的fin报文。当发现设备上time-wait状态的连接过多时,一般就要检查是否是存在短连接的反复的连接和断开。

发送端和接收端的状态情况如下所示:
在这里插入图片描述
将建立连接和断开连接放在一起,就是下面这个很经典的TCP状态机。
在这里插入图片描述
其中:

  • 粗线是主要流程,细线为非主要流程
  • 实线为发送端流程,虚线为接收端流程
  • 数字序号为连接建立流程
  • 中文序号为连接断开流程

如何成为一个靠谱的协议

TCP通过解决如下5个问题,尽可能的成为一个靠谱的协议

  • 顺序问题
  • 丢包问题
  • 连接维护
  • 流量控制
  • 拥塞控制

下面一起看看TCP通过哪些机制解决上面5个问题

报文确认机制

单独确认
将收到的报文一个ID一个ID的确认
累计确认
应答某个 ID,表示该ID之前的所有报文都收到了
SACK
TCP选项中已经描述

Advertised window 通告窗口

指的是接收端向发送端回应的窗口大小
发送端
在这里插入图片描述

  • 整个加粗黑框内为通告窗口的大小
  • LastByteAcked之前的为已经发送且已经收到ack确认的报文
  • LastByteSent之前为已经发送但未收到ack的报文

接收端
在这里插入图片描述

  • MaxRcvBuffer:接收端最大缓存的量
  • LastByteRead 之后是已经接收且回了ack,但是还没被应用层读取的报文
  • NextByteExpected之后为还没有回ack的报文
  • AdvertisedWindow=MaxRcvBuffer-(NextByteExpected-LastByteRead)

还可能出现下面这种情况:

发送端一直在发送报文,接收到的窗口大小一直在减小,一直减小到LastByteAcked和 LastByteSent在一个位置,即窗口大小为0了。如下图所示:
在这里插入图片描述
接收端一直在接收报文,但是上层应用一直不读取缓冲区数据,慢慢的缓冲区满了,就会通知发送端当前窗口大小为0。
在这里插入图片描述
当出现窗口大小为0时,发送方会定时发送窗口探测数据包,看是否有机会调整窗口的大小。当接收方比较慢的时候,要防止低能窗口综合征(空出一个字节来就赶快告诉发送方,然后马上又填满了,依次反复,浪费网络资源,以及发送端和接收端系统资源-组装与解析报文),可以当窗口太小的时候,不更新窗口,直到达到一定大小,或者缓冲区一半为空,才更新窗口。

Sliding Window 滑动窗口

下面这个图比较简明的介绍了滑动窗口机制,注意告知的rwnd大小包含已经收到但未向发送端回ack的报文。
在这里插入图片描述

重传机制

超时重试:对每一个发送了,但是没有 ACK 的包,都有设一个定时器,超过了一定的时间,就重新尝试,该时间要大于往返时延RTT(Round-Trip Time),TCP 通过采样 RTT 的时间,然后进行加权平均,算出一个值,不断变化的,重传时间是不断变化的,我们称为自适应重传算法(Adaptive Retransmission Algorithm)。
假设5、6、7 都超时了,就会重新发送。接收方发现 5 原来接收过,于是丢弃 5;6 收到了,发送 ACK,要求下一个是 7,7 不幸又丢了。当 7 再次超时的时候,有需要重传的时候,TCP 的策略是超时间隔加倍。每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。

快速重传:当接收方收到一个序号大于下一个所期望的报文段时,就检测到了数据流中的一个间格,每收到一个这样的报文,就会发送一起期望的ack,当连续发送三个冗余的 ACK,客户端收到后,就在定时器过期之前,重传丢失的报文段。
假设接收方发现 6、8、9 都已经接收了,就是 7 没来,那肯定是丢了,于是发送三个 6 的 ACK,要求下一个是 7。客户端收到 3 个,就会发现 7 的确又丢了,不会等待定时器超时,马上重发7号报文。

拥塞控制

发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。滑动窗口 的rwnd (接收窗口)是怕发送方把接收方缓存塞满,而拥塞窗口 cwnd,是怕把网络塞满。拥塞窗口和滑动窗口共同控制发送的速度。发送端通过下面公司控制发送报文数量。
LastByteSent - LastByteAcked <= min {cwnd, rwnd}
理想的情况是下面这种情况,发送报文和接收报文正好使网络占用率最高。
在这里插入图片描述

丢包恢复机制

一条 TCP 连接开始,cwnd 设置为一个报文段,一次只能发送一个;当收到这一个确认的时候,cwnd 加一,于是一次能够发送两个;当这两个的确认到来的时候,每个确认 cwnd 加一,两个确认 cwnd 加二,于是一次能够发送四个;当这四个的确认到来的时候,每个确认 cwnd 加一,四个确认 cwnd 加四,于是一次能够发送八个,(一直发送到慢启动门限ssthresh(大部分是65535)个时),每收到一个确认后,cwnd 增加 1/cwnd,我们接着上面的过程来,一次发送八个,当八个确认到来的时候,每个确认增加 1/8,八个确认一共 cwnd 增加 1,于是一次能够发送九个,变成了线性增长。

慢启动:sshresh 设为 cwnd/2,将 cwnd 设为 1,容易造成网络卡顿

快速恢复:当接收端发现丢了一个中间包的时候,发送三次前一个包的 ACK,于是发送端就会快速的重传,不必等待超时再重传。TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,cwnd 减半为 cwnd/2,然后 sshthresh = cwnd,当三个包返回的时候,cwnd = sshthresh + 3

两种情况对比如下所示:
在这里插入图片描述

TCP BBR(Bottleneck Bandwidth and Round-trip propagation time)

当前TCP协议处理丢包存在的问题。
问题一:是丢包并不代表着通道满了,也可能是管子本来就漏水。例如公网上带宽不满也会丢包,这个时候就认为拥塞了。
问题二:TCP 的拥塞控制要等到将中间设备都填充满了,才发生丢包,从而降低速度,这时候已经晚了。其实 TCP 只要填满管道就可以了,不应该接着填,直到连缓存也填满。

解决问题:充分利用带宽;降低buffer占用率。

主要为下面3个步骤:
S1:慢启动开始时,以前期的延迟时间为延迟最小值Tmin。然后监控延迟值是否达到Tmin的n倍,达到这个阀值后,判断带宽已经消耗尽且使用了一定的缓存,进入排空阶段。
S2:指数降低发送速率,直至延迟不再降低。这个过程的原理同S1
S3:协议进入稳定运行状态。交替探测带宽和延迟,且大多数时间下都处于带宽探测阶段。

三种情况对比如下所示:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值