TCP

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 连接。
  3. 序列号(Sequence Number)- 发送数据包中的第一个字节的序列号,32位
    在 TCP 传送的流中,每一个字节一个序号。比如一个报文段的序号为 300,此报文段的数据部分共有 100 字节,则下一个报文段的序号为 400。序号确保了 TCP 传输的有序性。
  4. 确认序列号(Acknowledgment Number)- 32位
    指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当 ACK 标志为 1 时才有效。
  5. 数据偏移(Data Offset)- 4位,该字段的值是 TCP 首部(包括选项)长度除以4
    首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。
  6. 保留(Reserved):为将来定义新的用途保留,现在一般置 0
  7. 控制标志位 - 6位
  8. 窗口(Window)- 滑动窗口大小,16位
    用来告诉TCP连接对端自己能够接收的最大数据长度。窗口大小最大为 65535。
  9. 校验和(Checksum)- 奇偶校验,16位
    此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
  10. 紧急指针(Urgent Pointers)- 紧急指针,16位
    只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
  11. 选项和填充(Options、Padding)
    最常见的可选字段是最长报文大小,又称为 MSS (Maximum Segment Size),每个连接方通常都在通信的第一个报文段 (为建立连接而设置 SYN 标志为 1 的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是 32 位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证 TCP 头是 32 的整数倍。
  12. 数据
控制位 说明
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 连接。

TCP 和 UDP 的对比

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

参考文章

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