前言
传输控制协议(Transmission Control Protocol)是因特网传输层的面向连接的可靠的传输协议
面向连接的传输:TCP
TCP 的特点
- 点对点:一个发送方,一个接收方
- 传输按顺序的字节流:没有报文边界
- 管道化(流水线):TCP 拥塞控制和流量控制
- 全双工数据:在同一连接中数据流双向流动
- 面向连接:在数据交换前通过握手(交换控制报文)初始化发送方、接收方的状态变量
TCP 报文段结构
- 源端口号:占两个字节,发送方的端口号
- 目的端口号:占两个字节,接收方的端口号
- 序号:占四个字节,报文段首字节在字节流的编号
- 确认号:占四个字节,期望从另一方收到的下一个字节的序号,这是一个累积确认
- 首部长度:占四位,即数据偏移,但其实该字段没有太大意义
- 保留未用:占六位,保留为今后使用
- 标志字段:占六位,在实践中,PSH、URG 和紧急数据指针并没有使用,为了完整性起见,才提到这些字段
- 接收窗口:占两个字节,用于流量控制,标识了接收方剩余可接收数据的空闲空间
- 因特网校验和:占两个字节,检验和字段检验的范围包括首部和数据这两部分
- 紧急数据指针:占两个字节,只有在 URG = 1 时才有效,一般不使用
- 选项:长度可变,最长可达40字节,可用于发送方与接收方协商最大报文段长度 MSS 。当没有使用“选项”时,TCP的首部长度是20字节,其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,那么选项部分最长为:(2^4-1)*4-20=40字节
- 数据:真正传输的数据
此外值得注意的是,由于 TCP 的首部一般是 20 字节,所以发送的报文段也许只有 21 字节长
TCP 的连接管理
三次握手
在正式交换数据之前,发送方和接收方握手建立通信关系。
- 第一次握手
客户端给服务器发送一个 SYN 段(在 TCP 标头中 SYN 位字段为 1 的 TCP/IP 数据包),该段中也包含客户端的初始序列号(seq=client_is x)
SYN 是同步的缩写,SYN 段是发送到另一台计算机的 TCP 数据包,请求在它们之间建立连接
- 第二次握手
服务器返回客户端 SYN+ACK 段(在 TCP 标头中 SYN 和 ACK 位字段都为 1 的 TCP/IP 数据包),该段中包含服务器的初始序列号(seq=server_is y),同时发送 ack 来表示确认已收到客户端的 SYN 段(ack=client_is x+1)
ACK 是确认的缩写,ACK 数据包是任何确认收到一条信息或一系列数据包的 TCP 数据包
- 第三次握手
客户端给服务器响应一个 ACK 段(在 TCP 标头中 ACK 位字段为 1 的 TCP/IP 数据包),该段中发送 ack 来表示确认已收到服务器的 SYN 段(ack=server_is y+1)。与此同时,可以将需要发送的数据一并发送(seq=client_is x+1)
二次握手与四次握手 ?
为什么不进行二次握手或者四次握手呢?
三次握手已经能够满足连接的稳定可靠,四次握手会导致浪费资源。而二次握手可能会导致只在服务器端维护了连接(产生半连接),甚至有可能会造成老的数据被当成新数据发送
- 二次握手的半连接与三次握手解决半连接
- 二次握手的收据发送与三次握手的解决方案
四次挥手
数据传输完毕后,双方都可以释放连接。最开始的时候,客户端和服务器都是处于 ESTAB 状态,然后客户端主动关闭,服务器被动关闭。
- 第一次挥手
客户端给服务器发送一个 FIN 段(在 TCP 标头中 FIN 位字段为 1 的 TCP/IP 数据包),并包含最后发送的数据(seq=client_is i),此时客户端进入 FIN_WAIT_1(终止等待1)状态
- 第二次挥手
服务器返回客户端 ACK 段(在 TCP 标头中 ACK 位字段为 1 的 TCP/IP 数据包),该段中 ack 表示确认已收到客户端的 FIN 段(ack=client_is i+1),并发送需要发送的数据(seq=server_is j),此时仅服务器能进行数据传输,此时服务器进入 CLOSE_WAIT(关闭等待)状态
- 第三次挥手
客户端在收到服务器发送的 ACK 段后就会进入 FIN_WAIT_2(终止等待2)状态。此后服务器发送一个 FIN 段(在 TCP 标头中 FIN 位字段为 1 的 TCP/IP 数据包),并包含最后发送的数据(seq=server_is a),此时服务器进入 LAST_ACK(最后确认)状态
- 第四次挥手
客户端收到服务器发送的 FIN 段后,会返回一个 ACK 段(在 TCP 标头中 ACK 位字段为 1 的 TCP/IP 数据包),同时附上自己的序列号(seq=client_is i+1)以及确认响应(ack=server_is a+1),此时客户端进入 TIME_WAIT(时间等待)状态,但此时 TCP 连接还未终止,必须要经过 2MSL(最长报文寿命)后客户端才会进入 CLOSED(关闭)状态,服务器接收到确认报文后会立即进入 CLOSED(关闭)状态
值得注意的是,TCP 的四次挥手存在“两军问题”
TCP 的流量控制
GBN or SR
GBN or SR 在我的这篇文章有提到:引流
TCP 是一个 GBN 协议还是一个 SR 协议?先给结论:GBN + SR 的混合体,一种所谓的“选择确认”
TCP 确认是累积式的,正确接收但失序的报文段是不会被接收方逐个确认的,这与 GBN 协议非常相似。但许多 TCP 的实现会将正确接收但失序的报文段缓存起来。对 TCP 提出的一种修改意见是所谓的“选择确认”,它允许 TCP 接收方有选择地确认失序报文段,而不是累积地确认最后一个正确接收的有序报文段。当将该机制与选择重传机制结合起来使用时(即跳过重传那些已被接收方选择性确认过的报文段),TCP 看起来就像我们通常的 SR 协议。因此,TCP 的差错恢复机制也许最好被分类为 GBN 协议与 SR 协议的混合体。
流量控制
流量控制通俗来讲就是接收方控制发送方,不让发送方发送得太多太快以致于让接收方的缓冲区溢出。
TCP 流量控制流程:
- 接收方在向发送方发送的 TCP 段头部的 rwnd(接收窗口)字段标识器空闲 buffer 的大小
- 发送方限制未确认字节的个数 <= 接收方发送过来的 rwnd 值,保证接收方不会被淹没
拥塞控制
拥塞原因、代价、方法
- 拥塞:太多的数据需要网络传输,超过了网络的处理能力,与流量控制不同,拥塞控制表现在分组丢失(路由器缓冲区溢出)以及分组经历比较长的延时(在路由器的队列中排队)。
- 代价:
- 流量强度越大,延时就越大,趋近 1 时延时将会趋近无限大
- 因为缓冲溢出的存在,发送方需要重传被丢弃的分组
- 链路中的长时延将会导致发送方超时而造成多余的重传
- 方法:
- 端到端拥塞控制:没有来自网络的显示反馈,端系统根据延迟和丢失事件推断是否有拥塞
- 网络辅助的拥塞控制:路由器提供给端系统以反馈信息,包括单个比特置位显示有阻塞和显示提供发送端可以采用的速率
默认因特网版本的 IP 和 TCP 采用端到端拥塞控制方法,本文也主要讲述 TCP 采用的端到端拥塞控制方法
TCP 拥塞控制
- 慢启动:初始值很低,速度很快,从 cwnd=1 开始倍增直至堵塞,将 cwnd/2 设置为阈值,再从 1 开始倍增至阈值,然后转变模式
- AIMD:达到阈值后,进行线性增、乘性减
- 线性增:当 cwnd 大于阈值时,一个 RTT(往返之间)内如果没有发生丢失事件,将 cwnd 加 1MSS ,然后继续探测
- 乘性减:超时、丢失事件发生后,将 cwnd 将为 1 ,将 cwnd/2 作为阈值,进入慢启动状态,直到达到阈值
- 快速重传事件:当收到 3 个重复的 ack 时,cwnd 减半,然后继续 AIMD
总结:
- 当 cwnd < threshold ,发送端处于慢启动阶段(ss),窗口指数性增长
- 当 cwnd > threshold ,发送端处于拥塞避免阶段(ca),窗口线性增长
- 当收到三个重复 ack 时,threshold=cwnd/2 ,cwnd=threshold+3
- 当超时事件发生时,threshold=cwnd/2 ,cwnd=1 ,进入 ss 阶段