07-传输层协议之TCP

传输层定义了主机应用程序之间端到端的连通性。传输层中最为常见的两个协议分别是传输控制协议TCP(Transmission Control Protocol)和用户数据包协议UDP(User Datagram Protocol)

一、TCP工作原理

TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN+ACK,并最终对对方的 SYN 执行 ACK 确认。这种建立连接的方法可以防止产生错误的连接

TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收

 

 TCP三次握手的过程如下:

  1. 第一次握手:Client(主机A)想Server(主机B)发送一个连接请求,在这个包中标志位SYN=1,发送序号SEQ=x,上图中令x=200,Client进入SYN_SEND状态,等待Server确认。
  2. 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,确认序号ACK=x+1=201,随机阐释一个发送序号y,令y=500。并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  3. 客户端收到服务器端的SYN报文,检查确认序号ACK是否为x+1=201;标志位ACK是否为1,如果正确,则将标志位ACK置1,确认序号ACK=y+1=501,并将该数据包发送给Server,Server检查确认需号ACK是否为y+1=501,标志位是否为1,如果正确则 连接建立成功,Client和Server进入ESTABLISHED状态。
三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了
 TCP四次挥手的过程如下:
  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(时间等待)状态
  6. 服务器只要收到了客户端发出的确认,立即进入CLOSED状态

1、TCP可靠性通过以下几点保证

  • 超时重传:TCP每发送出一个报文段后,都会启动一个定时器,对目的端传回的确认信息进行确认计时,超时后便重传。
  • 确认信号:当TCP收到一个来自TCP的报文段后,便会发送回一个确认信号。
  • 检验和:TCP将始终保持首部和数据的检验和,如果收到的报文段的检验和有差错,便将其丢弃,希望发送端超时重传。
  • 重新排序:由于IP数据报的达到可能失序,因此TCP将会数据进行重新排序,以正确的顺序交给应用层。
  • 丢弃重复:由于IP数据报有可能重复,因此TCP将会丢弃重复的数据。
  • 流量控制:TCP连接的两端都有固定大小的缓冲区空间,TCP接受端只允许对端发送本端缓冲区能容纳的数据
二、TCP报文格式
TCP 报文是传输层的数据单元,也称为报文段。TCP 报文中每个字段如图所示
源端口和目的端口字段
  • TCP源端口(Source Port):源计算机上的应用程序的端口号,占 16 位。
  • TCP目的端口(Destination Port):目标计算机的应用程序端口号,占 16 位。

序列号字段

序列号(Sequence Number):占 32 位。它表示本报文段所发送数据的第一个字节的编号。在 TCP 连接中,所传送的字节流的每一个字节都会按顺序编号。当SYN标记不为1时,这是当前数据分段第一个字母的序列号;如果SYN的值是1时,这个字段的值就是初始序列值(ISN),用于对序列号进行同步。这时,第一个字节的序列号比这个字段的值大1,也就是ISN加1。

确认号字段

TCP 确认号(Acknowledgment Number,ACK Number):占 32 位。它表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。其值是接收计算机即将接收到的下一个序列号,也就是下一个接收到的字节的序列号加1。

数据偏移字段

TCP 首部长度(Header Length):数据偏移是指数据段中的“数据”部分起始处距离 TCP 数据段起始处的字节偏移量,占 4 位。其实这里的“数据偏移”也是在确定 TCP 数据段头部分的长度,告诉接收端的应用程序,数据从何处开始。

保留字段

保留(Reserved):占 4 位。为 TCP 将来的发展预留空间,目前必须全部为 0。

标志位字段

  • CWR(Congestion Window Reduce):拥塞窗口减少标志,用来表明它接收到了设置 ECE 标志的 TCP 包。并且,发送方收到消息之后,通过减小发送窗口的大小来降低发送速率。
  • ECE(ECN Echo):用来在 TCP 三次握手时表明一个 TCP 端是具备 ECN 功能的。在数据传输过程中,它也用来表明接收到的 TCP 包的 IP 头部的 ECN 被设置为 11,即网络线路拥堵。
  • URG(Urgent):表示本报文段中发送的数据是否包含紧急数据。URG=1 时表示有紧急数据。当 URG=1 时,后面的紧急指针字段才有效。
  • ACK:表示前面的确认号字段是否有效。ACK=1 时表示有效。只有当 ACK=1 时,前面的确认号字段才有效。TCP 规定,连接建立后,ACK 必须为 1。
  • PSH(Push):告诉对方收到该报文段后是否立即把数据推送给上层。如果值为 1,表示应当立即把数据提交给上层,而不是缓存起来。
  • RST:表示是否重置连接。如果 RST=1,说明 TCP 连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。
  • SYN:在建立连接时使用,用来同步序号。当 SYN=1,ACK=0 时,表示这是一个请求建立连接的报文段;当 SYN=1,ACK=1 时,表示对方同意建立连接。SYN=1 时,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中 SYN 才为 1。
  • FIN:标记数据是否发送完毕。如果 FIN=1,表示数据已经发送完成,可以释放连接。

