一、建立TCP连接
建立TCP连接需要经过三次握手过程:
我会用官方的方式和我自己理解的方式解释一下的:
1、第一次握手,客户端发送连接请求,会发送syn(syn=j)包到服务器,并进入SYN_SENT状态,等待服务器确认。当然这是很官方的答案,当然是准确的,用我自己的话来解释呢,就是客户端要发起连接请求,这是它发送一个标志给服务器端,问它:我要发起请求了,你准备好了吗?服务器端准备好的话,则会回答客户端,此时进入第二次握手;
2、第二次握手,服务器收到客户端发送的syn包,则必须确认客户端的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;也就是,服务器准备好了,则发送一个自己的状态告诉客户端,我准备好了,你呢?此时客户端得到服务器端的这个信息,而且客户端也准备好了,就把它的状态传递给服务器端,则进入第三次握手;
3、第三次握手,客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack = k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手;这时客户端发送信息告诉服务器我也准备好了。
完成三次握手,客户端与服务器开始传送数据。
(ACK:确认标志;SYN:同步标志;FIN:结束标志)
二、关闭TCP连接
1、第一次挥手:客户端发起中断TCP连接的请求,即发送FIN报文,用来关闭客户端到服务器端的数据传送;即告诉服务器端“我没有数据要发送给你了,不过如果你还有数据没有传送完,则不必着急关闭socket,可以继续传送数据”;服务器接收到后,数据还没传送完,进入第二次挥手;
2、第二次挥手:服务器端收到FIN报文后,发送一个ACK报文给客户端,告诉客户端“我已经收到你的信息了,但是我还没准备好,数据没传完,所以你先等等我吧”;客户端收到这个ACK后,进入等待状态;当服务器端确定数据以及发送完成后,就向客户端发送FIN报文;进入第三次挥手;
3、第三次挥手:服务器端发送一个FIN,用来关闭服务器端到客户端的数据传送,告诉客户端“我这边数据发送完了,可以关闭连接了”;客户端收到FIN报文后,不太相信网络,所以为了确认,还是向服务器端发送了ACK报文,并进入等待TIME_WAIT状态,如果服务器端没有收到ACK可以进行重传;服务器端收到ACK后就知道可以断开连接了;客户端等了2MSL后,没有收到服务器端的回复,就证明服务器端已经正常关闭了,则客户端也进行关闭连接。于是TCP连接断开。
【注意】 在TIME_WAIT状态中,如果TCP client端最后一次发送的ACK丢失了,它将重新发送。TIME_WAIT状态中所需要的时间是依赖于实现方法的。典型的值为30秒、1分钟和2分钟。等待之后连接正式关闭,并且所有的资源(包括端口号)都被释放。
【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同
步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你
发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
当同时发起主动关闭的情况时: