TCP深入解析

TCP/IP深入剖析

在了解TCP/IP和UDP/IP之前,我个人认为大家应该先知道OSI七层网络模型的知识,可能科班出身的在大学学习过这些知识,我在这里也不深入了,简单介绍一下,就当为TCP/IP做一个铺垫.

OSI七层网络模型:

OSI(Open System Interconnect),即开放式系统互联。 一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互连模型。 ISO为了更好的使网络应用更为普及,推出了OSI参考模型。其含义就是推荐所有公司使用这个规范来控制网络。这样所有公司都有相同的规范,就能互联了。

  1. OSI七层网络模型指的是那七层呢?
    从上到下依次为应用层,表示层,会话层,传输层,网络层,数据链路层,物理层
  2. 那通常说的TCP/IP五层模型又是啥呢?
    其实只是参考OSI模型而已,说白了就是五层模型中把OSI的应用层,表示层以及会话层统称为了应用层,自然而然的五层模型就是指:应用层,传输层,网络层,数据链路层,物理层
    来一些图可能更好理解一点:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

每一层都代表什么呢?

应用层
OSI参考模型中最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务。我们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,POP3、SMTP等。

表示层
表示层提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。如果必要,该层可提供一种标准表示形式,用于将计算机内部的多种数据格式转换成通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的转换功能之一。
会话层
会话层就是负责建立、管理和终止表示层实体之间的通信会话。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。
传输层
传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。我们通常说的,TCP UDP就是在这一层。端口号既是这里的“端”。
网络层
本层通过IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是通常说的IP层。这一层就是我们经常说的IP协议层。IP协议是Internet的基础。
数据链路层
将比特组合成字节,再将字节组合成帧,使用链路层地址 (以太网使用MAC地址)来访问介质,并进行差错检测。 数据链路层又分为2个子层:逻辑链路控制子层(LLC)和媒体访问控制子层(MAC)。MAC子层处理CSMA/CD算法、数据出错校验、成帧等;LLC子层定义了一些字段使上次协议能共享数据链路层。 在实际使用中,LLC子层并非必需的。
物理层
实际最终信号的传输是通过物理层实现的。通过物理介质传输比特流。规定了电平、速度和电缆针脚。常用设备有(各种物理设备)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质。

TCP/IP通信原理

上边简单介绍了一下网络模型的概念,但是在传输层中的TCP是怎么通信的呢?我们都会知道三次握手和四次挥手,但是这两次交流到底是怎么回事呢?端到端又是如何传输的呢?传输的数据又是什么样子呢?
在讲解传输层通信之前,需要先介绍另一个东西,那就是报文段,报文段是指TCP/IP协议网络传输过程中,起着路由导航,查询各个网络路由网段,IP地址,交换协议等IP数据包。报文段充当整个TCP/IP协议数据包的导航路由功能.TCP提供的是一种面向连接的可靠的字节流服务,TCP提供可靠性的一种重要的方式就是MSS。通过MSS,应用数据被分割成TCP认为最适合发送的数据块,由TCP传递给IP的信息单位称为报文段或段(segment)。代表一个TCP socket的结构体struct tcp_sock中有多个成员用于确定应用数据被分割成最大为多大的数据块较为合适(最大报文段长度MSS)。跟最大报文段长度最为相关的一个参数是网络设备接口的MTU,以太网的MTU是1500,基本IP首部长度为20,TCP首部是20,所以MSS的值可达1460(MSS不包括协议首部,只包含应用数据)。咱们从外到内的扒一扒,心急吃不了热豆腐嘛!

用几张图来一层一层的扒,先研究下全身(报文段):

在这里插入图片描述

再看看脸(IP首部):