窗口大小字段

窗口大小(Window Size):占 16 位。它表示从 Ack Number 开始还可以接收多少字节的数据量,也表示当前接收端的接收窗口还有多少剩余空间。该字段可以用于 TCP 的流量控制。

TCP 校验和字段

校验位(TCP Checksum):占 16 位。它用于确认传输的数据是否有损坏。发送端基于数据内容校验生成一个数值,接收端根据接收的数据校验生成一个值。两个值必须相同,才能证明数据是有效的。如果两个值不同,则丢掉这个数据包。Checksum 是根据伪头 + TCP 头 + TCP 数据三部分进行计算的。

紧急指针字段

紧急指针(Urgent Pointer):仅当前面的 URG 控制位为 1 时才有意义。它指出本数据段中为紧急数据的字节数,占 16 位。当所有紧急数据处理完后,TCP 就会告诉应用程序恢复到正常操作。即使当前窗口大小为 0,也是可以发送紧急数据的,因为紧急数据无须缓存。

可选项字段

选项(Option):长度不定,但长度必须是 32bits 的整数倍

三、TCP窗口控制和重发控制

为了更有效地进行通信,TCP 协议在数据进行数据传输时,使用滑动窗口机制来同时发送多个数据包。当数据包丢失时,TCP 协议利用数据重发功能重新发送数据包

因接收端接收数据包的能力不同,TCP 流控制会根据接收端的能力发送适当数量的数据包

在进行数据传输时,如果传输的数据比较大,就需要拆分为多个数据包进行发送。TCP 协议需要对数据进行确认后,才可以发送下一个数据包,如图所示

 

从上图中可以看到,发送端每发送一个数据包,都需要得到接收端的确认应答以后,才可以发送下一个数据包。

这样一来,就会在等待确认应答包环节浪费时间。为了避免这种情况,TCP引入了窗口概念。窗口大小指的是不需要等待确认应答包而可以继续发送数据包的最大值

例如,窗口大小为 3,数据包的传输如图所示

 

从上图中可以看到,发送端发送第一个数据包(1-1000),没有等待对应的确认应答包,就继续发送第二个数据包(1001-2000)和第三个包(2001-3000)。当收到第3个数据包的确认应答包时,会连续发送3个数据包(3001-4000,4001-5000,5001-6000)

当收到第6个数据包的确认应答包时,又会发送3个数据包(6001-7000,7001-8000,8001-9000)。

以这种方式发送,就可以省去多个数据包(第1、2、4、5、7、8个)的确认应答包时间,从而避免了网络的吞吐量的降低

窗口大小指的是可以发送数据包的最大数量。在实际使用中,它可以分为两部分。第一部分表示数据包已经发送,但未得到确认应答包;

第二部分表示允许发送,但未发送的数据包。在进行数据包发送时,当发送了最大数量的数据包(窗口大小数据包),有时不会同时收到这些数据包的确认应答包,而是收到部分确认应答包

那么,此时窗口就通过滑动的方式,向后移动,确保下一次发送仍然可以发送窗口大小的数据包。这样的发送方式被称为滑动窗口机制。设置窗口大小为 3,滑动窗口机制原理如图所示

 

 上图中,每 1000 个字节表示一个数据包。发送端同时发送了 3 个数据包(2001-5000),接收端响应的确认应答包为“下一个发送4001”,表示接收端成功响应了前两个数据包,没有响应最后一个数据包。此时,最后一个数据包要保留在窗口中。

由于窗口大小为 3,发送端除了最后一个包以外,还可以继续发送下两个数据包(5001-6000 和 6001-7000)。窗口滑动到 7001 处

数据重发

在进行数据包传输时,难免会出现数据丢失情况。这种情况一般分为两种。

  • 第一种,如果未使用滑动窗口机制,发送的数据包没有收到确认应答包,那么数据都会被重发;如果使用了滑动窗口机制,即使确认应答包丢失,也不会导致数据包重发
  • 第二种,发送的数据包丢失,将导致数据包重发。


