您的位置:首页 > 理论基础 > 计算机网络

TCP状态转换流程

2013-04-14 11:22 225 查看
TCP一次Server和Client建立连接,关闭连接的完整流程图如下所示:



实线代表客户端流程,虚线代表服务端流程。
client:
1. 发起连接请求,三次握手中的第一次,client socket进入SYN_SENT状态

3. 收到server对于第一次握手请求包的ack应答(同时包含server的连接建立请求),发送client对于server连接建立请求的ack响应(第三次握手),client socket进入ESTABLISHED状态

5. 发起断开连接四次握手的第一个表示请求断开连接的FIN包,client socket进入FIN_WAIT_1状态

8. 如果收到了server发来的对于FIN包的ACK,但是没有收到server发来的FIN,则client socket进入FIN_WAIT_2状态

9. 如果收到了server发来的FIN,则client socket进入CLOSING状态

11. 发送对于server发来的连接关闭请求FIN包的ACK应答,随后client socket进入TIME_WAIT状态(最终状态)

12. 如果同时收到了server发来的对于FIN的ACK应答,以及server发来的FIN,则直接进入TIME_WAIT状态(最终状态)

server:
2. 收到client连接建立请求后,发送应答包(第二次握手),同时在应答包中携带syn=1标识标识同样请求与client建立连接,server socket进入SYN_RCVD状态,此时client到server建立了一条半双工链路
4. 收到client发来的第三次握手ack响应包后,server socket也进入ESTABLISHED状态,此时client与server间建立了全双工链接
6. 收到client发来的FIN包后,发送ack响应包,此为断开连接四次握手的第二次,server socket进入CLOSE_WAIT状态
7. 由于HTTP是双向连接,向client发送断开请求的FIN包,此为断开连接四次握手的第三次,server socket进入LAST_ACK状态(最终状态)
这里有两个问题需要说明一下:
1) 为什么需要三次握手而不是两次
官方的说法是是一种面向连接的、可靠的、基于字节流的运输层(Transport layer)通信协议。是专门为了在不可靠的互联网络上提供一个可靠的端到端字节流而设计的。既然网络是不稳定的,因此TCP所有的沟通都是靠请求-应答模式,即发出的请求一定要获得对方确认应答后方可达成协议,而TCP是全双工链接,即client可以主动向server发出数据,server也可以向client发出数据,因此就需要为client到server的单向数据传输产生一组请求-应答序列,同时也要为server到client的单向数据传输产生一组请求-应答序列,而server对于client请求的ack和server向client发出的请求seq可以放在一个包中发送,因此就产生了三次握手(第二次握手干了两件事情)。而对于链接断开而言,也需要一次把两个方向的链接关闭,因此也需要两组请求-应答序列,然后不同的是,关闭连接可能只需要关闭一个方向,即client端也许不需要向server端传输数据了,而server端还有数据没有发送完成,因此就两组关闭的请求-应答共四次操作无法合并,就产生了四次握手的断开过程。
2) 为什么会有TIME_WAIT状态
首先要解释一个概念MSL(Max Segment Lifetime)是指一个IP数据报在网络上的最大有效生存时间。RFC 1122的规定是2分钟,而Berkeley的实现是30秒,也就是说2MSL是1~4分钟。由于网络的不稳定,包丢失的原因很复杂,例如路由器宕机,或者两个路由之间的链路断开等等,在网络出现故障的这段时间内,发送方由于没有在规定时间内收到应答包而重发了之前的数据包,重发的数据报也正确的传递到了对端,不巧的是由于网络状况的恢复,之前未准时到达(超过MSL)的数据报又被送到的目的主机,因此TCP协议需要对这种情况进行处理,因此就产生了TIME_WAIT这个状态。
再来看另一种情况,在两台主机12.106.32.254端口1500和206.168.112.219端口21之间存在一条TCP连接,在连接断开的四次握手中,前三次握手都成功发出了请求和应答,最后一次ACK没有及时送达。此后在同样的两台主机和同样的端口之间又建立起了一条链接,并已进入正常的数据交互状态,突然上次链接的断开的最后一次ACK包莫名其妙的又送达了,而此时的命令会被当做第二次链接所发出,这显然是一次错误。为了避免这种错误,TCP链接在关闭以后都会进入TIME_WAIT状态并持续2MSL时间,让丢失包以及丢失包的应答包在网络上失效过期,从而避免了同样的IP+Port的链接不会受到上次链接的影响。
另一个原因是为了解决链接断开时的丢包问题,假如client对于server发送的FIN包所发出的ACK应答包丢失,server会再次发送FIN,而如果之前client发送完最后的ACK后直接清除掉socket,那么再次收到server的重传的FIN包后就只能发送RST了,因此TIME_WAIT的另一个目的是为了保持状态,为TCP断开容错提供机会。
linux下通过命令netstat可以查看目前机器的网络连接状况:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: