TCP的连接

TCP是面向连接的协议,它基于运输连接来传送TCP报文段
TCP运输连接的建立和释放,是每一次面向连接的通信中必不可少的过程

  • TCP运输连接有以下三个阶段:
    • 通过“三报文握手”来建立TCP连接。
    • 基于已建立的TCP连接进行可靠的数据传输。
    • 在数据传输结束后,还要通过“四报文挥手”来释放TCP连接。

三报文握手-建立TCP连接

  • TCP客户:主机中主动发起 TCP 链接的进程
  • TCP服务器:另一台主机中被动等待 TCP 链接的进程

TCP三报文握手-建立连接需要解决的问题

  • 使TCP双方能够确知对方的存在。
  • 使TCP双方能够协商一些参数(例如最大报文段长度、最大窗口大小、时间戳选项等)。
  • 使TCP双方能够对运输实体资源进行分配和初始化。运输实体资源包括缓存大小、各状态变量、连接表中的项目等。

TCP三报文握手流程

完成握手需要在两台主机间交换三个报文段

第一次握手

  1. 最开始两个的 TCP 进程都处于关闭状态
  2. TCP服务器(接收方)进程首先创建传输控制块TCB,用来存储TCP链接中的一些重要信息,例如:
  • TCP连接表
  • 指向发送
  • 接收缓存的指针
  • 指向重传队列的指针
  • 当前的发送和接收序号
  1. 然后,TCP服务器进程就进入监听状态,等待 TCP 客户进程的连接请求。(被称为被动打开连接
  2. TCP客户(主动发起方)进程也要先创建传输控制块TCB,向TCP服务器进程发送TCP连接请求报文段,并进入同步已发送状态。(主动打开连接
  3. TCP连接请求报文段和TCP连接请求确认报文段首部中的同步标志位SYN的值必须设置为1
    1. TCP规定同步标志位SYN被设置为1的报文段(例如TCP连接请求报文段和TCP连接请求确认报文段)不能携带数据,但要消耗掉一个序号
    2. 按上述规定,TCP连接请求报文段不能携带数据(即没有数据载荷),但是会消耗掉序号x。
    3. 因此,TCP客户进程下一次发送的TCP报文段的数据载荷的第一个字节的序号为x+1

第二次握手

  1. TCP服务器(接收方)发送TCP连接请求确认报文段,进入同步已接收状态
  2. TCP连接请求确认报文段首部中的同步标志位SYN 和确认标志位ACK的值都设置为 1
  3. 序号seq字段被设置了一个初始值y,作为TCP服务器进程所选择的初始序号
    1. TCP规定同步标志位SYN被设置为1的报文段(例如TCP连接请求报文段和TCP连接请求确认报文段)不能携带数据,但要消耗掉一个序号
    2. 注意这个seq的值是TCP服务器随意选择的初始序号,和其他报文段中的值无关(但是第三次握手中的ack由此决定)
  4. 确认号ack字段的值被设置为x+1,这是对TCP客户进程所选择的初始序号x的确认

第三次握手

  1. TCP客户(主动方)发送针对TCP连接请求确认报文段的普通TCP确认报文段,并进入连接已建立状态
  2. 确认标志位ACK的值被设置为1,表明这是一个普通的TCP确认报文段。
  3. 因为TCP客户进程之前发送的TCP连接请求报文段的序号为x,该报文段虽然不能携带数据,但要消耗掉一个序号。因此TCP客户进程发送的第二个报文段的序号为x+1
  4. 确认号ack字段的值被设置为y+1,这是对TCP服务器进程所选择的初始序号y的确认(也就是第二次握手中,TCP服务器随意选择的seq字段)
  5. TCP服务器接收到TCP客户的普通确认报文段后,也进入连接已建立状态

TCP两报文握手不可行的原因

QUESTION

第三个TCP报文段是否多余,能否只用两报文握手

  • TCP客户进程发送TCP连接请求报文段,若该报文段长时间滞留,将会超时重传(这个重传在图示底部到达)
  • 这将导致TCP客户发送超时重传TCP连接请求报文段
  • 重传的TCP连接请求报文段,使得TCP服务器发送TCP连接请求确认报文段,进入”连接已建立状态”
  • TCP客户收到第二次握手的确认答复后,进入”连接已建立状态”,开始进行数据传输
  • 双方的数据传输完成了,释放连接后,都进入了”关闭状态”
  • 但原先滞留的报文到达服务端,会将其误认为未客户进程继续建立连接
  • 然后实际上,TCP客户已经处于关闭状态,不会理会该报文段,但TCP服务已进入连接状态,即等待接收数据,这将浪费服务器的资源

故使用三次是为了防止建立连接时,防止失效的连接请求报文突然又传送到了服务器,导致错误

三次握手时出现丢包

第一次握手丢包

假设第一个包丢了,客户端发送给服务端的 SYN 包丢了(简而要之就是服务端没接收到客户端的 SYN 包),客户端迟迟收不到服务端的 ACK 包,那会周期性超时重传,直到收到服务端的 ACK

第二次握手丢包

假设第二个包丢了,服务端发送的 SYN+ACK 包丢了(简而要之就是客户端没接收到服务端的 SYN+ACK 包),服务端迟迟收不到客户端的 ACK 包,那会周期性超时重传,直到收到客户端的 ACK

第三次握手丢包

假设第三个包丢了(ACK 包),客户端发送完第三个包后单方面进入了 ESTABLISHED 状态,而服务端也认为此时连接是正常的,但第三个包没到达服务端

  • 如果此时客户端与服务端都还没数据发送,那服务端会认为自己发送的 SYN+ACK 的包没发送至客户端,所以会超时重传自己的 SYN+ACK 包
  • 如果这时候客户端已经要发送数据了,服务端接收到了 ACK + Data 数据包,那自然就切换到 ESTABLISHED 状态下,并且接收客户端的 Data 数据包
  • 如果此时服务端要发送数据了,但发送不了,会一直周期性超时重传 SYN + ACK,直到接收到客户端的 ACK 包

随机生成序列号

一方面为了安全性(随机 ISN 能避免非同一网络的攻击),另一方面可以让通信双方能够根据序号将「不属于」本连接的报文段丢弃