下面详细介绍使用滑动窗口机制的两种情况。

确认应答包丢失

这种情况指的是前面发送的数据包没有收到对应的确认应答。当收到后面数据包的确认应答包,表示前面的数据包已经成功被接收端接收了,发送端不需要重新发送前面的数据包了。如图所示

 

 下面分为 5 部分对上图进行讲解。

1) 发送端第 1 次发送数据包:这里设置的窗口大小为 3,可以最大发送 3 个数据包。发送端同时发送 3 个数据包 1-1000、1001-2000 和 2001-3000。

2) 接收端返回确认应答包:接收端接收到这些数据,并给出确认应答包。数据包 1-1000 和数据包 2001-3000 的确认应答包没有丢失,但是数据包 1001-2000 的确认应答包丢失了。

3) 发送端第 2 次发送数据包:发送端收到接收端发来的确认应答包,虽然没有收到数据包 1001-2000 的确认应答包,但是收到了数据包 2001-3000 的确认应答包。判断第一次发送的 3 个数据包都成功到达了接收端。再次发送 3 个数据包 3001-4000、4001-5000 和 5001-6000。

4) 接收端返回确认应答包:接收端接收到这些数据,并给出确认应答包。数据包 3001-4000 和数据包 4001-5000 的确认应答包丢失了,但是数据包 5001-6000 没有丢失。

5) 发送端第 3 次发送数据包:发送端收到接收端发来的确认应答包,查看到数据包 5001-6000 收到了确认应答包。判断第 2 次发送的 3 个数据包都成功到达了接收端。再次发送 3 个数据包 6001-7000、7001-8000 和 8001-9000

发送数据包丢失

这种情况指的是发送端发送的部分数据包没有达到接收端。那么,如果在接收端收到的数据包,不是本应该要接收的数据包,那么就会给发送端返回消息,告诉发送端自己应该接收的数据包。

如果发送端连续收到 3 次这样的数据包,就认为该数据包成功发送到接收端,这时就开始重发该数据包。如图所示

 

 下面分为 7 部分对上图进行讲解。

1) 发送端发送数据包:这里窗口大小为 4,发送端发送 4 个数据包,分别为 1-1000、1001-2000、2001-3000 和 3001-4000。

2) 接收端返回确认应答包:接收端接收到这些数据,并给出确认应答包。接收端收到了数据包 1-1000,返回了确认应答包;收到了数据包 1001-2000,返回了确认应答包;但是数据包 2001-3000,在发送过程中丢失了,没有成功到达接收端。数据包 3001-4000 没有丢失,成功到达了接收端,但是该数据包不是接收端应该接收的数据包,数据包 2001-3000 才是真正应该接收的数据包。因此收到数据包 3001-4000 以后,接收端第一次返回下一个应该发送 2001 的数据包的确认应答包。

3) 发送端发送数据包:发送端仍然继续向接收端发送 4 个数据包,分别为 4001-5000、5001-6000、6001-7000 和 7001-8000。

4) 接收端返回确认应答包:接收端接收到这些数据,并给出确认应答包。当接收端收到数据包 4001-5000 时,发现不是自己应该接收的数据包 2001-3000,第二次返回下一个应该发送 2001 的数据包的确认应答包。当接收端收到数据包 5001-6000 时,仍然发现不是自己应该接收的数据包 2001-3000,第三次返回下一个应该发送 2001 的数据包的确认应答包。以此类推直到接收完所有数据包,接收端都返回下一个应该发送 2001 的数据包的确认应答包。

5) 发送端重发数据包:发送端连续 3 次收到接收端发来的下一个应该发送 2001 的数据包的确认应答包,认为数据包 2001-3000 丢失了,就进行重发该数据包。

6) 接收端收到重发数据包:接收端收到重发数据包以后,查看这次是自己应该接收的数据包 2001-3000,并返回确认应答包,告诉发送端,下一个该接收 8001 的数据包了。

7) 发送端发送数据包:发送端收到确认应答包后,继续发送窗口大小为 4 的数据包,分别为 8001-9000、9001-10000、10001-11000 和 11001-12000

TCP流控制

在使用滑动窗口机制进行数据传输时,发送方根据实际情况发送数据包,接收端接收数据包。但是,接收端处理数据包的能力是不同的。

