网络编程中的TCP——TCP的连接的建立、关闭、状态转移
TCP连接的建立和关闭
wireshark捕获数据:
TCP三次握手+四次挥手的时序图:
三次握手:
- 报文段1包含
SYN
标志,这是一个同步报文段,表示发起连接请求,包含自己起始的序号值0;- 报文段2是服务端同意建立连接,发送了自己的起始序号并对第一个报文进行了确认;
- 报文3是对服务端第二个报文的确认;
四次挥手:
- 报文14:由客户端发起了关闭连接的请求,带有
FIN
标志位,以及此时的序号和对服务器上一个报文的确认;- 报文15:服务器确认了客户端的关闭请求,此时进入半关闭状态;
- 报文16:服务器发出断开连接请求,开始等待客户端最后一个确认;
- 报文17:客户端进行最后的确认;
半关闭状态
TCP是全双工的,所以允许两个方向的数据传输单独关闭。也即是通信的一端可以发送结束报文给对方,告知对方本端已完成数据的发送,但是允许继续接收来自对方的数据,直到对方也发送报文段关闭连接
以上面那个例子来说,客户端主动发起了关闭请求,在服务器返回确认之后,就进入了半关闭状态,客户端不会继续向服务端发送新的数据,但是还可以接收服务端的数据
TCP状态转移
上图描述了完整的TCP状态转移,下面是状态转移时序图:
三次握手建立连接:
- 客户端和服务器初始都处于
CLOSED
状态;- 例子中由客户端发起连接请求
SYN
,发送完后客户端变成SYN_SENT
状态;- 服务器开启之后首先变成
LISTEN
状态,在接收到客户端的SYN
后变成SYN_RCVD
状态;- 服务器发送
SYN+ACK
,客户端接收到之后,变成ESTABLISHED
状态,发送最后一个ACK
;- 最后服务器收到
ACK
之后也变成ESTABLISHED
状态,建立连接完成;四次挥手:
- 例子中由客户端首先发起关闭连接请求,客户端发送完
FIN
后首先变成FIN_WAIT_1
状态;- 服务器收到关闭连接的请求之后变成
CLOSE_WAIT
状态,然后发送ACK
表示同意关闭连接;- 客户端收到服务器的
ACK
进入半关闭状态,FIN_WAIT_2
;- 此时客户端不会继续发送数据,但如果服务器还有数据,服务器会继续发送数据;
- 服务器发起关闭请求,进入
LASK_ACK
状态,表示等待客户端发送最后一个ACK
;- 客户端收到
FIN
请求,进入TIME_WAIT
状态,发送最后一个ACK
;- 服务器在收到最后一个
ACK
后首先进入完全关闭状态;
TIME_WAIT
- 处于
TIME_WAIT
状态要等待2 * msl
才能完全关闭,原因如下:
- 可靠的终止TCP连接;
- MSL是报文段在网络中最大生存时间,2MSL保证网络上两个传输方向上尚未被接受到、迟到的TCP报文段都已经消失,保证新的连接在这个端口建立起来之后不会收到上一个连接的数据;
TIME_WAIT
是第一个主动发起关闭连接的一端才会有的状态,如果是服务器先发起关闭连接的请求,在收到对方的关闭请求后也会变成TIME_WAIT
状态;- 处于
TIEM_WAIT
的这个端口不能立即被用来建立新的连接,要等连接彻底关闭;
- 对于客户端来说,处于
TIME_WAIT
状态的端口无法立即重新使用不是什么问题,因为客户端一般使用系统自动分配的临时端口号来建立连接,一般不会刚好分配到程序上一次用到的端口;- 但是对于服务器来说,他总是使用一个固定端口。如果服务器程序刚刚关闭后又希望立即重新启动,就要等待2MSL,避免的方式是可以在创建socket时升值
SO_REUSEADDR
来强制进程可以立即使用处于TIME_WAIT
状态的端口;