TCP的三次握手和四次挥手
TCP是一种可靠的,发送和接收方双方面向连接的数据传输控制协议。保证了数据传输的可靠性是可控的。避免在传送过程中发生丢包后接收方数据缺失。实现了这种可靠性的方式是:发送方将每一个数据包按序编号进行发送,接收方在每收到一个包,便向发送方发送对应的确认接收的ack应答包,发送包通过接收该ack应答来确定该包已经被接收。这种方式下无论是发送方的数据包丢失,还是接收方的ack确认包丢失,发送方都接收不到这个ack确认包,一段时间后,发送方会重新发送,直到这个包确认被接收。
三次握手
为了保证在连接开始数据传输就是可靠的,TCP需要经过三次预先的连接来检测连接双方是否据有相应的数据接受与发送能力,任意一方在尝试握手的过程中连接异常,本次握手都不能成功完成。这就是经典的三次握手。三次握手除了建立一个可靠的连接,还会确定双方发包的初始序号,为将来包的发送做准备。
连接过程
第一个交互:客户端向服务端发送SYN请求,并附带一个随机数x,这个x与将作为客户端发包序号的初始值,x的值是随机产生的。数据发送后,客户端状态变为SYN_SENT
。
第二次交互:服务端收到该数据包后,服务器将会向客户端发送一个回复确认包。这个包中包含了服务端的确认数据,ACKbit=1,acknum = x + 1
,和自己的请求数据 SYNbit=1,Sep=y
。acknum是在客户端发送的x值基础上+1
,这个值决定了下一次客户端向服务端发包时的sep值,即下一次客户端包的seq=x+1
。而服务端本次发送数据sep为将会作为服务端发包序号的初始值。发送该数据后,服务器会将该客户端信息放入半连接队列,等待会客户端回复,并将状态从LISTEN
置为SYN_RCVD
。
第三次交互:客户端收到服务端的包后,向服务端回复确认,ACKbit=1, acknum=y+1
,客户端准备就绪,将状态置为ESTABLISHED
,并可以向服务器直接发送消息了。该消息确认消息被服务器接收后,也会将状态置为 ESTABLISHED
,并将客户端从半连接队列中转入全连队列。
至此连接建立,客户端和服务器可以正常的发送消息。正常传输时,发包方的seq序列号会根据接收方acknum
的值加1得到,接收方回复的acknum
值 = 上一个数据包的sep + 接受方从该包中读取的字节数。这个sep值不但实现了包的完整性,而且从字节层面保证了数据。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。
四次挥手
数据交互结束后,由于连接的可靠性,任一方异常退出,另一方不会立即退出而是尝试重新连接,这样将占用大量时间,所以在退出时候同样需要通过确认来结束这个连接,保证双方都知晓对方退出的状态,来结束自己连接。这就是四次挥手过程
客户端可服务器准备断开连接,该请求可以由服务器发送,也可以由客户端发送,先发送者会后关闭连接,并被迫等待2MSL时长再关闭。服务器的时间总是珍贵的,所以该请求一般由客户端发起。
断开过程
第一次交互:客户端向服务器发送FIN请求FINbit=1,sep=x
,并将状态置为FIN_WAIT_1
。
第二次交互:服务器接收请求后,正常向发送应答包ACKbit=1, acknum=x+1
。服务器状态为CLOSE_WAIT;
第三次交互:服务器确认之前的数据包发送完毕后,正式向客户端发送FIN包FINbit=1, sep=y
,并将状态置为LAST_ACK
,
第四次交互:客户端发送ack应答ACKbit=1, ACKnum=y+1
,并将状态转化为TIMED_WAIT,服务器接收请求后,直接关闭服务器端的连接,释放资源等待别的连接。客户端等待2MSL秒后,如果没有收到服务器的消息,说明服务器正常关闭,随之自己释放资源,关闭连接。
为什么等待2MSL时间
客户端最后需要等待2MSL时间后才关闭,以保证服务器关闭后才关闭客户端。那么客户端如何确认服务端已经关闭的?。MSL时间指的是客户端和服务端之间的单次消息传送所需的最大时长。
当服务端发送FIN请求给客户端后,会等待客户端的应答,如果长时间没有受到ack应答,服务器会认为FIN包发生了丢包,于是会重新发送该FIN包。
假如客户端收到了FIN包,但是ack应答发生了丢包,服务器将收不到应答,而客户端并不知道服务器是否受到应答消息,于是等待服务器是否有回应。
1、如果服务器收到了ack应答,服务器直接关闭,客户端在2MSL后也关闭,此时没有回应。
2、如果服务器没有受到应答,服务器会认为客户端没有受到之前发个客户端的FIN包,于是将FIN包重发,这样客户端将会再次收到FIN包,服务器'回应'了。
这样就只能有两种情况,在2MSL时间内,客户端如果没有收到服务器的第二次FIN包,说明服务器关闭,自己正常退出即可。如果此时收到了第二个FIN包,说明应答丢包了,将再次发送ack应答,再次等待2MSL。直到没有响应,客户端才关闭。
客户端从发送ACK包开始,到达服务端的时间最大时间是MSL,如果在这个时间内没有到达,服务器会再次发送FIN,而这个FIN又经历一个MSL时间到达客户端,所以客户端需要等待时间为2MSL时长。