1) 如果窗口过小,发送端发送少量的数据包,接收端很快就处理了,并且还能处理更多的数据包。这样,当传输比较大的数据时需要不停地等待发送方,造成很大的延迟。

2) 如果窗口过大,发送端发送大量的数据包,而接收端处理不了这么多的数据包,这样,就会堵塞链路。如果丢弃这些本应该接收的数据包,又会触发重发机制。

3) 为了避免这种现象的发生,TCP 提供了流控制。所谓的流控制就是使用不同的窗口大小发送数据包。发送端第一次以窗口大小(该窗口大小是根据链路带宽的大小来决定的)发送数据包,接收端接收这些数据包,并返回确认应答包,告诉发送端自己下次希望收到的数据包是多少(新的窗口大小),发送端收到确认应答包以后,将以该窗口大小进行发送数据包。

TCP 流控制过程如图所示

 

 为了方便讲解,将上图以发送端发送数据包进行分隔,将其分为 3 部分进行讲解。

第一部分

发送端根据当前链路带宽大小决定发送数据包的窗口大小。这里,窗口大小为 3,表示可以发送 3 个数据包。因此发送端发送了 3 个数据包,分别为 1-1000、1001-2000 和 2001-3000。

接收端接收这些数据包,但是只能处理 2 个数据包,第 3 个数据包 2001-3000 没有被处理。因此返回确认应答包,设置窗口大小为 2,告诉发送端自己现在只能处理 2 个数据包,下一次请发送 2 个数据包。

第二部分

发送端接收到确认应答包,查看到接收端返回窗口大小为 2,知道接收端只处理了 2 个数据包。发过去的第 3 个数据包 2001-3000 没有被处理。这说明此时接收端只能处理 2 个数据包,第 3 个数据包还需要重新发送。

因此发送端发送 2 个数据包 2001-3000 和 3001-4000。接收端收到这两个数据包并进行了处理。此时,还是只能处理 2 个窗口,继续向发送端发送确认应答包,设置窗口为 2,告诉发送端,下一个应该接收 4001 的数据包。

第三部分

发送端接收到确认应答包,查看到接收端返回窗口大小为 2。说明接收端接收了上次发送的 2 个数据包。此时仍然可以处理 2 个数据包,继续发送数据包 4001-5000 和 5001-6000。

如果在接收端返回的确认应答包中,窗口设置为 0,则表示现在不能接收任何数据。这时,发送端将不会再发送数据包,只有等待接收端发送窗口更新通知才可以继续发送数据包。

如果这个更新通知在传输中丢失了,那么就可能导致无法继续通信。为了避免这样的情况发生,发送端会时不时地发送窗口探测包,该包仅有1个字节,用来获取最新的窗口大小的信息。

原理如图所示

 

 下面介绍上图所示的获取窗口更新数据包的原理。

1) 发送端发送数据。发送端以窗口大小为 2,发送了 2 个数据包,分别为 4001-5000 和 5001-6000。接收端接收到这些数据以后,缓冲区满了,无法再处理数据,于是向发送端返回确认应答包,告诉它下一个接收 6001 的数据,但是现在处理不了数据,先暂停发送数据,设置窗口大小为 0。

2) 发送端暂停发送数据。发送端收到确认应答包,查看到下一次发送的是 6001 的数据,但窗口大小为 0,得知接收端此时无法处理数据。此时,不进行发送数据,进入等待状态。

3) 接收端发送窗口大小更新包。当接收端处理完发送端之前发来的数据包以后,将会给发送端发送一个窗口大小更新包,告诉它,此时可以发送的数据包的数量。这里设置窗口大小为 3,表示此时可以处理 3 个数据包,但是该数据包丢失了,没有发送到发送端。

4) 发送端发送窗口探测包。由于窗口大小更新包丢失,发送端的等待时间超过了重发超时时间。此时,发送端向接收端发送一个窗口探测包,大小为 1 字节,这里是 6001。

5) 接收端再次发送窗口大小更新包。接收端收到发送端发来的探测包,再次发送窗口大小更新包,窗口大小为 3。

6) 发送端发送数据。发送端接收到窗口大小更新包,查看到应该发的是 6001 的数据包,窗口大小为 3,可以发送 3 个数据包。因此发送了数据包,分别为 6001-7000、7001-8000 和 8001-9000。

3、常见应用服务端口号

posted @ 2020-04-02 15:46  龙门、三少  阅读(440)  评论(0编辑  收藏  举报