TCP连接的建立与终止
1.tcpdump的输出
T C P报文段的tcpdump输出:
对于T C P段,每个输出行开始按如下格式显示:
源 > 目的: 标志
这里的标志代表 TCP首部中6个标志比特中的 4个:
看到了 S、 F和句点“.”标志符。其他的两个标志(R和P)。TCP首部中的其他两个标志比特—ACK 和 URG—tcpdump将作特殊显示。
在第1行中,字段1415531521:1415531521(0)表示分组的序号是 1415531521,而报文段中数据字节数为0。 tcpdump显示这个字段的格式是开始的序号、一个冒号、隐含的结尾序号及圆括号内的数据字节数。显示序号和隐含结尾序号的优点是便于了解数据字节数大于 0时的隐含结尾序号。这个字段只有在满足条件(1)报文段中至少包含一个数据字节;或者(2)SYN、FIN或RST被设置为1时才显示。图中的第1、 2、 4行是因为标志比特被置为 1而显示这个字段的,在这个例子中通信双方没有交换任何数据。
在第2行中,字段ack 1415531522 表示确认序号。它只有在首部中的 ACK标志比特被设置1时才显示。
每行显示的字段 win 4096表示发端通告的窗口大小。在这些例子中,我们没有交换任何数据,窗口大小就维持默认情况下的 4096。
图中最后一个字段 <mss 1024>表示由发端指明的最大报文段长度选项。发端将不接收超过这个长度的TCP报文段。这通常是为了避免分段
2.建立连接协议
1) 请求端(通常称为客户)发送一个SYN段指明客户打算连接的服务器的端口,以及初始序号(ISN,在这个例子中为1415531521)。这个SYN段为报文段1。
2) 服务器发回包含客户服务器的初始序号的 SYN报文段(报文段2)作为应答。同时,将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号。
3) 客户必须将确认序号设置为服务器的 ISN加1以对服务器的 SYN报文段进行确认(报文段3)。
这三个报文段完成连接的建立。这个过程也称为三次握手(three-way handshake)。
建立一个连接需要三次握手,而终止一个连接要经过 4次握手。这由 TCP的半关闭(half -close)造成的。既然一个TCP连接是全双工(即数据在两个方向上能同时传递),因此每个方向必须单独地进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个 F I N来终止这个方向连接。当一端收到一个 FIN,它必须通知应用层另一端几经终止了那个方向的数据传送。发送FIN通常是应用层进行关闭的结果。
上图报文段4发起终止连接,它由客户端关闭连接时发出。这在我们键入quit命令后发生。它将导致 TCP客户端发送一个FIN,用来关闭从客户到服务器的数据传送。
当服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加 1(报文段5)。和SYN一样,一个FIN将占用一个序号。同时TCP服务器还向应用程序(即丢弃服务器)传送一个文件结束符。接着这个服务器程序就关闭它的连接,导致它的 TCP端发送一个FIN(报文段6),客户必须发回一个确认,并将确认序号设置为收到序号加1(报文段7)。
3. 最大报文段长度
最大报文段长度(MSS)表示TCP传往另一端的最大块数据的长度。当一个连接建立时,连接的双方都要通告各自的 MSS。我们已经见过 MSS都是1024。这导致IP数据报通常是40字节长:20字节的TCP首部和20字节的IP首部。
细说断开的四次握手:
看图可知,主动关闭的一方发出 FIN(也错在服务端主动发送FIN哦),同时进入 FIN_WAIT1 状态,被动关闭的一方响应 ACK,从而使主动关闭的一方迁移至 FIN_WAIT2 状态,接着被动关闭的一方同样会发出 FIN,主动关闭的一方响应 ACK,同时迁移至 TIME_WAIT 状态。
Time-wait状态就是发生在主机A返回最后一个数据包之后,如下图所示,当主机A的套接字进入Time-wait状态后,该套接字绑定的端口号将在这段时间内不能被其他套接字使用,这就是当我们使用Ctrl+C结束服务端程序后,马上再使用该端口启动服务端时会出现bind error的原因(Ctrl+C虽然是强制关闭服务器端,但是断开TCP的连接时也会经历上述四个握手过程)。
连接双方在完成数据传输之后就需要断开连接。由于TCP连接是属于全双工的,即连接双方可以在一条TCP连接上互相传输数据,因此在断开时存在一个半关闭状态,即有有一方失去发送数据的能力,却还能接收数据。因此,断开连接需要分为四次。主要过程如下:
step1. 主机A向主机B发起断开连接请求,之后主机A进入FIN-WAIT-1状态;
step2. 主机B收到主机A的请求后,向主机A发回确认,然后进入CLOSE-WAIT状态;
step3. 主机A收到B的确认之后,进入FIN-WAIT-2状态,此时便是半关闭状态,即主机A失去发送能力,但是主机B却还能向A发送数据,并且A可以接收数据。此时主机B占主导位置了,如果需要继续关闭则需要主机B来操作了;
step4. 主机B向A发出断开连接请求,然后进入LAST-ACK状态;
step5. 主机A接收到请求后发送确认,进入TIME-WAIT状态,等待2MSL之后进入CLOSED状态,而主机B则在接受到确认后进入CLOSED状态;
为何主机A在发送了最后的确认后没有进入CLOSED状态,反而进入了一个等待2MSL的TIME-WAIT主要作用有两个:
第一,确保主机A最后发送的确认能够到达主机B。如果处于LAST-ACK状态的主机B一直收不到来自主机A的确认,它会重传断开连接请求,然后主机A就可以有足够的时间去再次发送确认。但是这也只能尽最大力量来确保能够正常断开,如果主机A的确认总是在网络中滞留失效,从而超过了2MSL,最后也无法正常断开;
第二,如果主机A在发送了确认之后立即进入CLOSED状态。假设之后主机A再次向主机B发送一条连接请求,而这条连接请求比之前的确认报文更早地到达主机B,则会使得主机B以为这条连接请求是在旧的连接中A发出的报文,并不看成是一条新的连接请求了,即使得这个连接请求失效了,增加2MSL的时间可以使得这个失效的连接请求报文作废,这样才不影响下次新的连接请求中出现失效的连接请求。
为什么断开连接请求报文只有三个,而不是四个因为在TCP连接过程中,确认的发送有一个延时(即经受延时的确认),一端在发送确认的时候将等待一段时间,如果自己在这段事件内也有数据要发送,就跟确认一起发送,如果没有,则确认单独发送。而我们的抓包实验中,由服务器端先断开连接,之后客户端在确认的延迟时间内,也有请求断开连接需要发送,于是就与上次确认一起发送,因此就只有三个数据报了。