TCP三次握手和四次挥手详解

来源:互联网 发布:python kmeans 编辑:程序博客网 时间:2024/06/05 07:19

TCP三次握手和四次挥手详解

TCP头部:其中ACK SYN 序号 FIN ack这三个部分在以下会用到,介绍如下

ACK:表示是否前面的确认号字段是否有效。ACK=1,表示有效。只有当ACK=1时,前面的确认号字段才有效。TCP规定,连接建立后,ACK必须为1,带ACK标志的TCP报文段称为确认报文段。

SYN:在建立连接时使用,用来同步序号。当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当SYN=1,ACK=1时,表示对方同意建立连接。SYN=1,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中SYN才置为1,带SYN标志的TCP报文段称为同步报文段。

序列号:表示本报文段所发送数据的第一个字节的编号。在TCP连接中所传送的字节流的每一个字节都会按顺序编号。由于序列号由32位表示,所以每2^32个字节,就会出现序列号回绕,再次从0 开始。

FIN::表示通知对方本端要关闭连接了,标记数据是否发送完毕。如果FIN=1,即告诉对方:"我的数据已经发送完毕,你可以释放连接了",带FIN标志的TCP报文段称为结束报文段

ack: 确认号:表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。也就是告诉发送发:我希望你(指发送方)下次发送的数据的第一个字节数据的编号是这个确认号

 

TCP工作在传输层,每一次连接都需要三个阶段:建立连接,数据传送和数据释放。"三次握手"就发生在连接建立阶段。

一.TCP连接建立过程中为什么需要"三次握手"

 目的是防止已失效的连接请求报文段突然又传送到了服务端,因而发生错误。

"已失效的连接请求报文段"的产生在这样一种情况下:

(客户端)client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但(服务端)server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。若不采用"三次握手",那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了采用"三次握手"的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。"

1.TCP三次握手

  三次握手是指建立一个TCP连接时,需要客户端和服务端总共发送3个包。

首先client发送连接请求报文,SYN=1 ACK=0 (请看文首TCP包头的介绍),TCP规定SYN=1时不能携带数据,但要消耗一个序列号,因此声明自己的序号是seq=x

然后server段接受连接后回复ACK报文,并为这次连接分配资源,client端接收到ACK报文后也向server段发送ACK报文,但不用SYN了,这时即为ACK=1,seq=x+1,ack=y+1

并分配资源,这样TCP连接就建立了。

2.TCP四次挥手

然后就是断开连接了,TCP的连接的拆除需要发送四个包,因此称为四次挥手。

客户端或服务端均可发起挥手动作,在socket编程中,任何一方执行close操作即可产生挥手操作。

简单的过程如下:

假设客户端A发起中断连接请求,也就是发送FIN报文,服务器端接受到FIN报文后,意思是说"我客户端没有数据发送给你了",但是如果你还有数据没有发送完成,就不必急着关闭socket,可以继续发送数据,所以你先发送ACK,"告诉客户端,你的请求我收到了,请你继续等我的消息"这时候客户端就进入FIN_WAIT状态,继续等待服务端的FIN的报文,当服务端确定数据已经发送完成,则向客户端发送FIN报文"告诉客户端,好了,我这边数据发完了,准备好关闭连接了"客户端收到FIN报文后,"就知道可以关闭连接了,但它为了保险起见,担心服务端不知道要关闭,所以发送ACK后进入T"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报文。

娱乐一下:我老家开往北京的大巴,由于没有车站买票,所以采用直接给大巴司机打电话预定的方式订票。
而大巴司机的智慧简直让我惊叹劳动人民的伟大。
订票流程是这样子的,我们前一天上午先给司机打电话订票,司机前一天下午打电话向每一个人确认。第二天坐车的时候凭借电话号码上车。这就是活生生的三次握手。大笑



 

原创粉丝点击