计算机网络中连接管理模块还是非常重要的, 因为这里涉及到传说中的 “三次握手和四次挥手的概念”; 上过计算机网络的应该都知道这个概念的重要性, 其实连接管理说的就是如何建立连接 (三次握手), 如何断开连接 (四次挥手); 因为关于它的过程特别容易记混或者忘记, 因此我是以这样的方式写的这篇博客, 如下⬇︎⬇︎⬇︎⬇︎⬇︎
🤝 三次握手建立连接
建立连接的过程就是一个投石问路的过程, 下面以呼叫器的测试为例子进行介绍, 当前小明和小红不知道自己的呼叫器是否能够正常使用, 如下图所示:
说明:
- 本质上, 当小明的 syn 到达小红那的时候, 小红的内核就会第一时间进行应答 ack, 同时也会第一时间发起 syn, 这两件事是同时触发的, 因此也就没必须分成两次传输.
- 关于上述过程中涉及的状态:
-
- LISTEN: 当创建了 Socket 实例的时候, 就进入了 LISTEN 状态; 类似于说明我这边一切正常, 可以接收消息;
-
- ESTABLISHED: 双方已经互通, 可以进行会话了.
总之, 三次握手的目的就是来确认两个主机之间的传输是否是正常的, 尤其是两者的发送能力和接收能力是否是正常的; 其实这也是表明 TCP 可靠性的体现之一.
👋🏻 四次挥手断开连接
断开连接的过程比较容易好理解, 如下图所示:
这里就有个疑问, 在建立连接的时候 syn 和 ack 可以合并到一起进行发送, 那这里的 FIN 和 ack 为什么就不能合并到一起发送呢???
对于小红来说, ACK 和 FIN 的触发时间是不一样的, 理由如下:
- 小红只要是收到了 FIN 就会立即触发 ACK 进行确认应答, 这个事情是内核完成的;
- 小红发送 FIN 实际上是用户代码控制的, 如代码中的 socket.close(), 出现这样的操作后才会触发 FIN;
- 当然也有可能小红的代码出问题了, 一直不发送 FIN 结束报文段, 但是 socket 是会被 GC (垃圾回收机制) 回收的, 这时候也会关闭释放对应的文件, 这个操作也不是那么的及时; 也有可能代码中没有调用 close, 但是进程结束了, 这时候 PCB 就会被销毁, PCB 上的文件描述符也就没了, 这时候也会触发 FIN.
断开连接的过程也有两个状态:
- CLOSE_WAIT: 服务器收到 FIN 之后进入的状态, 等待用户代码调用 close 来发送 FIN;
-
- 当出现大量的 CLOSE_WAIT 状态, 大概率是服务器没有正确的关闭 socket, 导致四次挥手没有正确完成, 只需要加上对应的 close 即可.
- TIME_WAIT: 客户端收到 FIN 之后进入 TIME_WAIT, 这个状态存在的意义主要就是为了处理最后一个 ACK 丢包;
-
- 即使进程已经退出了, TIME_WAIT 仍然会存在, 因为 TCP 连接不会立即就销毁掉;
-
- 如果等待一定时间后还是没有重传 FIN 过来, 才会真正销毁.