网络原理(2)——TCP协议(传输层)

本文详细介绍了TCP协议的结构,包括TCP段格式、确认应答的机制以及超时重传策略,以确保可靠传输。讨论了网络通信中可能出现的问题和TCP如何对抗丢包,以及在直播应用中的实际意义。
摘要由CSDN通过智能技术生成

目录

一、TCP协议段格式

二、确认应答

三、超时重传


        TCP全称为:"传输控制协议 Transmission Control Protocol)"。协议如其名,要对数据的传输进行一个详细的控制。

一、TCP协议段格式

        

源 / 目的端口号:表示数据从哪个进程来,到哪个进程去。

32位序号 / 32位确认序号:后面详细讲。

4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个四字节);

        注意:4个bit位:1111 =》15,此处这里的单位是:4字节,而不是:字节。所以TCP头部最大长度为:15 * 4 = 60

保留(6位):TCP 在设定报头的时候,会提前准备几个 保留位(现在虽然用不到,但是可以先占个位置),后面一旦需要用了,咱们就会把这些保留位给使用起来。后续一旦需要扩展功能,使用保留位就可以实现,就可以避免 TCP 的扩展引起不兼容的问题。(而UDP协议,长度受到 2 个字节的限制,想要进行扩展,发现扩展不了,一旦改变这里的报头长度,就会使机器发送的UDP数据报和其他机器不兼容,无擦通信)

6位标志位(TCP的核心部分,后面也会讲到) :

        URG:紧急指针是否有效;

        ACK:确认号是否有效;

        PSH:提示接收端应用程序立刻从TCP缓冲区把数据读走;

        RST:对方要求重新建立连接;我们把携带RST标识的称为复位报文段;

        SYN:请求建立连接;我们把携带SYN标识的称为同步报文段;

        FIN:通知对方,本端要关闭了,我们称携带FIN标识的为结束报文段;

16位窗口大小:后面再说。

16位校验和:类似于UDP校验和,但是把报头和数据载荷放在一起计算校验和.、。

16位紧急指针:标识哪部分数据是紧急数据。

选项:TCP 报头中的前20个字节是固定长度的,后面这里包含了 “选项”(optional)部分(“可选的” / “可有可无的”),选项部分可以有,也可以没有,可以有一个,也可以有多个。


        以下是TCP协议的特性

二、确认应答

        我们知道,TCP协议具有可靠传输的特点,而这一特点也是 TCP 安身立命的本钱,初心就是解决 “可靠传输” 问题。

        而网络通信过程中很复杂,无法确保发送方发出去的数据,100% 能够到达接收方;此处的“可靠性”,也只能 “退而求其次”。只要尽可能的去进行发送了,发送方能够知道:对方是否收到,就人为是 可靠传输 了。

        用来确保可靠性,最核心的机制,称为 “确认应答”。

        在网络中,发送数据可能会出现 “后发先至”的情况,为什么呢?一个数据包从发送方到接收方传输过程中,走的路径可能不一样。第一个数据包,走路线一,第二个数据包,走路线二,有可能路线二非常畅通,路线一堵车了,就导致,第二个数据报虽然发的迟,但是能先到,这就是后发先至的情况。

        解决方案:引入了序号和确认序号对于数据进行编号,应答报文里就告诉发送方说,我这次应答的是哪个数据。给第一个数据包进行编号1(序号),第二个数据包进行编号2(序号),接收方收到一条数据就进行确认序号,如果确认序号为1和序号1匹配上了,就接收数据,不会出现后发先至的情况。

        真实的 TCP 的情况要更复杂一些,TCP 是面向字节流,以字节为单位进行传输的,描述按一条、两条的概念进行传输。实际上,TCP的序号和确认序号都是以字节来进行编号的,如图:

        同时,接收方也希望应用程序读到的数据是顺序正确的,顺序不对,对于接收方应用程序的逻辑肯定也会有一些影响,所以会有一个接收缓冲器,可以认为是一个 “优先级队列”,作为优先级的参考。

        在TCP报头中,报头里的序号只能存一个假设载荷有 1000 个字节,就有 1000 个序号,由于序号是连续的,只需要在报头中保存第一个字节序号即可,后续字节的序号都是很容易计算得到的。

        确保TCP可靠性的最核心机制:TCP的确认应答

        确认应答中,通过应答报文来反馈给发送方,表示当前的数据正确收到了应答报文,也叫ack报文,acknowledge的缩写)


三、超时重传

——确认应答的补充

        发送数据的时候如果一切顺利,通过应答报文就可以告诉发送方,当前数据是不是收到了。但是网络可能存在 “丢包” 的情况,如果数据包丢了,没有到达对方那,对方自然也没 ack 报文了,这个情况下,就需要 超时重传 TCP可靠性就是在对抗丢包,期望在丢包客观存在的背景下,也能够尽可能的传过去)。

        为啥会出现 “丢包” 的情况?这个网络的 路由器 / 交换机,不仅仅是给你这一次通信提供服务的,还要能支持千千万万的主机之间的同期;在整个网络中,就可能某个 路由器 / 交换机 ,在某个时刻,突然负载量很高(短时间内可能有大量的数据包要经过这个设备转发);但是要知道,一台设备能够处理的数据是有限的!!很可能瞬间的高负载超出了这个设备能转发的数据量的极限,此时多出来的部分,就无了,就被设备 “丢包” 了丢包情况客观存在,啥时候会丢包,难以预测)。

        超时重传就要解决丢包的问题,情景如下:发送方发了个数据之后,要等,等的时间里,收到ack报文(数据报在网络上传输,需要时间),如果等好久,ack还没等到,此时发送发就认为:数据的传输出现丢包了,当认为丢包之后,就会把刚才的数据包再传输一次(重传),等待的过程有一个时间的阈值(上限),就是  超时