这里以IPV4来说,6不在讨论范围哈.
在这里插入图片描述
IP首部不包含上图中的数据部分,数据部分其实就是TCP的内容了,咱们一会再说,先说说IP首部,由上图可以看出来,IP首部包含有20个固定字节,也就是480个比特位,图是为了好识别才这么画的,其实从上到下你可以理解成连续的,只不过分了一下段而已,那下边我就从头到尾依次介绍一下他们具体是干什么的:
版本:
长度是4个比特位,指IP协议的版本。通信双方使用IP协议的版本必须一致,比如你使用的是IPV4这里就是4
首部长度
长度是4个比特位,顾名思义,这个字段就是标识了IP数据报的首部长度。该字段以4字节为单位,可以表示的最大的数是”1111”,也就是十进制数15,所以IP首部长度最大为60字节(15*4=60)。由于IP首部固定长度为20字节,所以该字段的最小值为”0101
区分服务
占8个比特位。有3位优先权字段已经弃用,还有4位TOS字段和1位保留字段(这个保留字段必须置为0)。4位TOS字段分别代表最小延时、最大吞吐量、最高可靠性、最低成本。这四者相互冲突,只能选择一个。
总长度
占16个比特位,表示IP数据报的总长度(包括数据部分)。单位为字节,所以数据报的最大长度为65536字节(2^16-1)。
在这里补充一个知识:最大传输单元MTU。表示某一层上面可以通过的最大的数据包的大小,所以IP数据报的总长度不能超过下面数据链路层的MTU值。
为了不使IP数据报的传输速率降低,规定所以主机和路由器必须能够处理的IP数据报长度不得小于576字节。当数据报长度超过网络所容许的最大传输单元时,就要把过长的数据报进程分片,这时数据报首部中的总长度不是指没有分片前的数据报长度,而是指分片后每一个分片数据报的长度。
标识
占16个比特位,IP软件在存储器中维持一个计数器,每产生一个数据报计数器就加一,并将这个值赋给标识字段。当数据报长度超过网络的MTU要进行分片时这个标识字段的值就会复制到所有的数据报片的标识字段中。为了之后重新组装数据的时候可以分辨哪些数据报之前属于一个数据报的。
标志
占3个比特位。标志虽然占了三位,但目前只有两位有意义
MF:在最低位,MF=1表示后面还有分片的数据报,MF=0表示这已经是所有数据报片中的最后一个了
DF:在中间的一位,DF=1表示不允许分片,DF=0表示允许分片
片偏移
占13个比特位。该字段表示,被分片的数据报,每一个数据报片在原分组的相对位置。也就是说相对于用户数据字段的起点该片从何处开始。
片偏移以8个字节为单位所以每个分片的长度一定是8字节的整数倍
生存时间
占8个比特位,这个字段也就是我们常说的TTL,表示数据报在网络中的寿命,目的是为了防止数据报在传送过程中无限制的在因特网中兜圈子而白白浪费网络资源。
TTL的单位是跳数,路由器在转发这个数据报之前就将该数据报的TTL减一,当数据报的TTL被减到0时,就丢弃这个数据报。
协议
占8个比特位。协议字段指出此数据报携带的是哪种协议,这样就可以使目的主机的网络层知道应该将数据部分上交给哪个传输层协议处理。
具体数值与协议的对应如下表:

协议名协议字段值
ICMP1
IGMP2
TCP6
EGP8
IGP9
UDP17
IPV641
OSPF89

首部检验和
占16个比特位,这个字段是为了帮助路由器检验收到的IP数据报中的比特错误。需要注意的是,这个字段只检验数据报的首部,不包括数据部分。数据报每经过一个路由器,路由器都要重新计算一下首部检验和。
来看看IP数据报是如何检验的:

  1. 在发送方,先把IP数据报首部划分为许多的16位字的序列,并把检验和字段置零。
  2. 在用反码算数运算把所有16位字相加后,将得到的和的反码写进检验和字段。
  3. 接收方收到数据报之后,将首部的所有16位字在使用反码算数运算相加一次,将得到的和取反码,即得出接收方检验和的计算结果。
  4. 我们根据接收方检验和结果判断,如果结果为0,表示此数据报有效,不为0就丢弃该数据报。

