三次握手是TCP建立连接时进行的,四次挥手是TCP断开连接是进行的,要弄明白三次握手和四次挥手,需要了解TCP的协议。
上图是TCP协议的组成部分,分头部和数据两大部分,下面我们简单介绍下TCP协议各个部分:
源端口:16位,表示通信的源端口号,它与IP协议中源IP地址用来标识报文的返回地址
目标端口:16位,表示通信目的端口或传输的目的端口,它与IP协议中目的地址用来标识报文的传输目标地址
序号:32位,当SYN出现时,它是初始序列码(Initial Sequence Number, ISN),第一个数据字节是ISN+1;当用于传输时,它可以表示分段报文的序号,用于组合完整的报文数据。它可以用来补偿传输中的不一致
确认号:32位,当ACK出现时,它表示一个准备接收的包的序列码;当用于传输时,被接收到使用,用于重组分段的报文成最初形式
数据偏移:4位,表示TCP头部大小,指示数据从何处开始
保留:6位,这些必须都为0,用于将来定义新的用途而保留
URG: 1位,紧急标志位,为1表示该标志位有效
ACK:1位,应答确认标志位,大多数情况该标志位是置位的(即为1)TCP报头内的确认标号栏内包含的确认后(w+1)为下次预期的序列号,同时提示远端已经成功接收所有数据
PSH:1位,推送数据标志位,置位时,接收到不将该数据进行队列处理,而是尽可能快的将数据转有应用处理。
RST:1位,重置连接(复位)标志位,用于重组相应的TCP连接
SYN:1位,同步序列号标志位,置位时表明同步序列号栏有效。该标志位仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列号,改序列号是TCP连接初始端(一般是客户端)的初始序列号
FIN:1位,完成发送标志位
*窗口:16位,表示每个TCP数据包数据部分的大小。TCP的流量控制由每一端通过声明窗口大小来提供。窗口大小为2个字节数,最大为65535,起始于确认序号字段指明的值,这个值是接收端期望接收的字节。
*校验和:16位,发送端基于数据内容计算的一个数值,接收端要与发送端计算出的值完全一样,保证数据的有效性。校验和覆盖了整个TCP的报文段。它是一个强制性的字段,由发送端计算和存储,并有接收端验证
*紧急指针:16位,指向后面是优先数据的字节,URG标志设置了才有效
*选项和填充:长度不定,当长度必须为1个字节,如果没有选项就表示这个1字节的域等于0
*数据:TCP协议包负载的数据
TCP三次握手
三次握手是TCP建立连接是,需要客户端和服务端总共发送3个包确认连接的,整个流程如下图所示:
第一次握手:客户端将标志位SYN置为1,随机生成一个值seq=1,接着将数据表发给服务端,此时客户端进入SYN_SENT(请求建立已发送)状态,等待服务端确认
第二次握手:服务端收到数据包后,有SYN=1知道客户端请求建立连接,服务端将标志位SYN和ACK都置为1,ack=J+1,随机生成一个值seq=K,并将数据包发送给客户端以确认连接请求,接着服务端进入SYN_RCVD(建立连接已收到)状态
第三次握手:客户端收到确认包后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务端,服务端收到之后检测ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务端都进入ESTABLISHED状态,完成三次握手,随后客户端和服务端之间可以开始传输数据了。
TCP四次挥手
四层挥手就是断开TCP连接,需要客户端和服务端总关发送4个数据表以确认连接的断开,其流程如下图所示:
由于TCP是全双工的,所有每个方向必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接;另一方收到一个FIN只是意味着己方不在接收到数据了,但是这个TCP连接上己方仍然能否发送数据,直到己方发送一个FIN。首先进行关闭的一方执行主动关闭,另一方则执行被动关闭。
第一次挥手:客户端将FIN置为1,随机生成一个值seq=J,将数据包发送给服务端,用来关闭客户端到服务端的数据发送,此时客户端进入FIN_WAIT_1(等待关闭)状态
第二次挥手:服务端收到数据包,有FIN=1知道客户端请求断开连接,将ACK置为1,ack=J+1,接着数据包发送回给客户端,表示断开连接的请求已收到,此时服务端进入CLOSE_WAIT(等待关闭)状态。客户端收到确认包之后,检测ACK是否为1,ack是否为J+1,检查正确之后表明服务端已经收到断开连接的请求,客户端随后进入FIN_WAIT_2状态
第三次挥手:服务端将FIN置为1,随机生成一个值seq=K,将数据包发送给客户端,用来关闭服务端到客户端的数据发送,此时服务端进入LAST_ACK(等待最后确认)状态
第四次挥手:客户端收到服务端的FIN后,表明服务端请求断开数据发送,接着将ACK置为1,ack=K+1并把数据包发送给服务端,此时客户端进入TIME_WAIT(等待2MSL之后进入CLOSED状态)状态。服务端收到FIN的确认包之后,检测ACK是否为1,ack是否为K+1,如果正确服务端进入CLOSED状态,关闭TCP连接
注意:此时客户端并未进入CLOSED状态,为了防止服务端延迟,需要等待2MSL的时间,然后进入CLOSED状态关闭TCP连接(这是因为如果客户端直接进入CLOSED,如果网络异常,客户端就不能重发数据了)
问题
1、为什么连接是三次握手,而断开连接是4次挥手?
答:这是因为服务端在LISTEN(监听)状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发给客户端,而关闭连接时,当收到客户端的FIN报文时,仅仅表示客户端不在发送数据了但还能接受数据,服务端也未必把全部数据都发送给对方了,所以服务端可以可以立即关闭也可以发送一些数据给客户端后,再发送FIN报文给客户端来表示同意现在关闭连接,所以服务端ACK和FIN一般会分开发送
2、为什么TIME_WAIT状态需要等待2MSL(最大报文生成时间)才能进入CLOSED状态
答:原因一:为保证TCP协议的全双工连接能改可靠关闭。如果客户端直接关闭,那么由于IP协议的不可靠性或网络原因,导致服务端没有收到客户端的最后回复的ACK,那么服务端就会在超时之后继续发送FIN,此时由于客户端已经关闭,就找不到与重发的FIN对应的连接,最后服务端就会收到RST而不是ACK, 服务端就会以为连接错误把问题报告给高层。这样的错误虽然不会操作数据丢失,但是导致TCP协议不符合可靠连接的要求,所以客户端不直接进入关闭状态,而是要保持TIME_WAIT,当再次受到FIN时,能够保证对方受到ACK,最后正确的关闭连接
原因二:保证这次连接的重复数据段从网络中消失。如果客户端直接关闭,然后又再向服务端发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不是不同的,也就是说有可能新连接和老连接的端口号是相同的。一般不会发生什么问题,但是还是有特殊情况出现:假设新连接和已关闭连接的端口号是一样的,如果前一次连接的有些数据仍然滞溜在网络中,这些延迟数据在建立新连接之后才到达服务端,由于新连接和老连接的端口号一样,又因为TCP判断不同连接的依据是socket pair, 于是TCP协议认为那个延迟的数据是属于新连接的,这样就合真正的新连接的数据包发生混淆了,所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样以保证本次连接的所有数据都能从网络中消失。
网友评论