TCP

TCP首部

TPC首部最小为20Byte,这20Byte分为5行,每行4个Byte,也就是32个bit(一个int)

源端口和目的端口

  • 源端口号:16位的源端口中包含初始化通信的端口
  • 目的端口号:16位的目的短裤定义传输的目的,这个端口指明报文接收计算机上的应用程序地址接口

计算机通过端口号识别访问哪个服务,发送方端口号是随机端口,目标端口号决定了接收方哪个程序来接收

序列号 Sequence Number

TCP用序列号对数据包进行标记,以便在到达目的地后重新重装,假设当前的序列号为,发送数据长度为,则下次发送数据时的序列号为。在建立连接时通常由计算机生成一个随机数作为序列号的初始值

确认号 Acknowledgment Number

占4个Byte,表示期望收到对方下一个报文段的序号值。TCP的可靠性,是建立在每一个数据报文都需要被确认收到的基础之上的

数据偏移 Offset

占4bit,指出了TCP首部的长度,它指出TCP报文段的数据起始处距离TCP报文的起始处有多远,一个数据偏移量为4Byte,由于Offset最大为15,所以TCP首部的最大长度为60Byte

保留 Reserved

6bit不知道干什么用的

标志位 TCP Flags

一共有6个,分别占1bit,每一位只能取0或1

  • ACK:确认序号有效
    • 当ACK=1时,确认号有效。一般把携带ACK标志的TCP报文段称为确认报文段
    • 当ACK=0时,确认号无效
  • RST:重置连接
    • 当RST=1时,表示TCP连接出现严重错误,需要释放并重新建立连接。一般称携带RST标志的TCP报文段为复位报文段
  • SYN:发起一个新连接
    • 当SYN=1时,表示这是一个请求连接报文段。一般称携带SYN标志的报文段为同步报文段
    • 如果对方同意建立连接,则应在响应的报文段中使SYN=1和ACK=1
  • FIN:释放一个连接
    • 当FIN=1时,表示此报文段发送方的数据已经发送完毕,并要求释放TCP连接,一般称携带FIN的报文段为结束报文段
    • 在TCP四次挥手释放连接的时候,就会用到该标志

窗口大小 Window Size

指出现在允许对方发送的数据量,它告诉对方本端的TCP接受缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度

校验和 TCP Checksum

占2个Byte,由发送端填充,接收端对TCP报文执行CRC算法,以检验TCP报文段在传输过程中是否损坏,如果损坏则丢弃

检验范围包括首部和数据两部分,这也是TCP可靠传输的一个重要保障

紧急指针 Urgent Pointer

占2个Byte,仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数,当URG=1时,发送方TCP就把紧急数据插入到报文段数据的最前面,而在紧急数据之后的数据仍然是普通数据

连接建立与释放

三次握手

TCP连接必须经过三次“对话”才能建立起来

对于客户端来说,发出①,收到②,确认了服务端可以正常收发信息

对于服务端来说

  • 收到①,确认了客户端可以正常发消息

  • 发出②,收到③,确认了客户端可以正常收发消息

四次挥手

挥手请求可以是客户端,也可以是服务端发起的,上图假设是客户端发起的

由于TCP协议是全双工模式,这就意味着,在关闭连接时,当某一端觉得自己的数据都发完了,发出FIN报文后,不代表另一端的数据都发送完毕了。当端收到FIN报文并返回ACK报文时,表示端知道端没有数据要发了,但是端还有往端发送数据的能力,所以端很有可能不会立即关闭SOCKET,直到端的数据也发送完毕为止

为什么要等待2MSL

MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间

  • 保证TCP协议的全双工连接能够可靠关闭):如果端没有收到端的ACK报文,那么端就会在超时之后重新发送FIN,如果此时端已经关闭了,那么重发的FIN就找不到对应连接,从而导致连接错乱,所以端发送完最后的ACK后不能立即进入CLOSED状态,而要保持TIME_WAIT一段时间,增加容错
  • 保证这次连接的重复数据段从网络中消失):如果端发送最后的ACK后直接进入CLOSED状态,然后又向端发起一个新连接,这时不能保证新连接与刚关闭的连接的端口号是不同的,这些延迟数据在建立新连接之后到达端,由于新老连接的端口号和IP都一样,TCP协议就认为延迟数据是属于新连接的,就有可能导致混乱

流量控制

在网络通信中,我们都会希望数据的传输效率更高一些,让通信更加流畅。但是,如果发送方的发送速率太快,可能会导致接收方来不及接收和处理数据,造成网络资源浪费

流量控制就是一种接收方,针对发送方发来的数据太多,采取的一种控制机制。以下只考虑这样的一条单向通信

建立TCP连接时,会将自己的接受窗口大小(RWND)告知会把自己的发送窗口大小也设置为RWND。在交流的过程中,会不时传递给一个二元组:,表示现在发送范围的数据就足够了,端进程的收取数据速度影响

在极端情况下,会变成停止发送任何数据给。如果过了一段时间,又重新大于了,那么将发送报文段通知,如果又不巧在网络中丢失了,将导致:

  • 端在等待端重设其大于
  • 端在等待端传送这部分数据

为了防止这种意外发生,我们设置端受到端的时会自动启动一个持续计时器,当超时时,如果还没有接收到来自端的更新报文段,则会发送一个零窗口探测报文段(携带1Byte数据),当端收到这个TCP报文段后,会给端回复一个的更新,如果,那么端就可以继续发送数据;如果,则重新启动一个,重复上述步骤

拥塞控制

在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络性能就会变坏,这种情况就叫做网络拥塞

若出现拥塞而不进行控制,整个网络的吞吐量将随输入负荷的增大而下降

在讨论拥塞控制时,我们做出如下假设:

  • 数据是单方向传送,而另一个方向只传送确认
  • 接收方端总是有足够大的缓存空间,因而发送方端发送窗口的大小由网络的拥塞程度来决定
  • 以TCP报文段的个数为讨论的单位,而非以字节为单位

在这里我们引入拥塞窗口(CWND),它是端的一个内部参数,端的最大发送范围是由RWND和CWND中较小的那一个确定的,即,大体策略是如果没有出现拥塞,扩大;否则缩小

慢启动

拥塞避免:当窗口扩大到一定程度后(达到慢启动门限,ssthresh,slow start threshold),转变为线性扩大窗口,

有时,个别报文段会在网络中丢失,但实际上网络并未发生拥塞,然而我们仍然会直接把CWND重设为1,降低了传输效率

快速重传端发送号报文端后,端接收到号报文,返回对号报文的确定,在端接收到之前,就可以把发出去了

快速恢复:假设端收到了,说明在网络中丢失了,并且往后有至少个报文端是收到了的,说明丢包不是因为网络发生拥塞

  • 端将ssthresh值和CWND设置为当前的一半,并开始执行拥塞避免算法
  • 也有的实现是让CWND=ssthresh+3