序号可以区分报文,应答报文的**确认序号是要应答的报文的序号加一。报文的发送方在收到确认序号后,就知道确认序号之前的数据都被接收方接收了。**比如 A 给 B 发报文,B 给 A 的确认序号是 1001,那么 A 就知道 B 收到了序号为 1~1000 的数据。 一个报文为什么既需要序号,又需要确认序号呢?
经过第一、二次握手时,主机 A 认为连接已经建立好了,并向主机 B 发送 ACK 报文, 主机 B 在收到 主机 A 发送的 ACK 报文后,才认为连接建立好了,也就是说,主机 A 和 主机 B 认为连接建立好的时间点是错开的。
如果主机 A 发送的 ACK 报文丢包了,主机 B 认为连接还没有建立好,但 主机 A 并不知道这一情况,就向 主机 B 发送数据了,这时候主机 B 就需要告诉主机 A 连接还没有建立好,所以 主机 B 向主机 A 发送RST 报文 ,要求主机 A 关闭与主机 B 建立好的连接,重新与主机 B 进行三次握手。
通信双方是谁先发起连接的呢?
谁先调用 connect 函数,谁就先发起连接。客户端发送 SYN 置为1的报头后,只有处于 listen 状态(即,调用了listen函数)的服务器才可以受理 SYN 置为 1 的报文,并回复 ACK 置为 1 的报文,如果服务器没有处于 listen 状态,就会丢弃 SYN 置为 1 的报文。connect 函数在三次握手期间,一直阻塞等待,等待三次握手的结果,三次握手成功 connect 返回值为 0,失败则返回值为 -1.
主机 A 收到 主机 B 的 ACK 报文,说明主机 A 确认 主机 B 既可以接收消息(因为主机B收到了 SYN 报文才会发 ACK 报文),也可以发消息(主机 B 发了 ACK 报文),但是主机 B 还无法确认主机 A 是否可以接收消息,当主机 A 向 主机 B 发送 ACK 报文时,主机 B 确定了主机 A 可以接收消息,那么主机 A 和主机 B 都是可以接收消息和发消息的,就可以保证全双工。也就是说,三次握手是确认全双工的最小次数。一次握手和两次握手无法确认全双工,而更多的握手次数会消耗网络资源,所以三次握手是最合适的。
2、我们知道连接的维护是需要成本的,如果大量的主机向主机 B 发起连接,这些连接只是经过一次,或者两次握手,服务器无法知道哪些连接是成功的,哪些连接是失败的,但是服务器需要同时维护成功和失败的连接,那么服务器就会出现很多闲置连接(已经建立但长时间未进行数据传输或操作的连接),从而消耗服务器的资源。
3、其实三次握手,也可以看作四次握手,只是中间的两次握手,即主机 B 向主机 A 的 ACK 和 SYN 报文,被合并为捎带应答报文了。
断开连接,应该看作 主机 A 与 主机 B 断开连接,主机 B 也和主机 A 断开连接。主机 A 与主机 B 断开连接时,意味着 主机 A 已经没有数据要发给主机 B 了,主机 A 要关闭发送缓冲区了,但是 主机 B 可能还要主机 A 发消息,或者有的报文还在网络中阻塞,所以需要等消息都被接收后,主机 B 才发报文,与主机 A 断开连接。所以在中间两次挥手之间,需要等待一段时间,等待消息的到达。