您的位置:首页 > 理论基础 > 计算机网络

深入TCP(三)--三次握手和四次挥手

2018-01-28 20:51 357 查看
经过前面两篇文章的铺垫,我们对于TCP有了一个较为明显的认识,因此此篇文章便讲解建立连接和断开连接的过程–三次握手四次挥手。

一、建立连接

(1)窗口机制

TCP采用的是窗口机制进行流量控制。那么什么是窗口机制呢?

窗口机制实际上是一种流量控制的手段,它是一段缓冲区,在信息传递的过程中用户端和服务器端各自分配一块缓冲区来存储接收的数据,此时通讯的时候我们需要告诉对方我们的缓冲区的大小,不然对方发送数据的时候不知道你最大能接收的信息到底多大。

如果发送多组数据,则接收方的确认信息包含了自己剩下的缓冲区大小。

所以我们把剩下的缓冲区大小叫做窗口。

(2)三次握手连接过程



说明:

SYN:建立连接

ACK:确认

ack:确认序号。等于对方发送序号+1(即对方期望收到的下一个序列号)

seq:发送序号。

CLOSED:没有连接状态

LISTEN:监听远方的TCP端口的连接请求

SYN-SENT:在发送方发送连接请求后等待对连接请求的确认。

SYN-RCVD:在接收方收到和发送一个连接请求后等待对连接请求的确认

ESTAB-LISHED:代表一个打开的连接,数据可以传递给双方。

在建立三次握手的过程中,每一次握手的说明:

第一次握手:建立连接时,客户端A发送SYN包,此时SYN等于1,(SYN报文段不能携带数据,但要消耗一个序号),同时发送初始号sep=x到服务器,并且进入SYN-SENT状态,等待服务器B确认。

第二次握手: 服务器B接收到SYN包,向A发送确认报文,此时SYN和ACK全部为1,确认序号为x+1,同时也初始化自己的发送序号seq=y,此时服务器B进入SYN-RCVD同步状态。

第三次握手:客户端A收到服务器发送的SYN+ACK报文,此时向服务器发送确认包ACK,确认序号ack=y+1,A的序号为seq=x+1,此包发送完毕,客户端和服务器都进入ESTAB-LISHED状态。

双方完成三次握手,此时客户端和服务器开始传送数据。

这个三次握手具体化,实际上相当于谈恋爱(-。-)

1、你想做我女朋友吗?

2、你想做我男朋友吗?

3、好的,我们去约会吧。



二、断开连接

(1)四次挥手断开连接过程

TCP的连接是全双工的,因此每个方向都必须单独的进行关闭,因此如果建立简介的双方要进行关闭,则需要发送一个FIN包来终止这个方向的连接,因此接收到一个FIN只意味着这一个方向上没有数据的流动,所以一个TCP连接在接收到FIN后仍然可以发送数据。所以进行关闭的一方执行主动关闭,另外一方被动关闭。

由于TCP的连接是全双工的连接,所以一个TCP连接存在双向的读写管道。

简单来说就是先关闭读,后关闭写。由于客户端和服务器都要关闭,所以一共需要四个阶段。以客户端为例:



说明:

FIN:结束

FIN-WAIT-1:等待远程TCP连接的中断请求,或者之前的连接中断请求的确认。

FIN-WAIT-2:从远程TCP等待连接中断请求。

CLOSE-WAIT:等待从本地用户发来的连接中断请求。

LAST-ACK:等待原来发向远程TCP的连接中断请求的确认

TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认。

CLOSED:没有任何连接状态。

整个挥手过程如下:

第一次挥手:客户端A发送FIN包,用来关闭与服务器B之间的数据传输,同时发送发送序号为u,客户端A进入等待状态。(关闭服务器读通道)。