源IP地址
占32个比特位,表示发送方主机的IP地址
目的IP地址
占32个比特位,表示接收方主机的IP地址
可变部分
IP首部的可变部分就是一个选项字段。此字段长度可变,从1字节~40字节不等。最后用全0的填充字段补齐为4字节的整数倍
注:IPV6不在采用此字段
数据
数据字段就是要交付给目的地的传输层报文段(TCP/UDP等),也可以承载其他类型的数据(ICMP报文段等)

最后慢慢研究身材(IP数据部分):

IP数据部分其实就是TCP的报文了,也是咱们这里说的重点了,也就是IP首部介绍的时候的那个数据
老样子,先上图:
在这里插入图片描述
如果IP报文段首部的协议是TCP,那么自然IP数据部分也就是TCP的内容,如下:
在这里插入图片描述

1、源端口号
占16位,标识发送主机的端口或进程,一个TCP报文必须包含源端口号,要让接收主机知道该向哪发送确认报文
2、目的端口号
占16位,标识目的主机的端口或进程
3、序号
占32位,即4个字节。序号范围是0~(2^32-1), 当序号增加到2^32-1后,下一个序号又会变成0。因为TCP是面向字节流的,在一个TCP连接中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段则指的是本报文段所发送的数据的第一个字节的序号。
4、确认序号
同样的占4个字节,标识了期望收到对方下一个报文段的第一个数据字节的序号。
注:若确认序号=N,表明到序号N-1为止的所有数据都确认收到
5、首部长度
占4位。这个字段指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。也就是TCP报文段首部的长度。
6、保留
占6位,保留为今后用,目前都置为0
7、六个标志位

  • URG:紧急标志位。当URG=1时,表明紧急指针字段(后面介绍)有效,它告诉操作系统报文段中有紧急数据应该被尽快传送

  • ACK:确认标志位。仅当ACK=1时该字段才有效。TCP规定在连接建立后所有传送的报文段都必须把ACK置为1

  • PSH:推送标志位。当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,发送方TCP就可以将PSH字段置1 ,并立即创建一个报文段发送出去,接收方收到 PSH = 1的报文段,就尽快地交付给接收应用进程,而不再等到整个缓存都填满后再向上交付。

  • RST:复位标志位。当RST=1时,表明TCP连接中出现了严重差错必须释放连接,然后在重新建立运输连接。RST置为1还可以用来拒绝一个非法的报文段或拒绝打开一个连接。

  • SYN:同步标志位。在连接建立时用来同步序号。当SYN=1而ASK=0时表明这是一个连接请求报文段。如果对方同意建立连接,就可以在响应报文段中使用SYN=1和ACK=1。

  • FIN:终止标志位。用来释放一个连接,当FIN=1时,表明此报文段发送方的数据已经发送完毕,并要求释放连接。
    8、窗口
    占16位。窗口值是0~(2^16-1)之间的整数。
    窗口指的是发送本报文段的一方的接收窗口,也就是自己接受缓冲区的大小。窗口值告诉对方,从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量。窗口值作为接收方让发送方设置其发送窗口的依据。
    9、检验和
    占16位。和IP数据报不同的是,TCP报文段检验的范围包括首部和数据两部分(IP数据报只检验首部部分),但是检验方法类似。

  1. 在发送方,首先把全零放入检验和字段
  2. 把伪首部以及TCP数据报看成是由许多16位字的字串连接起来。若TCP报文段的数据部分不是偶数个字节,则要填入一个全零字节(但此字节不发送)
  3. 然后按二进制反码计算出这些16位字的和,将结果的二进制反码写入检验和字段并发送
  4. 在接受方,把收到的TCP报文连同伪首部一起按二进制反码求出这些16位字德和。当无差错时结果为1,若结果为0,就表示有差错,接收方就丢弃这个报文段

