TCP三次握手和四次挥手

来源:互联网 发布:尔雅网络课程登陆网址 编辑:程序博客网 时间:2024/06/03 13:43

TCP首部常用字段介绍

序号:尽管从应用层交付下来的是TCP报文段,但是TCP是面向字节流的(就是说TCP传送时时按照一个个字节来传送的),所以在一个TCP连接中传送的字节流需要编号,这样才能保证按序交付。
确认号:TCP含有确认机制,所以接受端需要给发送端发送确认号,这个确认号只需记住一点:若确认号等于N,则表明到序号N-1为止的所有数据都已经正确收到。
确认比特ACK:只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。TCP规定,一旦连接建立,所有传送的报文段都必须把ACK置1.
例如:B正确收到A发送过来的一个报文段,其序号字段值501,而数据长度是200B(序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B将发送给A的确认报文段中的报文段设置为701.
同步比特SYN:同步比特SYN=1,表示这是一个连接请求或接受连接的报文。[SYN=1的报文段不能携带数据]
终止比特FIN:释放一个连接,当FIN=1时,表明此报文段的发送端的数据已经发送完毕,并要求释放传输连接。


TCP三次握手

这里写图片描述

第一次握手:客户端A向服务端B发送连接请求报文段,其首部中的同步比特SYN=1,并选择序号seq=x(表明传送数据时的第一个数据字节的序号是x),然后等待服务端B确认。
第二次握手:服务端B收到了数据报,并从SYN=1知道客户端A请求建立连接,服务端B在确认报文段中设置SYN=1,ACK=1,其确认号ack=x+1,自己选择序号seq=y,并将该数据报发送给客户端A以确认连接请求。
第三次握手:客户端A收到确认后,检查确认号ack是否等于x+1,确认比特ACK是否为1,如果正确则将确认比特ACK置为1,确认号ack=y+1,并将该数据包发送给服务端B,服务端B检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,完成三次握手,随后客户端A与服务端B之间可以开始传输数据了。

连接建立:
1)SYN=1,seq=x
2)SYN=1,ACK=1,seq=y,ack=x+1
3)ACK=1,seq=x+1,ack=y+1

为什么是三次握手?不是2次,4次握手?
在谢希仁著《计算机网络》第四版中讲“三次握手”的目的是“为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误”。在另一部经典的《计算机网络》一书中讲“三次握手”的目的是为了解决“网络中存在延迟的重复分组”的问题。这两种不用的表述其实阐明的是同一个问题。
谢希仁版《计算机网络》中的例子是这样的,“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
也就是说三次握手是为了防止上述问题的最小次数。4次握手最后一次又显得多余了。


TCP四次挥手

这里写图片描述

第一次挥手:Client向Server发送连接释放报文段,其首部设置终止比特FIN=1,选择序号seq=u,然后等待Server确认。
第二次挥手:Server向Client发出确认报文段,其首部确认比特ACK=1,确认号ack=u+1,自己的序号seq=v。TCP服务器进程通知高层应用进程,从Client到Server这个方向的连接释放了,TCP连接处于半关闭状态。Server若要发送数据,则Client仍要接受。
第三次挥手:Server向Client发送连接释放报文段,其首部设置终止比特FIN=1,ACK=1,确认号ack=u+1,自己的序号seq=w,然后等待Client确认。
第四次挥手:Client收到连接释放报文段后发出确认,在确认报文段中,设置ACK=1,确认号ack=w+1,序号seq=u+1。
提示:TCP连接必须讲过2MSL后才真正释放。

释放连接:
1)FIN=1,seq=u
2)ACK=1,seq=v,ack=u+1
3)FIN=1,ACK=1,seq=w,ack=u+1
4)ACK=1,seq=u+1,ack=w+1

假设客户端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说”我Client端没有数据要发给你了“,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,”告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息“。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,”告诉Client端,好了,我这边数据发完了,准备好关闭连接了“。Client端收到FIN报文后,”就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,”就知道可以断开连接了“。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那Client端也可以关闭连接了。TCP连接就这样关闭了!注意:中断连接端可以是客户端,也可以是服务端。

为什么最后“一次握手”后要等待2MSL(最长报文寿命)时间?
1)可靠地实现TCP全双工连接的终止
因为虽然双方都同意关闭连接了,而且握手的4个报文也都发送完毕,按理可以直接回到CLOSED 状态(就好比从SYN_SENT 状态到ESTABLISH 状态那样),但是我们必须假想网络是不可靠的,你无法保证你(客户端)最后发送的ACK报文一定会被对方收到,就是说对方处于LAST_ACK 状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT 状态的作用就是用来重发可能丢失的ACK报文。

2)允许老的重复分节在网络中消逝
TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个迟到的迷途分节到达时可能会引起问题。在关闭“前一个连接”之后,马上又重新建立起一个相同的IP和端口之间的“新连接”,“前一个连接”的迷途重复分组在“前一个连接”终止后到达,而被“新连接”收到了。为了避免这个情况,TCP协议不允许处于TIME_WAIT状态的连接启动一个新的可用连接,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个新TCP连接的时候,来自旧连接重复分组已经在网络中消逝。

MSL即Maximum Segment Lifetime,即报文最大生存时间,是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。

参考:http://blog.csdn.net/whuslei/article/details/6667471/

原创粉丝点击