TCP三次握手和四次挥手

来源:互联网 发布:淘宝卖家订单险在哪里 编辑:程序博客网 时间:2024/06/03 20:06

1、TCP三次握手

TCP建立连接需要进行“三次握手”:
这里写图片描述

TCP三次握手过程描述如下

  1. 客户端发送连接请求报文:SYN标志位为1,ACK标志位为0,序列号seq为x。然后客户端进入SYN_SENT状态,等待服务器的确认响应;

  2. 服务器收到客户端的连接请求,对这个SYN报文段进行确认,发送:SYN标志位为1,ACK标志位为1,序列号seq为y,确认序列号ack为x+1。此时服务器进入SYN_RCVD状态;

  3. 客户端收到服务器的SYN+ACK报文段,确认ACK后,发送:SYN标志位为0,ACK标志位为1,序列号seq为x+1,确认序列号ack为y+1。发送完成后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

2、TCP四次挥手

TCP断开连接需要进行“四次挥手”:
这里写图片描述

TCP四次挥手过程描述如下

  1. 主机1(可以使客户端,也可以是服务器端)发送:FIN标志位为1,ACK标志位为0,序列号seq为u。此时,主机1进入FIN_WAIT_1状态。

  2. 主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段:FIN标志位为1,ACK标志位为1,序列号seq为v,确认序列号ack为u+1。主机1进入FIN_WAIT_2状态;主机2进入CLOSE_WAIT状态。

  3. 主机2向主机1发送FIN报文段:FIN标志位为1,ACK标志位为1,序列号seq为w,确认序列号ack为u+1。请求关闭连接,同时主机2进入LAST_ACK状态。

  4. 主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段:FIN标志位为1,ACK标志位为1,序列号seq为u+1,确认序列号ack为w+1。,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那么,主机1也可以关闭连接了。

3、状态转换图

这里写图片描述

4、几个问题

4.1 TCP中“全双工的字节流”含义的理解!

(1)全双工
意味着,TCP的收发是可以同时进行的。也就是说收的时候可以发,发的时候也可以收,两者互不冲突。

(2)字节
意味着,无论物理层或链路层收到的数据是否为一个个bit的数据,在TCP层一定是一个个字节。

(3)
意味着,socket的数据无头无尾,就像流水一样,如果从中间任意位置起,你无法知道一个消息包确切的开始或结束位置,除非从TCP的头开始算起。也就是意味着,我们在应用层编程时,必须定义一个应用层的包头,从收到的第一个字节开始,通过该包头能确定一个包的长度,然后根据包的长度,确定一个个包的起止位置。这也就是我们看到所有的TCP的socket编程中,都需要定义一个包头的原因。

4.2 为什么是“三次握手”?

因为TCP是“全双工通信”。
前提1:TCP协议要保证双方可以建立可靠的通信。 即 发送端、接收端要确认自己发送的信息对方能接收到,对方发送的信息自己能接收到。(必须确认收、发正常)
前提2:在前提1的情况下“握手”的次数越少越好。

(1)第一次握手
发送端向接受端发送一个SYN包。

发送端:无法确认自己发送的信息对方是否收到。

(2)第二次握手
接收端收到SYN包之后,接收端回一个ACK包。

发送端:可以确定自己发送的信息能被对方收到,也能确定对方发的信息自己能收到。
接收端:只能确定对方发的包自己能收到, 无法确定自己发的包对方能收到。

(3)第三次握手
发送端接收到SYN,之后再发一个ACK。

接收端:能够确定字节发送的消息,发送端能够收到。

4.1 三次握手建立连接时,发送方再次发送确认(第三次握手)的必要性?

主要是为了防止发送方已失效的连接请求报文段突然又传到了B,因而产生错误。假定出现一种异常情况,即A发出的第一个连接请求报文段并没有丢失,而是在某些网络结 点长时间滞留了,一直延迟到连接释放以后的某个时间才到达B,本来这是一个早已失效的报文段。但B收到此失效的连接请求报文段后,就误认为是A又发出一次 新的连接请求,于是就向A发出确认报文段,同意建立连接。假定不采用三次握手,那么只要B发出确认,新的连接就建立了,这样一直等待A发来数据,B的许多 资源就这样白白浪费了。

4.2 四次挥手释放连接时,等待2MSL的意义?

原因有二:
(1)保证TCP协议的全双工连接能够可靠关闭。
(2)保证这次连接的重复数据段从网络中消失。

先说第一点,如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。

再说第二点,如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。

什么是2MSL ?

MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为tcp报文(segment)是ip数据报(datagram)的数据部分,具体称谓请参见《数据在网络各层中的称呼》一文,而ip头中有一个TTL域,TTL是time to live的缩写,中文可以译为“生存时间”,这个生存时间是由源主机设置初始值但不是存的具体时间,而是存储了一个ip数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报文通知源主机。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等。

2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。

TTL与MSL是有关系的但不是简单的相等的关系,MSL要大于等于TTL。