在这里说一下伪首部的概念:伪首部有12个字节,分为5个字段。
第一字段和第二字段分别为源IP地址和目的IP地址。
第三字段是全零
第四字段是IP首部中的协议字段的值
第五字段是TCP数据报的长度
10、紧急指针
占16位。紧急指针只在URG=1时有效,标识了本报文段中紧急数据的字节数,指出来紧急数据末尾在报文段中的位置
注:当窗口为0时,也可以发送紧急数据。
11、选项
也是一个可变长字段最大可达40字节,当没有使用选项时,TCP的首部长度就是20字节。

如果IP报文段首部的协议是UDP,那么自然IP数据部分也就是UDP的内容,UDP相对来说就比较简单了,如下:
在这里插入图片描述
1、源端口号
占16位。标识源主机的端口或进程,同TCP。
2、目的端口号
占16位。标识要发送个目的主机的哪个端口或进程
3、首部长度
占16位。标识UDP整个数据报的长度(包括首部和数据)。最小值为8(仅有首部)
4、检验和
占16位。检测UDP用户数据报在传输中是否有错,有错就丢掉。检测方式同TCP一样,检验范围也是包括首部和数据。

UDP与TCP的区别
UDP:
面向非链接,即发送数据之前不需要建立连接
不维护链接状态,支持同时向多个客户端传输相同消息
数据包报头只有8个字节,额外开销较小
吞吐量只受限于数据生成速率,传输速率以及机器性能
尽最大努力交付,不保证可靠交付,不需要维持复杂的链接状态表
UDP是面向报文的,不对应用程序提交的报文信息进行拆分或合并,所以报文大小由应用程序解决和优化, UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
UDP支持一对一,一对多,多对一和多对多的交互通信
UDP则是不可靠信道
TCP:
面向链接,三次握手,四次挥手
TCP提供可靠的服务,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达
TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流
每一条TCP连接只能是点到点的,TCP速度比UDP慢
TCP属于重量级,UDP属于轻量级,TCP报头20个字节UDP报头8个字节
TCP的逻辑通信信道是全双工的可靠信道

单工,半双工,全双工
单工:我跟你说话,你不能跟我说.
半双工:我跟你说话,你只能等我说完了你才能跟我说.
全双工:我跟你说话,你不用等我说完就可以中途插嘴跟我说话!

好了,到这里报文段基本算是结束了,下面我们就结合通信来说,这些比特位为什么存在,有啥作用?

三次握手

在这里插入图片描述
客户端与服务端想要通信,就需要发送三个数据包来最终确定建立一个连接.就像是:


我:

  1. 约不约?
  2. 然后满脸期待.

妹子:

  1. 听到我问她了约不约了.
  2. 然后说"约"
  3. 然后心里想着"算你识相,还知道主动约老娘!"

我:

  1. 听到并且确认妹子同意了
  2. 说"那走吧!"
  3. 然后屁颠屁颠牵着妹子手进行下一步了!

1. 那这三次交流到底是怎么完成的呢?
第一次握手(我):
  客户端向服务端发送一个SYN=1(位数为1),seq=x(同步序列编号,随机产生一个)到服务端(也就是约不约?),然后客户端进入SYN_SENT(同步发送)状态,然后等待服务端确认.当SYN=1而ASK=0时表明这是一个连接请求报文段。如果对方同意建立连接,就可以在响应报文段中使用SYN=1和ACK=1,TCP规定SYN=1时不能携带数据,但要消耗一个序号,因此声明自己的序号是 seq=x
第二次握手(妹子):
  当服务端收到客户端的SYN包之后,就必须确认客户端的SYN,也就是(ack=x+1)表示我收到这个消息了,同时自己也发送一个SYN包(SYN=1,seq=y,ACK=1,ack=x+1)给客户端,告诉客户端我收到你发给我的消息了,同时自己进入一个SYN_RECV状态(同步收到)
