搞linux后台开发,必须掌握Stevens的著作《UNIX网络编程》里提及的大量知识点,所以我特意从网上购买了一套(O(∩_∩)O)。
面对厚厚的卷一,不实践,不记笔记,我觉得很难有所提升,故我决定将自己看书时候觉得重要的知识点和一些总结记录下来。
今天的笔记是关于TCP状态的。
TCP状态变迁主要发生在三次握手或四次挥手的时候,而且在此期间客户端client和服务器server的TCP状态变化是不同的,大家如果有兴趣可以去google或者看原书,这里我就不再画他们的状态图了。不过有些状态需要我们去研究下它们的意义,以及计算机在此状态下在干什么。
先来看三次握手和四次挥手阶段client和server的TCP状态含义。
三次握手阶段:
正常三次握手情况下:
client的tcp状态变迁应该是:CLOSED→SYN_SENT→ESTABLISHED
server的tcp状态变迁应该是:CLOSED→LISTEN→SYN_RCVD→ESTABLISHED
你也许会奇怪,那为什么在client的tcp状态中出现了SYN_RCVD状态,在server的tcp状态中出现了SYN_SENT状态?
一般来说,我们把主动率先发起连接请求的一方叫做client,而被动接受连接请求的一方叫做server。那么有没有可能是双方同时主动发起连接请求呢?
这个是可能的,但是非常罕见,并且如果是双方同时发起连接请求,三次握手会变成四次:
此时A、B双方既是client也是server,任何一方不会出现LISTEN状态。
再来看四次挥手阶段:
在四次挥手阶段,TCP的状态变迁已经不再根据client还是server进行区分,而是看是谁率先主动发起关闭请求,谁被打接收关闭请求了。也就是说client可能是主动关闭的一方,也可能是被打关闭的一方,server同理。
这里需要说明下FIN报文的含义。FIN报文的含义表面看是一方发给另一方的关闭请求,但是更具体的含义是告诉对方自己已经没有数据要发送,如果对方也没有新数据要发送给自己,那么本次连接便可终止,双方tcp状态回到CLOSED。这也解释了为什么主动关闭方会出现FIN_WAIT_1和FIN_WAIT_2的状态。
FIN_WAIT_1和FIN_WAIT_2状态表明主动关闭方在等待被动关闭方发送完所有数据,在等待被动关闭方发送它的FIN报文;而被动关闭的一方,在发送给主动关闭方FIN报文前,一直处于CLOSE_WAIT状态。CLOSE_WAIT状态表明被动关闭方正在等待上层应用程序关闭,一旦应用程序关闭,被动关闭方将发送FIN报文给主动关闭方,而自己的TCP状态转为LAST_ACK,等待主动关闭方的确认。
至于CLOSING状态,其实类似于三次握手阶段的同时打开现象,它是在四次挥手阶段双方几乎同时主动关闭。
最后着重说明下TIME_WAIT的意义:
(1)可靠的实现TCP的全双工连接的终止
被动关闭方处于LAST_ACK或者CLOSING状态时,会等待主动关闭方发来(对自己先前发送的FIN报文的)确认,如果确认丢失,被动关闭方会重发先前的FIN报文给主动关闭方,若没有TIME_WAIT状态,或者TIME_WAIT状态不够长,那么主动关闭方在CLOSED状态时会忽视新接收到的FIN报文,导致被动关闭方不能可靠的关闭。
(2)允许老的重复分组在网络中消逝
由于路由选择等原因,网络中会残留双方先前通信的旧报文分组。如果在这些旧的重复报文分组消逝前,完全关闭了主动方的端口,也即端口处于CLOSED的状态,若此时又在此端口上新开一个连接,恰巧那些旧的报文分组又刚好到达,那么计算机就会把这些报文分组当成是新连接的分组,会导致解析错误。所以为了避免这一错误,通常将TIME_WAIT持续时间设置成MSL时间的2倍,这样足以让那些旧的报文分组在存活MSL时间后就消逝。