TCP - 基础

249 阅读7分钟

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

  • 应用层向 TCP 层发送用于网间传输的、用8位字节表示的数据流,然后 TCP 把数据流分区成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。
  • 之后 TCP 把结果包传给 IP 层,由它来通过网络将包传送给接收端实体的 TCP 层。
  • TCP 为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。
  • 接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。
  • TCP 用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

TCP 报文结构

  1. 源端口(Source Port)- 16 位(bit
  2. 目标端口(Destination Port)- 16 位
源端口号和目的端口号,用来标识同一台计算机的不同的应用进程。TCP 报头中的源端口号和目的端口号同 IP 数据报中的源 IP 与目的 IP 唯一确定一条 TCP 连接。
  1. 序列号(Sequence Number)- 发送数据包中的第一个字节的序列号,32位
在 TCP 传送的流中,每一个字节一个序号。比如一个报文段的序号为 300,此报文段的数据部分共有 100 字节,则下一个报文段的序号为 400。序号确保了 TCP 传输的有序性。
  1. 确认序列号(Acknowledgment Number)- 32位
指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当 ACK 标志为 1 时才有效。
  1. 数据偏移(Data Offset)- 4位,该字段的值是 TCP 首部(包括选项)长度除以4
首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。
  1. 保留(Reserved):为将来定义新的用途保留,现在一般置 0
  2. 控制标志位 - 6位
  3. 窗口(Window)- 滑动窗口大小,16位
用来告诉TCP连接对端自己能够接收的最大数据长度。窗口大小最大为 65535。
  1. 校验和(Checksum)- 奇偶校验,16位
此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
  1. 紧急指针(Urgent Pointers)- 紧急指针,16位
只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
  1. 选项和填充(Options、Padding)
最常见的可选字段是最长报文大小,又称为 MSS (Maximum Segment Size),每个连接方通常都在通信的第一个报文段 (为建立连接而设置 SYN 标志为 1 的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是 32 位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证 TCP 头是 32 的整数倍。
  1. 数据
控制位 说明
URG 紧急指针标志,为 1 时表示紧急指针有效,为 0 则忽略紧急指针
ACK (Acknowledgement) 确认序号标志,为 1 时表示确认号有效,为 0 表示报文中不含确认信息,忽略确认号字段
PSH push 标志,为 1 表示是带有 push 标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队
RST 重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求
SYN (Synchronize) 同步序号,用于建立连接过程,在连接请求中,SYN=1 和 ACK=0 表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即 SYN=1 和 ACK=1
FIN (Finish) 用于释放连接,为 1 时表示发送方已经没有数据发送了,即关闭本方数据流

TCP 建立连接 (三次握手)

TCP三次握手的过程如下:

  1. 客户端发送 SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。
  2. 服务器端收到 SYN 报文,回应一个 SYN (SEQ=y)ACK (ACK=x+1)报文,进入 SYN_RECV 状态。
  3. 客户端收到服务器端的 SYN 报文,回应一个 ACK(ACK=y+1)报文,进入 Established 状态。

三次握手完成,TCP 客户端和服务器端成功地建立连接,可以开始传输数据了。

TCP 关闭连接 (四次挥手)

建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由 TCP 的半关闭(half-close)造成的。

  1. 客户端调用 close() 函数,并发送一个 FIN (finish) 标志为 1 的数据包给服务端,来表示本方的数据已经全部发送完毕,此时客户端进入 FIN_WAIT_1 状态。TCP 规定,FIN 报文段即使不携带数据,也要消耗一个序号。
  2. 服务端收到客户端的释放报文后,发出确认报文,其中 ACK=1, ack=u+1,并且带上自己的序列号 seq=v。表明自己接受到了客户端关闭连接的请求,但还没准备好关闭连接 (半关闭状态),也就是说客户端已经没有数据要发送了,但服务端仍有可能会发送数据。发送完毕后,服务端进入 CLOSE_WAIT 状态。当客户端收到该报文后,客户端就进入 FIN-WAIT-2 状态,等待服务器发送连接释放报文。
  3. 服务器端准备好关闭连接时,会向客户端发送一个连接释放报文,其中 FIN=1,ack=u+1。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为 seq=w。发送完毕后,服务端便进入 LAST-ACK(最后确认) 状态。
  4. 客户端收到服务器的连接释放报文后,需要发送一个确认包,其中 ACK=1,ack=w+1,而自己的序列号是 seq=u+1,并进入了 TIME-WAIT (时间等待)状态,等待过程可能出现的要求重传的 ACK 包。 此时 TCP 连接还没有释放,必须经过 2 * MSL (Maximum Segment Lifetime, 最长报文段寿命) 时间后,当客户端撤销相应的 TCB 后,才会进入 CLOSED 状态。 而服务器只要收到了客户端发出的确认,立即进入 CLOSED 状态。同样,撤销 TCB 后,就结束了这次的 TCP 连接。

TCPUDP 的对比

UDP TCP
是否连接 无连接 面向连接
是否可靠 不可靠传输,不使用流量控制和拥塞控制 可靠传输,使用流量控制和拥塞控制
连接对象个数 支持一对一,一对多,多对一和多对多交互通信 只能是一对一通信
传输方式 面向报文 面向字节流
首部开销 首部开销小,仅 8 字节 首部最小 20 字节,最大 60 字节
适用场景 适用于实时应用 (IP 电话、视频会议、直播等) 适用于要求可靠传输的应用,例如文件传输

参考文章

[HTTP 系列] 第 1 篇 —— 从 TCP/UDP 到 DNS 解析