第三次握手(我)
  当客户端收到服务端的"约"(SYN+ACK包)并且验证ack=x+1,seq=x+1以后,客户端就明白服务端知道了,也就是同意建立连接了,然后客户端就需要再告诉服务端一声,我准备给你数据了,也就是向服务端发送确认包ACK( ACK=1, seq=x+1, ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手.
2. 说完三次握手问题也就随之而来了,为什么是三次握手不是两次呢?
   不是两次是三次的主要原因其实是为了防止已失效的请求报文段突然又传送到服务端的情况.这样会造成连接异常.
假设有这么一种情况:
  当客户端发送SYN包给服务端时,由于网络问题,造成了数据包延迟,请求报文段在网络节点中滞留了,也就是第一次握手被无限延长了,妹子短时间内没听到,后来客户端又问了一次,也就是又发送一次SYN包给服务端,然后服务端回复了,之后建立连接,但是第一次的SYN包还在网络节点里,但是并没有消失,等网络通畅了,这个SYN包又被服务端接收了,然后服务端又回复了一个消息给客户端,如果客户端不确认这个请求报文段,那么就直接建立连接了,但是此时的客户端已经走远了,完全不知道妹子隔了那么久突然跟他说约,客户端听不到了,但是妹子还一直等着客户端回复呢,这就造成了服务端一直等待确认的情况,如果次数多了,对服务端是一个很大的BUG,会造成很多资源浪费.所以才有了第三次握手的确认过程!
3. 三次握手引起的DOS/SYN攻击
   什么是DOS或者SYN攻击呢,其实就是根据三次握手的漏洞造成的,原理是什么呢?其实也就是上边说的那种情况,客户端一直向服务端发送SYN包,然后服务端回复并进入SYN_RECV状态(同步收到),此时客户端不再进行第三次握手,并且频繁的发送第一次握手给服务端,那么服务端会一直接收SYN包并回复,但是没有了后续的事情,所以服务端久而久之就会崩溃,当然这是单机的DOS攻击,像分布式的DDOS攻击不多赘述了!

四次挥手

在这里插入图片描述
客户端与服务端想要终止通信,就需要四次通信了.就像是:


我:

  1. 我们分手吧,你马上给我搬出去,我不想再看到你!
  2. 然后气愤的等着妹子答复!

妹子:

  1. 分手就分手!老娘早看你不顺眼了,我现在就收拾完东西走人!哼!
  2. 然后妹子开始收拾东西,我继续等着

妹子:

  1. 收拾完了
  2. 冲我吼到"永不相见!"

我:

  1. 赶紧滚!,然后妹子走了,我又单身了!

1. 那这四次交流到底是怎么完成的呢?
第一次挥手(我):
  我跟妹子要分手,是我主动提出的,也没啥好说的,所以客户端数据发送完了没数据再发送了,所以主动要求关闭此次长连接,然后给服务端发送一个释放连接的报文段,而这个报文段首部是FIN=1,序列号是seq=u(u其实就是前面传送过来的数据的最后一个字节序号+1,TCP规定,及时报文不带数据也必须要消耗一个序列号,所以这里必须有seq),等客户端发送完成,也就是我说完分手以后就等着妹子答复了,此时进入了终止连接等待状态1(FIN-WAIT-1).
第二次挥手(妹子):
  妹子听到我要跟她分手,很气愤,所以告诉我分就分,也就是服务端接收到客户端发送过来的FIN报文段以后随即给客户端发送确认ACK报文段,也就是ACK=1,ack=u+1,并且还有自己的序列号seq=v(分手就分手!老娘早看你不顺眼了,我现在就收拾完东西走人!哼!),然后服务端进入了关闭等待状态(CLOSE-WAIT,也就是开始收拾东西,发送没有发送完的数据),服务端通知完客户端,客户端这边针对服务端的连接就释放了,这时候服务端处于半关闭状态,即客户端已经没有数据要发送了,但是服务器可能还要发送数据,客户端依然需要接受数据,这个发送数据的状态还是要持续一段时间,这也就是整个CLOSE-WAIT状态需要持续等待的时间.然后就是我听到妹子说要收拾完东西走,那我就等着她收拾完让她走人,也就是客户端收到服务端的确认ACK报文段之后,客户端进入终止连接等待状态2(FIN-WAIT-2),此时客户端等待服务端发送释放连接的报文的同时,还要继续接收服务端未发送完的数据.也就是我不仅要等着她走还要看着她收拾完东西.
第三次挥手(妹子)
  妹子收拾完了,然后跟我说永不相见.也就对应着服务端向客户端发送数据彻底完毕(东西收拾完准备撤了),此时服务端想客户端发送释放连接的FIN报文段(FIN=1,ack=u+1),由于服务端处于半关闭状态,这个期间还发送给客户端数据,所以此时的序列号已经不是之前的连续序列号了,假设此时发送的关闭连接报文段序列号为seq=w,那么报文段发送过去之后,服务端自然就进入了最后等待确认释放的状态,也就是等着客户端确认可以断开了.(也就是等着我说"赶紧滚")
第四次挥手(我)
  等我看到妹子收拾完了,我就说赶紧滚!,然后妹子走了,我又单身了!也就对应着服务端发送给客户端FIN报文段之后,客户端接收到了服务端释放连接的确认报文段,自然要给服务端回应说ok,所以客户端需要向服务端发送最终的断开连接确认ACK报文段(ACK=1,ack=w+1,seq=u+1),此时,客户端就确认完成了,自动进入报文寿命终结的状态,也就是等待此次报文失效的那一段时间(TIME-WAIT),需要搞明白的是,客户端发送ACK确认报文以后并不是直接就释放连接了,而是需要等待2MSL的时间之后,客户端才会进入关闭状态,与此同时,服务端接收到客户端的确认报文之后会直接进入关闭状态.

2. 什么是2MSL?
  MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为tcp报文(segment)是ip数据报(datagram)的数据部分,具体称谓请参见《数据在网络各层中的称呼》一文,而ip头中有一个TTL域,TTL是time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个ip数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。
  2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。
TTL与MSL是有关系的但不是简单的相等的关系,MSL>=TTL

3. 如果已经建立了连接,但是客户端突然出现故障了怎么办?
  TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

TCP如何维持数据传输有序性的?

RTT: 客户端从发送一个FIN数据包到服务端,服务端收到包并发送ACK确认包给客户端,一直到客户端收到ACK确认包所花费的时间.
RTO: 重传时间间隔, 客户端在发送一个数据包给服务端的时候会开启一个重传定时器, 而这个定时器的时间是通过算法算出来的,它是基于RTT计算得到的,并不是固定数据,在客户端收到服务端的ACK确认包之后,会让这个定时器失效,如果定时器时间,也就是超时时间到了都没有收到ACK包,那么就开始重新发送.关于这个时间怎么算不过多描述,如果有兴趣可以参考以下两篇博文:

  1. TCP中RTT的测量和RTO的计算
  2. TCP协议中RTO的计算

TCP的滑动窗口
我们都知道TCP是通过数据包的方式发送数据的,是一段一段的去发送的,而不是整个发送, 因为每段发送的顺序不固定,所以为了保证TCP的可靠传输就需要用到滑动窗口和重传机制!下面来详细介绍一下:
TCP会利用滑动窗口来做流量控制以及乱序后的重新排序, 用来保证TCP的可靠性和流控特性,可靠性可能好理解一点,但是流控是什么,流控其实就是流量控制,也就是数据流的大小控制,上边介绍的TCP报文段图中有一个窗口,而这个窗口就是服务端告诉客户端我还可以接受多少数据的指标,这样客户端就可以根据服务端给出的数据大小来处理发送的数据,也就可以避免服务端数据处理不过来的情况,这也就是TCP的流量控制模式,其实这就是滑动窗口实现的基石之一.

先来两张图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

相信看图大家已经很明白了,那就是滑动窗口是发生在TCP数据缓冲区中的,而它是怎么滑的呢?其实看懂第二个图以后基本也就明白了,大家可能看的有点懵,图描述的可能有点偏差,但是意思是可以表示的,概念差不多,下面我来详细介绍一下:

客户端缓冲区:

  1. lastByteAcked:
    客户端连续收到ACK确认包后的最大字节位置
  2. lastByteSent
    客户端已发送但是还未收到ACK确认包的最后一个字节的位置
  3. lastByteWritter
    指客户端已写完的最后一个字节的位置,也就是send方法写入的数据
  4. 发送缓冲区分布:
    (1):被服务端确认过的数据区
    (2):客户端已发送未被服务端确认的区域,也就是未收到ACK包的数据区,发送中的状态
    (3):客户端已写入但是未发送的数据区
    (4):客户端发送缓冲区还能继续写入的数据区

服务端缓冲区:

  1. lastByteRead:
    指上层应用已经读完的最后一个字节的位置,也就是recv方法正在读的最后一个字节,同时也是服务端给客户端发送过ACK包的最后一个字节位置
  2. nextByteExpected
    指向的是服务端已经接收到数据包正在处理还没来的及回复确认包的字节位置
  3. lastByteRcvd
    指向的是服务端已经接收到数据包最后一个字节的位置,而之前空白的区域也就是还没接收到的数据部分
  4. 接收缓冲区分布:
    (5):服务端处理好的数据区,也就是已经发送过ACK确认包之后的数据区
    (6):服务端接收到正在处理还没有发送ACK确认包的数据区
    (7):客户端已发送,但是服务端还没接收到的数据区
    (8):服务端接收到的最大字节之前的数据区(此处包含6和7,可以理解为8区=6区+7区)
    (9):服务端还能接收的数据区,(5)其实也算是这种数据区 ,此处大小计算方式为:
    advertisedWindow = MaxRcvBuffer-(lastByteRcvd-lastByteRead)
    还能接收的数据量=缓冲区大小-(正在接收的数据量),而对应的发送缓冲区还能发送多少的计算方式如下:
    effectiveWindow=advertisedWindow -(lastByteSent-lastByteAcked)
    还能发送的数据量=还能接收的数据量-(已发送还未确认的数据量)

怎么滑的?
好了,该说的基本都说完了,那咱们继续说怎么滑这个问题,老样子,先上图:

在这里插入图片描述
画这玩意简直太恶心了,看着有点乱,请见谅,看了我的介绍估计也就用不上这个图了,脑补一下好了,gif画起来更恶心,实在是蛋疼!

图中的方形数字表示发送缓冲区的字节,圆形表示接收缓冲区的字节,每个颜色的框和箭头表示每次滑动的区域.
假设发送方窗口大小为3,接收方窗口大小为2,这个窗口大小是计算得到的,并不是固定大小,具体计算方式说实话我还没来得及研究,以后研究了可以补充上,如果对这个感兴趣可以去查查.
具体的滑动步骤如下:

  1. 发送方向接收方发送了1,2,3三个字节,接收方收到1,2字节之后,发送接收1的ack确认包给发送方,然后发送方接收到ack包之后向后滑动一位.
  2. 以此类推,当然接收方处理字节的顺序并不是固定的,就是谁处理的快就先回复谁的ack,等到绿色窗口时,接收方先确认5,在此期间,当发送方接收到5的ack之后,并不会滑动窗口,因为发送方窗口是连续的,等到接收到4的ack包之后才会向后滑动,也就是等接收4的ack之后,滑动窗口直接滑动到5的下一位,也就是6的位置.期间如果4一直未收到ack确认包,那等到重发计时器时间到了就会进行数据重发,最终收到4的ack之后进行滑动.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值