第二次挥手:服务器B收到FIN包,发送ACK确认报文,确认序号为u+1,发送序号为v,客户端A收到服务器B的确认后,进入FIN-WAIT-2等待状态,等待B发送报文。(关闭客户端写通道

第三次挥手:服务器B关闭与客户端A的连接,发送一个FIN包给客户端,进入最后确认状态CLOSE-WAIT。(关闭客户端读通道

第四次挥手:客户端A收到服务器发送的报文后,发送ACK确认报文,表示对B的释放请求发出确认,并且将确认序号设置为收到序号+1,然后进入TIME-WAIT时间等待状态。(关闭服务器写通道

这个四次挥手具体化,实际上相当于分手(-。-)

A:我和你分手吧。

B:好的,我知道了。

B:我和你也分手吧。

A:好的。

三、TCP中TIME_WAIT和CLOSE_WAIT状态

四、常见问题

(1)为什么TCP连接时要3次握手,2次可以吗?

TCP三次握手,握的是什么? 握的是通讯双方数据源点的序列号!

下面我们来看下两次握手的情况:

A发送同步信号SYN,发送A的序列号。

B发送同步信号SYN,发送B的序列号,发送B的ACK报文

这里存在了一个问题,就是A和B就A的初始序列号达成了一致,但是B无法知道A是否已经收到了自己的同步信号,如果这个同步信号丢失了,则A和B的初始序列号将无法达成一致。

这里TCP的设计者将这个标志位设计成占一个字节的数据,按照TCP segment的必须确定的原则,则这里A必须给B一个确认,确认A已经收到了B的同步信号。

如果此时A发送给B的确认报文丢失了,并不会超时重传ACK报文,因为TCP不会为没有数据的ACK超时重传。

所以如果B没有收到A的ACK确认报文,则会超时重传自己的SYN同步信号,直到收到A的ACK确认报文为止。

假设此时采用了2次握手,如果因为网络延迟,client发送的请求报文延时到达server端,但是client端认为这个连接已经失效,server端任务连接请求到达,则发送确认报文,以为新的连接已经建立成功,所以一致等待client发送数据,这样server很多的资源就被浪费掉。





(2)为什么TCP连接时要3次握手,4次可以吗?

四次握手的情况:

A发送同步信号SYN,发送A的序列号

B确认收到A的同步信号,并记录到A的本地,命名B的ACK

B发送同步信号SYN,发送B的序列号。

A确认收到B的同步信号,记录到B的本地,命名A的ACK报文

所以我们可以看到中间的两部可以合并,所以只需要三次握手,可以提高连接的速度和效率

(3)TCP连接只需3次握手,为什么要4次挥手?

因为客户端的LISTEN状态下的SOCKET收到SYN报文的连接请求后,它可以把ACK和SYN放在一个报文里来发送。但关闭连接时,当收到对方的FIN通知时,它仅仅表示对方没有数据发送给你,但并不代表你不会给它发送数据,所以你可能不会立即关闭SOCKET,而是发送FIN报文给对方表示你同意现在可以关闭连接了,所以这里的ACK报文和FIN报文多数情况下是分开发送的。

(4)为什么TIME-WAIT状态必须要等待2MSL的时间?

被动关闭的B无需任何wait time,直接释放资源。

但,A并不知道B是否接到自己的ACK,A是这么想的:

1)如果B没有收到自己的ACK,会超时重传FIN那么A再次接到重传的FIN,会再次发送ACK

2)如果B收到自己的ACK,也不会再发任何消息,包括ACK无论是1还是2,A都需要等待,要取这两种情况等待时间的最大值,以应对最坏的情况发生,这个最坏情况是:

去向ACK消息最大存活时间(MSL) + 来向FIN消息的最大存活时间(MSL)。

这恰恰就是2MSL( Maximum Segment Life)。等待2MSL时间,A就可以放心地释放TCP占用的资源、端口号,此时可以使用该端口号连接任何服务器。

为什么要等待2MSL

一、保证TCP协议的全双工连接能够可靠关闭

二、保证这次连接的重复数据段从网络中消失

如果不等,释放的端口可能会重连刚断开的服务器端口,这样依然存活在网络里的老的TCP报文可能与新TCP连接报文冲突,造成数据冲突,为避免此种情况,需要耐心等待网络老的TCP连接的活跃报文全部死翘翘,2MSL时间可以满足这个需求(尽管非常保守)!

(5)第一个包,如果A发送给B的SYN包中途丢失,没有到达B

则此时A会启动周期性超时重传,直到收到B的确认。

(6)第二个包,如果B发送给A的SYN+ACK中途丢失,没有到达A

则B会启动超时重传机制,直到收到A的确认

(7)第三个包,即A发送给B的ACK中途被丢失,没有到达B

A发送完ACK,单方面认为已经建立好连接,但是很明显B认为没有建立好连接。所以此时有三种情况。

假设此时双方都没有数据传输,B会启动超时重传机制,直到收到A的确认,收到之后B的TCP连接也建立完成,双方可以发包

假设此时A有数据发送,B收到了数据和ACK确认报文,此时自然会切换到ESTAB-LISHED状态,并接收A的数据

假设B有数据发送,但是此时数据发送不了,会一直周期性的传送SYN+ACK,直到收到A的确认才可以发送。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: