通过netstat -an 命令查看网络状态,分析当前socket处于的状态。
上图分为三个部分:
1)粗实线部分主动发起连接、主动关闭连接(主动发起连接的是客户端,主动关闭连接客户端、服务器都有可能);
2)虚线部分:被动发起连接、被动关闭连接(被动发起连接的是服务器,主动关闭连接客户端、服务器都有可能)
3)细实线部分:表示两端同时操作的情况。
分析:
1)首先分析粗实线部分:主动发起连接(客户端)和主动关闭连接(客户端、服务器都有可能)
- 主动发起连接的一方,从CLOSED状态 --->调用connect函数,发送SYN后,变为SYN_SENT--->connect函数返回,接收SYN、ACK,发送ACK,变为ESTANBLISHED(数据传输状态),三次握手完成。
- 主动关闭连接的一方-->调用close函数,发送FIN,变为FIN_WAIT_1--->接收ACK,变为FIN_WAIT_2(完成半关闭)-->接收FIN,发送ACK,变为TIME_WAIT--->等待2MSL时长(目的方式为了确保对端接收到最后一个ACK)变为CLOSED.
完成半关闭的时候,查看服务器和客户端的状态,主动发起关闭的状态是FIN_WAIT2,被动关闭连接一端的状态是CLOSE_WAIT状态。
FIN_WAIT_2一定是主动发起关闭请求一方的状态。
TIME_WAIT一定是主动发起关闭请求一方的状态。
TIME_WAIT用来等2MSL(linux系统下,大约为1min),原因是不确定对端是否收到发送的ACK,所以要等,确保最后一个ACK能被对端收到。
2)接下来分析虚线部分,虚线部分是对应上述的粗实线部分的:被动连接和被动关闭连接(客户端、服务器都有可能)
- 被动发起连接的一方,从CLOSED状态 --->调用accept函数,处于LISTEN状态---->接收SYN,发送SYN、ACK变为SYN_RCVD
-->接收ACK,accept函数返回,,变为ESTANBLISHED
- 被动关闭连接的一方,接收FIN,发送ACK变为CLOSE_WAIT(等待关闭,对端已完成半关闭)-->调用close函数,发送FIN,变为LAST_ACK状态-->接收到ACK变为CLOSED.
从时序图中可以看出,发送两端发送FIN后的状态都发生了变化。
3)小细线部分,两端同时操作的情况。
说明:以下几个状态在经常可以看到:
处于LISTEN态的肯定是服务器端,
处于TIME_WAIT态的肯定是主动发起关闭的一端;
主动关闭的一方已经半关闭了,并且收到了FIN,发送了ACK时处于的状态,其实工作已经完成,但在等对端2MSL时长。
当发现,出现这种状态的时候,需要等待一会,过了2MSL,这个状态就会自动消失,而不管对端是否收到lastack。
处于CLOSE_WAIT的一定是被动关闭连接的一端,此时对端已完成半关闭,本端如果没有调用close函数,将一直处于本状态?
处于LAST_ACK的一定时被动关闭连接的一端,等待接收最后一个ACK,接收后为CLOSED.
2MSL:Maximum Segmen Lifetime 2倍的最大段生存时间(linux系统下大约是1分钟的时间)
小结:由上图可以看到,建立连接的3次握手,有4个点;断开连接的6个点,每个点都对应一种状态,可以结合上图来记忆状态改变的情况。
主动发起连接(关闭连接)发完SYN(FIN)状态就发生变化;
被动发起连接(关闭连接)接收SYN(FIN)并回复ACK之后转态才发生变化。
主动关闭的一方:FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT ;
被动关闭的一方:CLOSE_WAIT、LAST_ACK。