TCP三次握手是建立连接,四次挥手是关闭连接。

TCP:TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种端点我们叫作套接字(socket),它的定义:IP地址+端口号,例如:192.3.4.16:80。

TCP服务器进程先创建传输控制块TCB,进入LISTEN(监听)状态,时刻准备接受客户进程的连接请求。

第一次:
第一次握手:建立连接时,客户端进程创建传输控制块TCB,然后发送syn包(SYN=1,seq=x)到服务器,并进入SYN_SENT(同步已发送)状态,等待服务器确认;SYN:同步序列编号;

第二次:
第二次握手:服务器收到syn包,必须确认客户的SYN,同时自己也发送一个SYN包(SYN=1,ACK=1,ack=x+1,seq=y),即SYN+ACK包,此时服务器进入SYN_RECV(同步收到)状态;

第三次:
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(SYN=1,ACK=1,ack=y+1,seq=x+1),此包发送完毕,客户端进入ESTABLISHED(TCP连接成功)状态。

当服务器收到客户端的确认后,也进入ESTABLISHED(TCP连接成功)状态。

TCP报文字段含义:

  • 同步SYN,在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1。
  • 确认ACK,仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1。
  • 确认号ack,占4个字节,是期望收到对方下一个报文的第一个数据字节的序号。如,B收到了A发送过来的报文,其***字段是501,而数据长度是200字节,这表明B正确的收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于B在发送给A的确认报文段中把确认号置为701。
  • 序号seq,占4个字节,TCP连接中传送的字节流中的每个字节都按顺序编号。如,一段报文的序号字段值是 301 ,而携带的数据共有100字段,显然下一个报文段(如果还有的话)的数据序号应该从401开始。
  • 终止FIN,用来释放连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放。

问题:为什么最后客户端还要再发送一次确认

主要防止已经失效的连接请求报文忽然又传送到了服务器,从而产生错误。如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。

TCP四次挥手过程:

第一次:客户端发出连接释放报文,并且停止发送数据。释放报文首部:FIN=1,seq=u。此时客户端FIN-WAIT-1(终止等待1)状态。

第二次:服务器收到连接释放报文,发布确认报文(ACK=1,ack=u+1,seq=v)。此时服务端进入CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

客户端收到服务器确认请求后,此时客户端进入FIN-WAIT-2(终止等待2)状态。等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

第三次:服务器将最后的数据发送完毕之后,就向客户端发送释放报文(FIN=1,ack=u+1),假定此时的***为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端确认。

第四次:客户端收到服务器连接释放报文后,必须发出确认,ACK=1,ack=w+1,squ=u+1。此时客户端进入TIME-WAIT(时间等待)状态。需要注意的是,此时的TCP连接还没释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

服务器只要收到确认报文之后,马上进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些

TCP三次握手,四次挥手

问题:为什么客户端最后还要等待2MSL?

保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

问题:为什么连接是三次握手,关闭连接是四次挥手?

因为TCP是全双工。关闭连接时,服务器收到对方的FIN报文,仅仅表示对方不再发送数据,但是对方还能接受数据,而自己并非全部数据都已经发送出去了。

问题:如果已经建立连接,但是客户端出现故障怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75分钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

相关文章: