TCP协议笔记

版权声明:from Hasson https://blog.csdn.net/has_son/article/details/84243849

TCP协议笔记

TCP协议简介

在TCP/IP模型中,传输层的功能是使源端主机和目标端主机上的对等实体可以进行会话。在传输层定义了两种服务质量不同的协议。即:传输控制协议TCP(transmission control protocol)和用户数据报协议UDP(user datagram protocol).

TCP协议是一个面向连接的、可靠的协议。它将一台主机发出的字节流无差错地发往互联网上的其他主机。在发送端,它负责把上层传送下来的字节流分成报文段并传递给下层。在接收端,它负责把收到的报文进行重组后递交给上层。TCP协议还要处理端到端的流量控制,以避免缓慢接收的接收方没有足够的缓冲区接收发送方发送的大量数据.

其中运输层主要有两个作用

一、格式化信息流;

二、提供可靠传输。

TCP协议图

TCP报文组成部分

TCP报文组成部分

16位源端口号:16位的源端口中包含初始化通信的端口。源端口和源IP地址的作用是标识报文的返回地址。

16位目的端口号:16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。

其中

端口号 协议
FTP 21
TELNET 23
SMTP 25
DNS 53
HTTP 80
SNMP 161

0-1023称为公认端口,不能分配

1024-49151 是分配注册端口,已经登记过的

49152~65535 客户端使用的端口号,被保留给客户端进程选择暂时使用的

32位序号:32位的序列号由接收端计算机使用,重新分段的报文成最初形式。当SYN出现,序列码实际上是初始序列码(Initial Sequence Number,ISN),而第一个数据字节是ISN+1。这个序列号(序列码)可用来补偿传输中的不一致。

32位确认序号:32位的序列号由接收端计算机使用,重组分段的报文成最初形式。如果设置了ACK控制位,这个值表示一个准备接收(下一个)的包的序列码。只有ACK位为一才有意义

4位首部长度:4位包括TCP头大小,指示何处数据开始。

保留(6位):6位值域,这些位必须是0。为了将来定义新的用途而保留。

标志:6位标志域。表示为:紧急标志、有意义的应答标志、推、重置连接标志、同步序列号标志、完成发送数据标志。按照顺序排列是:URG、ACK、PSH、RST、SYN、FIN。

16位窗口大小:用来表示期望收到的每个TCP数据段的大小。TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。窗口大小是一个16字节字段,因而窗口大小最大为65535字节。

16位校验和:16位TCP头。源机器基于数据内容计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。

16位紧急指针:指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。加快处理标示为紧急的数据段。它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。

选项:长度不定,但长度必须为1个字节。如果没有选项就表示这个1字节的域等于0。

数据:该TCP协议包负载的数据。

在上述字段中,6位标志域的各个选项功能如下。

URG(urgent pointer):紧急标志。紧急标志为"1"表明该位有效。

ACK:确认标志。表明确认编号栏有效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。

PSH:推标志。该标志置位时,接收端不将该数据进行队列处理,而是尽可能快地将数据转由应用处理。在处理Telnet或rlogin等交互模式的连接时,该标志总是置位的。

RST:复位标志。用于复位相应的TCP连接。

SYN:同步标志。表明同步序列编号栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。

FIN:结束标志。

TCP可靠传输

何为可靠

  1. 不错:就是传输的数据包没有错误
  2. 不丢:传输的数据包不丢失
  3. 不乱:传输的数据包顺序要保持正确的交付。

可靠实现

校验和

计算方式:在数据传输的过程中,将发送的数据段都当做一个16位的整数。将这些整数加起来。并且前面的进位不能丢弃,补在后面,最后取反,得到校验和。

发送方:在发送数据之前计算检验和,并进行校验和的填充。

接收方:收到数据后,对数据以同样的方式进行计算,求出校验和,与发送方的进行比对。

如果接收方比对校验和与发送方不一致,那么数据一定传输有误。但是如果接收方比对校验和与发送方一致,数据不一定传输成功。

