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

剖析TCP/IP协议建立和释放连接的三次握手与四次挥手过程

2016-12-31 23:22 369 查看
最近在与X公司进行http api联调时积累了一些关于tcp/ip协议建立和释放连接的三次与四次挥手的详细过程,顺便也回顾一下tcp/ip协议方面的知识。本文首先介绍tcp/ip包结构和tcpdump的基本使用方法,到连接建立的三次握手及tcpdump抓包分析,再到连接释放的四次挥手及tcpdump抓包分析。

一、先来了解一下tcp/ip的包结构:



主要说明一下上图中几个字段:

序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:

a. URG:紧急指针(urgent pointer)有效。

b. ACK:确认序号有效。

c. PSH:接收方应该尽快将这个报文交给应用层。

d. RST:重置连接。

e. SYN:发起一个新连接。

f. FIN:释放一个连接。

注意:确认方Ack=发起方Seq+1,后面我们具体看抓包分析。

二、tcpdump的基本使用方法:

tcpdump是Linux中强大的网络数据采集分析工具之一,用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的tcp/udp等包进行分析的工具。

tcpdump的总的输出格式为:系统时间 来源主机.端口 > 目标主机.端口 数据包参数

这里就不再具体展开说明(可自行baidu),主要介绍一下几个常见用法:

a. 抓取经过网卡为eth0到达主机portal.xxx.com的tcp状态为syn、ack、fin的包:
`#tcpdump -i eth0 '(dst host portal.xxx.com) and tcp[tcpflags] & (tcp-syn|tcp-ack|tcp-fin) != 0'`

b. 实时抓取端口号8000的GET包("GET"的十六进制是47455420),然后写入GET.log
#tcpdump -i eth0 '((port 8000) and (tcp[(tcp[12]>>2):4]=0x47455420))' -nnAl -w /tmp/GET.log

具体包数据请见三、四中的说明。
下面正式进入主题:我们需要抓取的是clientYown对网站webServerB的http请求连接的建立与释放的tcp包。


三、连接建立的三次握手及tcpdump抓包分析:

建立TCP连接需要三次握手(Three-Way Handshake),我们结合实践即是指clientYown请求访问webServerB时建立的一个TCP连接,需要客户端和服务端总共发送3个包以确认连接的建立。整个流程如下图所示:



如上图所示,我们具体分析一下过程:

(1)第一次握手:clientYown将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给webServerB,clientYown进入SYN_SENT状态,等待webServerB确认。

(2)第二次握手:webServerB收到数据包后由标志位SYN=1知道clientYown请求建立连接,webServerB将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给clientYown以确认连接请求,webServerB进入SYN_RCVD状态。

(3)第三次握手:clientYown收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给webServerB,webServerB检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,clientYown和webServerB进入ESTABLISHED状态,也就是连接已建立,完成三次握手,随后clientYown与webServerB之间可以开始传输数据了。

具体我们看看tcpdump的抓包:

a. 在webServerB中抓包:

#tcpdump -i lo tcp port 80


b.在clientYown上用wget模拟访问一下webServerB:

#wget "http://webServerB/"


这个时候我们在webServerB上抓到的内容如下:

#tcpdump -i lo tcp port 80
-----------------------------
第1行:22:48:53.373712 IP clientYown.49988 > webServerB.80: Flags [S], seq 1208386797, win 29200, options [mss 1460,sackOK,TS val 1300546024 ecr 0,nop,wscale 7], length 0
第2行:22:48:53.373786 IP webServerB.80 > clientYown.49988: Flags [S.], seq 2895991656, ack 1208386798, win 28960, options [mss 1460,sackOK,TS val 1486897651 ecr 1300546024,nop,wscale 7], length 0
第3行:22:48:53.374048 IP clientYown.49988 > webServerB.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 1300546025 ecr 1486897651], length 0


第一行显示客户端clientYown先发送一个seq 1208386797给服务端,对应上面三次握手示意图中的SYN J

第二行显示服务端确认第一行的请求:seq 1208386797, ack的值为第一行的seq值+1,即(ack 1208386798),同时发送一个请求序列号2895991656。对应下图三次握手中的(SYN K, ACK J+1)

第三行显示客户端确认服务端的请求序号ack 1(第二行中的seq 2895991656),对应下图tcp三路握手中的 (ACK K+1)

四、连接释放的四次挥手及tcpdump抓包分析:

四次挥手(Four-Way Wavehand)即终止TCP连接,指webServerB断开clientYown的一个TCP连接,需要客户端和服务端总共发送4个包以确认连接的断开。整个流程如下图所示:



如上图所示:

1. 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

2. 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。

3. 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

4. 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

具体我们看看tcpdump的抓包:

我们在webServerB上抓到的内容如下:

第1行:22:48:53.375260 IP clientYown.49988 > webServerB.80: Flags [F.], seq 116, ack 110, win 229, options [nop,nop,TS val 1300546026 ecr 1486897652], length 0

第2行:22:48:53.376745 IP webServerB.80 > clientYown.49988: Flags [F.], seq 110, ack 117, win 227, options [nop,nop,TS val 1486897654 ecr 1300546026], length 0

第3行:22:48:53.376995 IP clientYown.49988 > webServerB.80: Flags [.], ack 111, win 229, options [nop,nop,TS val 1300546028 ecr 1486897654], length 0


从上面的内容可以看出(客户端主动关闭连接):

第一行显示:clientYown主动发送了一个FIN给webServerB, 对应FIN M ,其中M的值为116

第二行显示:服务端webServerB确认了客户端clientYown的116(即上图的ACK M+1, 即ack 117),并发送了一个FIN给客户端,对应上图的FIN N

第三行显示:clientYown确认了服务端的FIN ack 111,即上图的ACK N+1

常见问题:

Ask1:为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送,所以需要四步握手。

Ask2:为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息