问题
- 可靠的通信通常得益于在连接的每一端都有某种状态
- 问题:建立连接
你是怎么建立这个状态的? - 问题:连接断开
如何清理(重用端口等)
连接建立
3次握手
红字部分是常见的3次握手,主动方发送SYN消息,并标识第一个字节从Sa开始(active到passive的字节流)。被动方监听到后返回SYN,并标识第一个字节从Sp开始(passive到active的字节流)。主动方收到后回复ACK消息,该消息的序号为Sa+1,ACK Num为Sp+1,消息长度为0。
蓝色部分是并行打开连接,即两者同时发起连接请求。在这种情况下,总共需要发送4个包。
连接断开
- FIN位表示没有更多的数据需要发送
- 由另一终端的close()或shutdown()发起
- 两边的终端都要发送FIN消息来关闭连接
- 经典的连接关闭信息交换:
- A -> B:FIN,序列号 S A S_A SA,ack S B S_B SB
- B -> A:ack S A + 1 S_{A+1} SA+1
- B -> A:FIN,序列号 S B S_B SB,ack S A + 1 S_{A+1} SA+1
- A -> B:ack S B + 1 S_{B+1} SB+1
- 也能有并行关闭
A和B可以在最后的消息后忘记关闭socket吗?
安全清除
- 已关闭的socket的问题
- 如果网络中最终的ack丢失?
- 如果上一个连接使用的端口对马上用于新的连接?
- 解决方法:“active” closer进入TIME WAIT状态
- Active close是指在收到FIN消息之前发送FIN消息的一端
- 保留socket约2MSL的时间(2倍的最大segment的存活时间)
- 会给服务器造成一些问题
- OS有太多的socket都处于TIME WAIT状态,降低运行速度
- 技巧:发送RST(重置)命令并删除socket,设置socket选项SO_LINGER为时间0
- OS可能不会让你重启服务器因为端口正被使用(使用socket选项SO_REUESADDR来重新绑定被使用的端口号)