如上图,主机A发送数据给主机B,在规定时间内,B没有收到数据,也就不会发送ack报文给主机A,这时,主机A 就会重新发送数据给 主机B。

        上面的过程中,是认为没有收到 ack报文 就是丢包,其实这样的结论是有点小问题的;丢包,不一定是发的数据丢了,也可能是 ack报文 丢了。(数据丢了,还是 ack 丢了,从发送方角度来看,就区分不了,但都是发送方没接收到 ack)。

上图是 ack报文 丢了,但数据是实实在在的传输到主机B了,但这种情况还要进行重传吗?答案肯定是不行的,试想一下:发送的请求如果是扣款请求呢?那这样就扣了双份的钱,这就不符合逻辑的,问题也很严重。

所以如上图所示,数据传过来还要返回给主机A确认应答,只要接收方没有收到 ack,就会把发送过来的数据丢包,然后主机A 再次发送数据给主机B,知道主机B确认应答,发送ack给主机A了。

那接收方如何判断接收到的数据是重复的呢?

        TCP socket 在内核中存在接收缓冲区(一块内存空间),发送方发来的数据,是要先放到接收缓冲区中的,然后应用程序调用 read / scanner.next 才能读到数据。(这里的读操作其实是读接收缓冲区)。

        

        如图:当数据到达接收缓冲区的时候,接受方首先会先预判一下,看当前缓冲区中是否已经有这个数据了(或者这个数据曾经在接收缓冲区中存在过)。

        如果已经存在或者存在过,就会直接把重复发来的数据丢弃掉,就能确保应用程序,调用 read / scanner.next 的时候,不会出现重复数据了。(毕竟当前是靠应用程序来进行“扣款”)

上面是判断数据是否存在过,接收方如何判断数据是否是 “重复数据”?

——核心判断依据:数据的序号

        1、数据还在接受缓冲区里,还没被read走,此时,就拿着新收到的数据的序号,和缓冲区里的所有数据的序号对比一下看看有没有一样的,有一样的就是有重复了,就可以把新收到的数据丢弃了。

        2、数据在接收缓冲区中,已经被应用程序read走了,此时新来的数据序号直接无法再接受缓冲区查找,注意:应用程序读取数据的时候,是按照序号的先后顺序,连续读取的。

先读 1~1000        1001~2000        2001~3000

        一定是先读序号小的数据,后读序号大的数据的(可以把接收缓冲区这个队列想象成带有优先级的阻塞队列)。

        此时 socket api 中就可以记录上次读的最后一个字节序号是多少比如上次读的最后一个字节的序号是 3000,新收到的一个数据包的序号是 1001,这个 1001 一定是之前已经读过的了。这个时候同样可以把这个新的数据包判定为 “重复的包” 直接丢弃。

        上述谈到的 ack、重传、保证顺序、自动去重,都是 TCP 内置的我们使用 TCP 的api 的时候,只需调用一个简单的代码:outputStream.write() ,上述功能就能都自动生效了,我们程序员需要操心的就少多了。但如果使用 UDP,上述这些问题就都得好好考虑了

超时重传的时间阈值:

        超时是会重传,重传也不是无限的重传,重传的过程也是有一定的策略的,如下:

        1、重传次数是有上限的。重传到一定程度,还没有 ack ,就尝试重置连接,如果重置连接后,传输数据还是失败,就直接放弃。

        2、重传的超时时间阈值也不是固定不变的,随着重传次数的增加,而增大(重传频率越来越低)。

        经历了重传之后还是丢包,大概率是网络出现严重问题了。再怎么重传,也是白费劲,重传还有啥要重传,但是可以省点力气,少传两次。

举个例子:

        假设一次网络通信过程中,丢包的概率是 10%(这个数字其实已经非常夸张了,实际使用网络过程中,如果出现这种情况,这就是非常严重的故障)。

        那么顺利到达的概率是 90%进行重传一次的概率:10% * 10% = 1%两次传输包至少有一次能到达的概率:99%随着重传次数的增加,包到达对方的概率也会大大增加。

        如果这时候连续重传3、4次还丢包,只能说明当前丢包的概率太大了,远远不止 10%,这个时候意味着网络已经出现非常严重的故障了,再重传也意义不大,所以干脆就让它少传几次,省点力气(因为路都断了,再想从这个路上通过,势必就非常难了)。

        例如直播app,直播的延迟,网络传输的的过程中就会有丢包现象,才有直播延迟这一现象,但也因为延迟,可以给程序留有更多的 “重传时间”


都看到这了,点个赞再走吧,谢谢谢谢谢

  • 38
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

tao滔不绝

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

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

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

打赏作者

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

抵扣说明:

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

余额充值