TCP

来自WHY42
Riguz留言 | 贡献2021年4月30日 (五) 07:40的版本

TCP(Transmission Control Protocol)协议是面向连接的可靠的、基于字节流的传输层通信协议,工作在OSI模型中的第四层(传输层)上。


基本概念

OSI模型

ISO在1984年定义了网络互连的7层结构模型,分别是:

  1. 物理层(Physical Layer)在局域网传输数据帧(Data Frame),负责管理电脑通信设备和网络媒体之间的互通
  2. 数据链路层(Data Link Layer)负责网络寻址、错误侦测和改错=
  3. 网络层(Network Layer)决定数据的路径选择和转寄,将网络表头(NH)加至数据包,以形成报文。IP协议就在这一层。=
  4. 传输层(Transport Layer)把传输表头(TH)加至数据以形成数据包。=
  5. 会话层(Session Layer)负责在数据传输中设置和维护计算机网络中两台计算机之间的通信连接。=
  6. 表达层(Presentation Layer)把数据转换为能与接收者的系统格式兼容并适合传输的格式。=
  7. 应用层(Application Layer)提供为应用软件而设的接口,以设置与另一应用软件之间的通信。=

<img src="https://miro.medium.com/max/688/1*bXWAnvmLdUPi3mx5mZZn9Q.png" style="height:300px"/>

原理

在IP(Internet Protocol)层的任务仅仅是根据源主机和目的主机的地址来传送数据,数据在IP层传送时会被封装为数据包,但比较独特的是在传输数据之前无需与目的主机建立连接。IP协议提供了不可靠的数据传输机制(或者称之为“尽最大努力交付”),但无法保证数据能够准确的传输,因为数据包在到达的时候可能出现故障,包括:

  • 数据损坏
  • 丢失
  • 重复
  • 顺序错乱

IP协议不能保证可靠性,即便IPv4在数据报头中有校验和的计算,但假设计算出校验和不正确则直接丢掉错误的包,而不会通知到任一个终端节点。在Ipv6中为了快速传输已经放弃了计算校验和。而TCP协议可以提供在不同的主机的应用层之间进行可靠的、管道般的连接。整个过程是:应用层向TCP层发送数据流,TCP将数据流分割适当长度的报文段(通常受限于数据链路层的最大传输单元MTU),而后将包传输到IP层,并传送给接收端的TCP层。为了保证不丢包和顺序性,TCP给每一个包一个序号,接收端接受到包后会发送ACK信息确认;如果在往返时延(RTT)内未收到确认,那么对应的数据包就被认为已经丢失并进行重传。同时,TCP使用一个校验和来检测数据是否存在错误,在发送和接受的时候都需要计算。

运作方式

TCP协议运行分为三个阶段:创建连接、数据传送和连接终止。首先来看TCP的数据包的结构:

TCP包结构

TCP将数据封装在IP报文中进行传输。

<-------------------------------IP报文---------------------------------->
|-------IP头部--------|-------TCP头部--------|-----------TCP数据----------|

其中,IPv4下IP头部为20字节(不带选项,如果带选项可能更长),IPv6为40字节。TCP头部20字节(不带选项),TCP包的结构如下:

TCP package structure

  • 来源端口 发送连接端口,这个端口与IP报文中的IP地址组合到一起唯一标识一个TCP连接(也即Socket)
  • 目的端口 接收连接端口
  • 序列号:如果含有SYN标记,则此为最初的序列号;第一个资料的序列号将+1;如果没有则为第一个资料比特的序列号
  • 确认号:确认号为最后接收到的数据字节的序列号+1
  • 资料偏移:以4字节为单位计算出的数据段开始地址的偏移值
  • 保留位:须置位0
  • 标志位:
   - NS(ECN-nonce):ECN显式拥塞通知(Explicit Congestion Notification),是对TCP的扩展,用来允许拥塞控制的端对端通知而避免丢包。
   - CWR:拥塞窗口减,发送方降低发送速率
   - ECE:ECN回显,发送方接收到一个更早的拥塞通告
   - URG:紧急指针字段有效,很少被使用
   - ACK: 确认号字段有效,连接建立以后一般都是启动状态
   - PSH:推送,接收方应尽快给应用程序传送这个数据(没有被可靠实现或者用到)
   - RST:重置连接
   - SYN:初始化一个连接的同步序列号
   - FIN:该报文段的发送方已经结束向对方发送数据

连接创建与关闭

TCP使用三次握手(three-way handshake)来创建一个连接。这个过程是:

1. 客户端向服务端发送SYN来创建一个主动打开,客服端设定这段连接的序号为随机数 $ISN(c)$

  1. 服务端收到SYN后回复SYN/ACK,确认号为$ISN(c)+1$,而这个回复包含一个随机序号$ISN(s)$=
  2. 最后,客户端再次发送一个ACK,此时包的序号为$ISN(c) + 1$,服务端回复的确认码为$ISN(s) + 1$。这样就完成了三次握手,进入了连接创建状态=

Tcp connection flow

客户端和服务端任何一方都可以发起连接关闭的操作。这个过程如下:

  1. 主动关闭者发送一个FIN指明希望看到自己当前的序列号(K),并包含了对方最近一次的数据序列号(L)
  2. 被动关闭者发送ACK表明已经成功接收到FIN,并通知上层的应用程序连接端已经提出了关闭操作=
  3. 接着被动关闭者将变成主动关闭者,并发送FIN=
  4. 收到ACK,完成连接的关闭=

因为TCP是双工通信,实际上支持一种半关闭的操作,也就是说一方数据发送完成后关闭传输但任然保留接收数据的能力。这种情况下只有一方发送了FIN,但实际很少有程序使用这种特性。

其他需要了解的性质

由于TCP协议的设计,有一些相关的需要了解的性质如下:

  • TCP是面向流的,无法知道(或者说不关心)消息的边界。例如在一端发送时可能先发送10个字节,而后40个;但在接收端可能是每次读取10个字节或者说一次性读入,即无法知道字节写入的边界(需要上层协议支持)
  • TCP为了处理发送端和接收端的速度不匹配的问题,可以采取两种方式的流量控制,一种是基于速率(通常用于广播和组播发现),另一种是基于窗口的,通过窗口通告(或者称之为窗口更新)来更新窗口大小。
  • 对于发送端和接收端的中间网络,单靠流量控制是无法避免由于中间路由器之类的设备拥塞造成丢包的问题;所以当发送方识别到这样的丢包出现时会猜测这是由于中间网络拥塞导致的,从而开始隐式的拥塞控制。