「客户端」学习网络编程,不了解TCP协议?难怪面试被刷下去,还不来学习!( 五 )

netstat -napt 命令查看 。

TCP 连接状态查看

为什么是三次握手?不是两次、四次?
相信大家比较常回答的是:“因为三次握手才能保证双方具有接收和发送的能力 。 ”
这回答是没问题 , 但这回答是片面的 , 并没有说出主要的原因 。
在前面我们知道了什么是 TCP 连接:
  • 用于保证可靠性和流量控制维护的某些状态信息 , 这些信息的组合 , 包括Socket、序列号和窗口大小称为连接 。
所以 , 重要的是为什么三次握手才可以初始化Socket、序列号和窗口大小并建立 TCP 连接 。
接下来以三个方面分析三次握手的原因:
  • 三次握手才可以阻止历史重复连接的初始化(主要原因)
  • 三次握手才可以同步双方的初始序列号
  • 三次握手才可以避免资源浪费
原因一:避免历史连接
我们来看看 RFC 793 指出的 TCP 连接使用三次握手的首要原因:
The principle reason for the three-way handshake is to prevent old duplicate connection initiations from causing confusion.
简单来说 , 三次握手的首要原因是为了防止旧的重复连接初始化造成混乱 。
网络环境是错综复杂的 , 往往并不是如我们期望的一样 , 先发送的数据包 , 就先到达目标主机 , 反而它很骚 , 可能会由于网络拥堵等乱七八糟的原因 , 会使得旧的数据包 , 先到达目标主机 , 那么这种情况下 TCP 三次握手是如何避免的呢?
三次握手避免历史连接

客户端连续发送多次 SYN 建立连接的报文 , 在网络拥堵等情况下:
  • 一个「旧 SYN 报文」比「最新的 SYN 」 报文早到达了服务端;
  • 那么此时服务端就会回一个 SYN + ACK 报文给客户端;
  • 客户端收到后可以根据自身的上下文 , 判断这是一个历史连接(序列号过期或超时) , 那么客户端就会发送 RST 报文给服务端 , 表示中止这一次连接 。
如果是两次握手连接 , 就不能判断当前连接是否是历史连接 , 三次握手则可以在客户端(发送方)准备发送第三次报文时 , 客户端因有足够的上下文来判断当前连接是否是历史连接:
  • 如果是历史连接(序列号过期或超时) , 则第三次握手发送的报文是 RST 报文 , 以此中止历史连接;
  • 如果不是历史连接 , 则第三次发送的报文是 ACK 报文 , 通信双方就会成功建立连接;
所以 ,TCP 使用三次握手建立连接的最主要原因是防止历史连接初始化了连接 。
原因二:同步双方初始序列号
TCP 协议的通信双方 ,都必须维护一个「序列号」 ,序列号是可靠传输的一个关键因素 , 它的作用:
  • 接收方可以去除重复的数据;
  • 接收方可以根据数据包的序列号按序接收;
  • 可以标识发送出去的数据包中 ,哪些是已经被对方收到的;
可见 , 序列号在 TCP 连接中占据着非常重要的作用 , 所以当客户端发送携带「初始序列号」的 SYN 报文的时候 , 需要服务端回一个 ACK 应答报文 , 表示客户端的 SYN 报文已被服务端成功接收 , 那当服务端发送「初始序列号」给客户端的时候 , 依然也要得到客户端的应答回应 , 这样一来一回 , 才能确保双方的初始序列号能被可靠的同步 。
四次握手与三次握手

四次握手其实也能够可靠的同步双方的初始化序号 , 但由于第二步和第三步可以优化成一步 , 所以就成了「三次握手」 。


推荐阅读