确认应答与序列号

序列号:TCP传输时将每个字节的数据都进行了编号,这就是序列号。

确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,已经接收到了哪些数据,下一次的数据从哪里发。

序列号的作用不仅仅是应答的作用,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据。这也是TCP传输可靠性的保证之一。
ACK

超时重传机制

首先,发送方没有介绍到响应的ACK报文原因可能有两点:

  • 数据在传输过程中由于网络原因等直接全体丢包,接收方根本没有接收到。
  • 接收方接收到了响应的数据,但是发送的ACK报文响应却由于网络原因丢包了。

简单理解就是发送方在发送完数据后等待一个时间,时间到达没有接收到ACK报文,那么对刚才发送的数据进行重新发送。如果是刚才第一个原因,接收方收到二次重发的数据后,便进行ACK应答。如果是第二个原因,接收方发现接收的数据已存在(判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用),那么直接丢弃,仍旧发送ACK应答。

时间计算方法如下:

R T T RTT 报文段往返时间

R T O RTO 超时重传时间

R T T D RTT_D 是RTT的偏差的加权平均值

R T T s RTT_s 加权平均往返时间(平滑的往返时间RTT)

n e w   R T T s = ( 1 a ) ( o l d   R T T s ) + a ( n e w   R T T ( s a m p l e ) ) new \ RTT_s = (1-a) * (old \ RTT_s) + a*(new\ RTT_(sample))

R T O   = R T T S + 4 R T T D RTO \ = RTT_S + 4*RTT_D

n e w   R T T D   = ( 1 β ) ( o l d   R T T D ) + β     R T T s n e w   R T T ( s a m p l e ) new\ RTT_D \ = (1-\beta)*(old\ RTT_D) + \beta \ * \ \mid RTT_s - new\ RTT_(sample) \mid

连接管理

image
step1:第一次握手

建立连接时,客户端发送SYN包到服务器,其中包含客户端的初始序号seq=x,并进入SYN_SENT状态,等待服务器确认。(其中,SYN=1,ACK=0,表示这是一个TCP连接请求数据报文;序号seq=x,表明传输数据时的第一个数据字节的序号是x)。

step2:第二次握手

服务器收到请求后,必须确认客户的数据包。同时自己也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN_RECV状态。(其中确认报文段中,标识位SYN=1,ACK=1,表示这是一个TCP连接响应数据报文,并含服务端的初始序号seq(服务器)=y,以及服务器对客户端初始序号的确认号ack(服务器)=seq(客户端)+1=x+1)。

step3:第三次握手

客户端收到服务器的SYN+ACK包,向服务器发送一个序列号(seq=x+1),确认号为ack(客户端)=y+1,此包发送完毕,客户端和服务器进入ESTAB_LISHED(TCP连接成功)状态,完成三次握手。

我们来分析一种特殊情况,假设客户端请求建立连接,发给服务器SYN包等待服务器确认,服务器收到确认后,如果是两次握手,假设服务器给客户端在第二次握手时发送数据,数据从服务器发出,服务器认为连接已经建立,但在发送数据的过程中数据丢失,客户端认为连接没有建立,会进行重传。假设每次发送的数据一直在丢失,客户端一直SYN,服务器就会产生多个无效连接,占用资源,这个时候服务器可能会挂掉。这个现象就是我们听过的“SYN的洪水攻击”。
总结:第三次握手是为了防止:如果客户端迟迟没有收到服务器返回确认报文,这时会放弃连接,重新启动一条连接请求,但问题是:服务器不知道客户端没有收到,所以他会收到两个连接,浪费连接开销。如果每次都是这样,就会浪费多个连接开销。

image

  1. 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
  2. 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
  3. 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
  4. 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
  5. 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
  6. 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。

第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

流量控制与拥塞控制

主要包括两个内容

(1)慢开始,拥塞避免

(2)快重传,快恢复

1.流量控制——滑动窗口

