TCP连接的建立
三次握手
- 服务器端准备好接收外来的链接,通过该socket、bind、listen3个函数完成,为被动打开
- 客户端通过connect函数主动建立连接,通过发送一个SYN(带序号)
- 服务器确认(ACK)客户的SYN,确认序号为服务SYN的序号加1,同时发送一个SYN(带序号)
- 客户端确认(ACK)服务的SYn,确认序号为服务SYN的序号加1.
如上就是我们通常所说的三次握手
TCP连接的终止
四次握手
- Client调用close主动关闭(通常是Client,也可以是server)。发送一个FIN(带序号)。进入FI_WAIT1状态
- 接收到FIN的对端执行被动关闭。发送ACK确认。然后进入CLOSE_WAIT。对端接收到ACK进入FIN_WAIT_2。此时为单方向关闭。
- 对端调用close执关闭。发送FIN(带序号)。进入LAST_ACK状态。
- 接收到FIN的client发送ACK确认,进入TIME_WAIT状态。
- Server接收到ACK之后进入CLOSED状态。完成连接的关闭。
如上为连接关闭的四次握手。
CLOSE_WAIT
Server接收到Client的FIN回复ACK之后进入CLOSE_WAIT状态。此时Client到Server的连接关闭。Client不能向Server发送数据。而此时Server仍可以向Client发送数据。
即此时为单向的连接关闭。需要Server也执行close关闭,才能转入之后的状态。
有时我们发现server有大量的close_wait,原因就是对方关闭了连接,而这边由于忙于读写或其他原因,没有执行关闭。
TIME_WAIT
Client端接收到Server的FIN发送相应的ACK之后,进入TIME_WAIT状态。该状态的持续时间最长为MSL(maximum segment lifetime)的两倍,即2MSL。
RFC1122的建议值为2分钟,而Berkeley的传统实现为30秒。所以其持续时间在1分钟到4分钟之间。
其存在是为了保证最后的ACK可以成功达到。否则会在MSL之后,Server重新发送FIN,从而触发其重新发送ACK。最长为2MSL的时间。这个是最主要的理由。
还有一个理由是允许老的重复segment在网络中消逝:
考虑如下一个场景,在A的端口port1和B的端口port2建立了TCP连接,然后关闭了连接。为了保证过一段时间,我们还可以在A的端口port1和B的端口port2之间可以
建立连接。我们应该避免之前的在该连接上的老的分组再出现。为做到这一点,TCP不给处于TIME_WAIT状态的连接发起新的连接。TIME_WAIT的状态持续时间为2MSL,
这样每个方向上的数据的最大存活时间为MSL。这样保证成功建立一个TCP连接时,来自该连接的先前的老的重复分组都已经在网络中消逝了。