编写Winsock程序时,你可以不知道TCP状态转换,但是如果你想知道Winsock API调用如何影响底层协议时,你需要知道它。本章将详解服务端、客户端建立以及退出时的 TCP SOCKET 状态转换情况。
TCP的状态转换过程即众所周知的TCP三次握手。
所有socket都从 CLOSED 状态开始,当服务端socket绑定完周知地址并监听后,此时socket状态变为LISTEN。当一个客户端尝试连接时,服务端将收到其发出的 SYN ,故回复 SYN_ACK 并进入 SYN_RCVD 状态。最后,客户端发送最后的 ACK ,时服务端转换为ESTABLISHED 状态。
客户端socket也从 CLOSED 开始,当建立连接时,向服务端发送一个含有 SYN 消息的数据包,然后客户端socket将进入SYN_SENT 状态,服务端收到 SYN 会对应发送确认消息:SYN-ACK。客户端收到这个回复后做出肯定回答:发送一个ACK。此时客户端socket将进入ESTABLISHED 状态。如果服务器没有及时响应而发送 SYN-ACK ,超时后时客户端socket将回到CLOSED 状态。
一旦应用在 ESTABLISHED 状态时,有两种方式来关闭。
1.积极关闭 (Active socket closure) 2.消极关闭 (Active socket closure)
如果你的应用(客户端)请求关闭,则为积极关闭,否则为消极关闭。
如果你主动申请关闭,你的应用使用closesocket() 或shutdown(第二个参数为SD_SEND)关闭连接时,
将向服务端发送 FIN ,此时你的socket变为 FIN_WAIT_1状态。
通常服务器会回复 ACK ,然后你的socket会变为 FIN_WAIT_2状态。
然后服务器关闭连接,并发送 FIN ,你的客户端收到后回复 ACK 并进入 TIME_WAIT 状态。
在积极关闭中,有另外两种方式进入 TIME_WAIT 状态。当客户端和服务端同时发起关闭时,
可能存在这两种情形:
1.客户端发送 FIN ,同时服务端发送 FIN ,此时socket进入CLOSING 状态,然后客户端回复 ACK 并进入TIME_WAIT 状态。
2.客户端发送 FIN ,同时服务端发送 FIN 并在短时间内发送 FIN_ACK,此时socket直接从 FIN_WAIT_1 进入TIME_WAIT状态。
MSL 表示最大报文段生命周期,即一个报文段在销毁之前能够存在与网络中的最长时间。每一个IP包有一个生命周期域(TTL),TTL是一个整数值,IP包没经过一个路由时TTL减一,TTL为0时该IP数据包被丢弃。一旦应用进入TIME_WAIT 状态,它保留了两倍MSL时间,使之能够发送最后一个ACK并且接收服务器发送的FIN。
服务器发起关闭请求,向客户端发送 FIN ,客户端接收后回复 ACK 并进入 CLOSE_WAIT状态。然后客户端关闭socket,向服务端发送 FIN 并进入 LAST_ACK 状态。客户端接收最后一个 ACK 后进入 CLOSED 状态。