image
TCP采用大小可变的滑动窗口进行流量控制,窗口大小的单位是字节。
发送窗口在连接建立时由双方商定。但在通信的过程中,接收端可根据自己的资源情况,随时动态地调整对方的发送窗口上限值(可增大或减小)。
为什么要设置窗口?
我们可以把窗口理解为缓冲区(但是有些窗口和缓冲区又不太一样)。
如果没有这些“窗口”,那么TCP没发送一段数据后都必须等到接收端确认后才能发送下一段数据,这样做的话TCP传输的效率实在是太低了。
解决的办法就是在发送端等待确认的时候继续发送数据,假设发送到第X个数据段是收到接收端的确认信息,如果X在可接受的范围内那么这样做也是可接受的。这就是窗口(缓冲区)引入的缘由。
1.1 窗口
(1)接收端窗口 rwnd
接收端缓冲区大小。接收端将此窗口值放在 TCP 报文的首部中的窗口字段,传送给发送端。
(2) 拥塞窗口 cwnd (congestion window)
发送端缓冲区大小
(3)发送窗口swnd
发送窗口的上限值 = Min [rwnd, cwnd]
当 rwnd < cwnd 时,是接收端的接收能力限制发送窗口的最大值。
当 cwnd < rwnd 时,则是网络的拥塞限制发送窗口的最大值。
1.2 滑动窗口
发送端已发送了 400 字节的数据,但只收到对前 200 字节数据的确认,同时窗口大小不变。还可发送 300 字节。

发送端收到了对方对前 400 字节数据的确认,但对方通知发送端必须把窗口减小到 400 字节。现在发送端最多还可发送 400 字节的数据。

2. 拥塞控制

image

2.1 慢开始和拥塞避免

2.1.1 慢开始原理

(1)在主机刚刚开始发送报文段时可先将拥塞窗口 cwnd 设置为一个最大报文段 MSS 的数值。

(2)在每收到一个对新的报文段的确认后,将拥塞窗口增加至多一个 MSS 的数值。

(3)用这样的方法逐步增大发送端的拥塞窗口cwnd,可以使分组注入到网络的速率更加合理。

注:图中窗口的单位都是报文段
(1)当 TCP 连接进行初始化时:
发送窗口:swnd = 1
慢开始阈值:ssthresh = 16

(2)发送端收到 ACK1 (确认 M0,期望收到 M1)后,将 cwnd 从 1 增大到 2,于是发送端可以接着发送 M1 和 M2 两个报文段(指数增长)

(3)接收端发回 ACK2 和 ACK3。发送端每收到一个对新报文段的确认 ACK,就把发送端的拥塞窗口加 1。现在发送端的 cwnd 从 2 增大到 4,并可发送 M4 ~ M6共 4个报文段。(指数增长)

(4)当swnd >= ssthresh,swnd执行拥塞避免算法,swnd窗口按线性规律增长。 (加法增大)

(5)当发送 超时,此时swnd = 24 :ssthresh = swnd/2 = 12;(乘法减小)swnd = 1

(6)重复地2步。

2.2 快重传和快恢复

2.2.1 快重传

发送端只要一连收到三个重复的ACK即可断定有分组丢失了,就应立即重传丢失的报文段而不必继续等待为该报文段设置的重传计时器的超时
2.2.2 快恢复
(1) 当发送端收到连续三个重复的 ACK 时,就重新设置慢开始门限 ssthresh。

(2) 与慢开始不同之处是 swnd 不是设置为 1,而是设置为 ssthresh + 3 * MSS。

(3) 若收到的重复的 ACK 为 n 个(n > 3),则将 cwnd 设置为 ssthresh + n * MSS。

(4) 若发送窗口值还容许发送报文段,就按拥塞避免算法继续发送报文段。

(5) 若收到了确认新的报文段的 ACK,就将 swnd 缩小到 ssthresh。

猜你喜欢

转载自blog.csdn.net/has_son/article/details/84243849