tcp三次握手与四次挥手
作者:互联网
引言
TCP是一个面向连接的协议。无论哪一方向另一方发生数据之前,都必须先在双方直接建立一条连接。而建立连接的过程需要经历三次握手,而连接的断开则需要进行四次挥手,下面将来简要说明下连接建立和断开的过程。
tcp首部说明
TCP首部的数据格式如下图。不算上可选项的话通常是20字节,最大60字节。
首部说明:
-
端口号:每个tcp首部都包含源端口号和目的端口号,用于寻找发送和接收的应用进程。这两个端口号加上IP首部中的源IP和目的IP地址组成唯一的一个TCP连接。
-
序号:序号用来标识从TCP源端向目的地发送的数据字节流,它表示这个报文段中的第一个数据字节。如果将字节流当作两个应用程序中的单向流动,则TCP用序列号来对每个字节进行计数。其为32位无符号数,当达到2^32 - 1后又从0开始。
-
确认序号:对于TCP协议来说,每传输一个TCP报文段都需要接收方确认。不过这种效率较低,所以在TCP中使用累计确认的机制,即对于多个TCP报文段只用对最后一个报文段确认即可。
例如:发送方发生一个报文段,其序号为11232且报文段大小为204,则接收方应当回复确认序号为11436。
说明:只有A C K标志为 1时确认序号字段才有效。 -
4位首部长度:代表TCP报文段首部的长度,由于是4位所以最大为15。其基本单位为4字节,所以最大代表15 X 4 = 60字节。
-
保留:未使用。
-
6个标志位:
URG:紧急指针(u rgent pointer)有效
ACK:确认序号有效
PSH:接收方应该尽快将这个报文段交给应用层
RST:重建连接
SYN:同步序号用来发起一个连接
FIN : 发端完成发送任务 -
窗口大小:TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端期望接收到的字节。
-
检验和:检验和覆盖了整个TCP报文段,包括首部和数据部分。这是一个强制字段,由发送端计算和存储,并且由接收端验证。
-
紧急指针:在URG置为1时才有效。
TCP连接建立
建立连接的过程如下:
- 请求端(通常称为客户端)发送一个SYN段指明客户端打算连接的服务端的端口,以及初始化序号(ISN,在下图中为1415531521)。这个SYN段为报文段1。
- 服务器发回包含服务器的初始序号的SYN报文段(报文段2)作为应答。同时,将确认序号设置为客户的ISN加1以对客户端SYN报文段进行确认。
- 客户端必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认(报文段3)。
这三个报文段完成连接的建立。这个过程就称之为三次握手(three- way handshake)。
发送第一个SYN的一端将执行主动打开( active open)。接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
当一端为建立连接而发送它的 SYN时,它为连接选择一个初始序号。 ISN随时间而变化,因此每个连接都将具有不同的 ISN。RFC 793 [Postel 1981c]指出ISN可看作是一个32比特的计数器,每4ms加1。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它作错误的解释。
TCP连接终止
建立一个连接需要三次握手,而终止一个连接需要经过四次握手。这是由于TCP的半关闭(half- close)造成的。既然TCP连接是全双工(即数据能同时在两个方向上传递),因此每个方向上的必须单独关闭。这原则就是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。当一端收到一个FIN,它必须通知应用层另一端几经终止了那个方向的数据传送。
收到一个FIN只意味着在这一方向上没有数据流动。一个TCP连接在收到一个FIN之后仍然能够发送数据。而这对利用半关闭的应用来说是可能的,尽管实际应用中只有很少的TCP应用这样做。
连接的终止流程:
第一次挥手:客户端向服务器发出释放连接请求的报文,其中FIN(终止位) = 1,seq(序列号)=M;在客户端发送完之后,客户端进入FIN-WAIT-1(终止等待1)状态。此时客户端还是可以进行收数据的
第二次挥手:服务器在收到客户端的连接释放请求后,随即向客户端发送确认报文。其中ACK=1,seq=v,ack(确认号) = M +1;在服务器发送完毕后,服务器端进入CLOSE_WAIT(关闭等待)状态。此时A收到这个确认后就进入FIN-WAIT-2(终止等待2)状态,等待服务器发出连接释放的请求。此时服务器还是可以发数据的。
(如果服务器直接跑路,则客户端永远处与这个状态。TCP 协议里面并没有对这个状态的处理,但 Linux 有,可以调整 tcp_fin_timeout 这个参数,设置一个超时时间。)
第三次挥手:当服务器已经没有要发送的数据时,就会给客户端发送一个释放连接报文,其中FIN=1,ACK=1,seq=N,ack=M+1,在服务器发送完之后,进入LAST-ACK(最后确认)状态。
第四次挥手:当客户端收到服务器的释放连接请求时,必须对此发出确认,其中ACK=1,seq=M+1,ack=N+1;客户端在发送完毕后,进入到TIME-WAIT (时间等待)状态。服务器在收到客户端的确认之后,进入到CLOSED(关闭)状态。在经过时间等待计时器设置的时间之后,客户端才会进入CLOSED状态。
QA
1.为什么是三次握手,而不是二次或者四次?
- 首先,为什么不是二次握手。
考虑一种情况,当客户端发送连接请求报文段时,由于网络原因导致该报文滞留某网络节点,这必然会导致超时重传。
此时,假设重传的报文段被服务器正常接收,TCP服务器进程给TCP客户进程发送一个TCP连接请求确认报文段,并进入连接已建立状态。
注意,假设此时我们使用的是两次握手,现在,TCP双方都处于连接已建立状态,它们可以相互传输数据,之后可以通过四报文挥手来释放连接,TCP双方都进入了关闭状态。
此时之前滞留网络的请求报文段达到服务器,服务器会误认为此时客户端发起了连接请求,服务器会响应一个确认连接的报文并进入连接完成的状态。
该报文段到达TCP客户进程,由于TCP客户进程并没有发起新的TCP连接请求,并且处于关闭状态,因此不会理会该报文段。
但TCP服务器进程已进入了连接已建立状态,他认为新的TCP连接已建立好了,并一直等待TCP客户进程发来数据。这将白白浪费TCP服务器进程所在主机的很多资源。 - 为什么不是四次握手
TCP是全双工的通信模式,理论上可以使用四次握手实现TCP连接的建立,不过在服务器响应客户端的请求报文段时,为了节省带宽以及效率的原因,将响应请求和服务器向客户端的连接请求合并成一个报文段,本质上是三次和四次都能达到目的。
2.为什么需要四次挥手?
前面说了,TCP是全双工的通信模式,在任意时刻数据流都可以相互流动。所以客户端和服务器的挥手对都对应着某一个方向上数据流向的终止。即两次挥手只是客户端或者服务器方向上连接的断开,需要四次挥手才是客户端和服务端分别释放连接的过程。
3.四次挥手时最后客户端发出ACK响应服务器的请求时为什么要等待2msl?
msl(Maximum Segment Lifetime):报文段最大生存时间。它是任何报文段被丢弃前在网络内存活的最大时间。RFC 793 [Postel 1981c] 指出MSL为2分钟。然而,实现中的常用值是30秒,1分钟,或2分钟。
等待2msl主要有两个原因,一个是为了让服务器能够按照正常步骤进入CLOSED状态,二是为了防止已经失效的请求连接报文出现在下次连接中。
1. 由于客户端最后一次的确认报文可能会丢失,这会导致服务器无法进入CLOSE状态。于是服务器会重传释放连接的请求报文,如果此时客户端没有等待直接关闭了,那么客户端无法接收到服务器重传的请求,这样就会导致服务器无法正常释放。如果客户端还在等待,就会收到服务器的重传,然后进行应答,这样B就可以进入CLOSED状态了。
2. 在这2MSL等待时间里面,本次连接的所有的报文都已经从网络中消失,从而不会出现在下次连接中。
标签:报文,握手,tcp,四次,TCP,序号,服务器,连接,客户端 来源: https://www.cnblogs.com/liuershi/p/16464452.html