(四)深入浅出TCPIP之TCP三次握手和四次挥手(下)的抓包分析

两盒软妹~` 提交于 2020-12-05 15:11:46

目录

1. 通过netstat来分析服务器和客户端的TCP状态

2.通过tcpdump抓包分析服务器和客户端的TCP状态

2.1 语法

2.2 抓包返回格式

2.3 抓包的FLags标记 

2.4 分析三次握手,数据收发,四次挥手的状态

2.4.1三次握手

2.4.2数据发送

2.4.3 四次挥手


专栏其他文章:

 

理论篇:

(一)深入浅出TCPIP之理解TCP报文格式和交互流程

  (二)深入浅出TCPIP之再识TCP,理解TCP三次握手(上)

  (三)深入浅出TCPIP之再识TCP,理解TCP四次挥手(上)

  (四)深入浅出TCPIP之TCP三次握手和四次挥手(下)的抓包分析

  (五)深入浅出TCPIP之TCP流量控制

  (六)深入浅出TCPIP之TCP拥塞控制

  (七)深入浅出TCPIP之深入浅出TCPIP之TCP重传机制

 (八)深入浅出TCPIP之TCP长连接与短连接详解

 (九)深入浅出TCPIP之网络同步异步

 (十)深入浅出TCPIP之网络阻塞和非阻塞

(十一)深入浅出TCPIP之TCP粘包问题

  (十二)深入浅出TCPIP之Nagle算法

  (十三) 深入浅出TCPIP之TCP套接字参数

  (十四)深入浅出TCPIP之初识UDP理解报文格式和交互流程

  (十五)非常全面的TCPIP面试宝典-进入大厂必备总结

 (十六)深入浅出TCPIP之Hello CDN

 ....

(二十)深入浅出TCPIP之epoll的一些思考

实践篇:

   深入浅出TCPIP之实战篇—用c++开发一个http服务器(二十一)

其他实践篇+游戏开发中的网络问题疑难杂症解读 正在完善。。。

我们在第二章和第三章讲了三次握手和四次挥手,那么这一章节我将带领读者来通过tcpdump工具来抓包分析这两个过程。

按照我第一章文章里初识TCP,理解TCP报文格式和交互流程(一)提供的客户端和服务器代码进行本次试验。

首先编译客户端和服务器代码:

gcc -g -o server server.c

gcc -g -o client  client.c

1. 通过netstat来分析服务器和客户端的TCP状态

关于netstat的用法我这里不赘述,网上可以找到大量的学习资料。

1.先启动服务器:

2.查看服务器的端口状态:

此时服务器的端口在调用listen之后开始监听客户端的连接,此时服务器的连接状态变成LISTEN。

3.启动客户端:

4.查看服务器和客户端的端口状态

这里注意,我们发现多了两行记录,第二行代表的是服务器本地已经连接到客户端,并且监听的客户端端口是58344,第三行代表的是本地客户端端口是58344,连接的是远端ip为172.16.0.9,端口为8888的服务器。既然新增的两个状态都是ESTABLISHED说明双方三次握手已经建立并正在通信。

5.主动关闭掉客户端查看端口状态

我们发现客户端当前的状态发生了变化 FIN_WAIT2,实际上这就是著名的半关闭的状态了,这是在客户端断开的时候发送了FIN包,服务端处于CLOSE_WAIT状态。为什么会发生这个变化,可以我们参考  TCP,理解TCP报文格式和交互流程(一)

存在CLOSE_WAIT的原因

CLOSE_WAIT这个状态存在于服务端,当服务端发送FIN(之前客户端已经发送过fin),请求关闭连接之后进入CLOSE_WAIT,然而没有收到客户端的响应,可能由于客户端掉线了(如网络故障或者掉电),没有及时给予客户端回复造成问题。
或者由于客户端已经调用close(socket)退出,而服务端对其监测并断开连接,这种是服务端问题。
解决方法:一般是编程问题,可用KEEP_ALIVE机制加以解决

存在FIN_WAIT2的原因

这个状态存在于主动发起断开请求的一端,如果服务器存在大量的这个状态,那么这个服务器就充当客户端的角色,如网络爬虫,出现的原因是由于客户端发起FIN请求结束连接之后,收到了服务端的应答之后进入FIN_WAIT2,之后就没收到服务端发送的FIN信号导致。
解决方法:可以配置FIN_WAIT2的时长,当超过时长后自动断开加以解决

我想这个问题你应该明白了。

6.主动关闭服务器

如果我们先关掉服务器呢,看下现在的状态:

现在客户端的状态怎么变成了CLOSE_WAIT呢,实际上产生CLOSE_WAIT状态的一方,是属于被动关闭的一方,用简单的话对解释上图(主动关闭方为A,被动关闭方为B):

A发一条FIN(关闭)请求给B,说我要关闭了;

B回应一条ACK(确认)请求给A,说我知道了,你关吧,此时B就会进行CLOSE_WAIT状态;

B发送一条FIN(关闭)请给A,说我要关闭了;

A收到发送一条ACK(确认)消息说,你关闭吧。

上面四次握手完成后,双方的连接就都关闭了,但是这里在客户端产生了CLOSE_WAIT现象,首先可以确定的是服务端主动关闭的连接,且客户端没有给服务端发送关闭的请求(第三次握手请求),就会一直处在CLOSE_WAIT的状态,可是客户端为什么不向服务端发送关闭的请求,它当时在忙什么呢,原来服务端在调用关闭时,而客户端正在执行RECV(数据接收),这时候有可能服务端发送的FIN包客户端接收出错,就是由TCP代回了一个ACK包,所以客户端就会处在CLOSE_WAIT的状态中。

2.通过tcpdump抓包分析服务器和客户端的TCP状态

2.1 语法

类型的关键字

host(缺省类型): 指明一台主机,如:tcpdump host 210.27.48.2

net: 指明一个网络地址,如:tcpdump  net 202.0.0.0

port: 指明端口号,如:tcpdump  port 23

确定方向的关键字

src: src 210.27.48.2, IP包源地址是210.27.48.2

dst: dst net 202.0.0.0, 目标网络地址是202.0.0.0

dst or src(缺省值)

dst and src

协议的关键字:缺省值是监听所有协议的信息包

其他更多用法通过tcpdump用法查看。

2.2 抓包返回格式

16:38:11.960274 IP 106.53.211.6.54296 > VM_0_9_centos.ddi-tcp-1: Flags [P.], seq 2552352431:2552352437, ack 1375985570, win 229, options [nop,nop,TS val 585232425 ecr 585202018], length 6

 16:38:11.960274                     

●网络包发生的时间 

 IP 106.53.211.6.54296 > VM_0_9_centos.ddi-tcp-1

●IP标识 
●源ip或者源主机名和端口54296;
●>流向符,数据包从左边发往右边
●目的ip或者目的主机名和端口443



Flags [P.]

●Flags的标记,此处为[P.]数据推送
 

seq 2552352431:2552352437, ack 1375985570, win 229, options [nop,nop,TS val 585232425 ecr 585202018], length 6

●seq为序列号
●ack为确认码
●win为滑动窗口大小
●length为承载的数据(payload)长度length, 如果没有数据则为0


2.3 抓包的FLags标记 

 tcpdump的Flags代表了这个数据包的用途,这些标记是TCP首部的内容 
[S]: SYN同步标识 
[.]: .表示ACK确认标识 
[S.]: SYN同步标识,以及确认[S]的ACK 
[P.]: PSH,push推送, 数据传输 
[R.]: RST,连接重置 
[F]: FIN结束连接 
[DF]: Don't Fragment ,当DF=0时, 示允许分片,一般-v时才有这个标识 
[FP.]:标记FIN、PUSH、 ACK组合,这样做是为了提升网络效率,减少数据来回确认等 







2.4 分析三次握手,数据收发,四次挥手的状态

客户端和服务器启动:

2.4.1三次握手

服务器端:

[root@VM_0_9_centos unit_test]# tcpdump -i eth0  port 8888
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
17:38:17.816221 IP 120.132.11.203.48096 > VM_0_9_centos.ddi-tcp-1: Flags [S], seq 734888645, win 65044, options [mss 1412,sackOK,TS val 1928888411 ecr 0,nop,wscale 7], length 0
17:38:17.816395 IP VM_0_9_centos.ddi-tcp-1 > 120.132.11.203.48096: Flags [S.], seq 1632166146, ack 734888646, win 28960, options [mss 1460,sackOK,TS val 588838281 ecr 1928888411,nop,wscale 7], length 0
17:38:17.848272 IP 120.132.11.203.48096 > VM_0_9_centos.ddi-tcp-1: Flags [.], ack 1, win 509, options [nop,nop,TS val 1928888444 ecr 588838281], length 0

客户端:

root@10-23-185-135:/home/ubuntu# tcpdump -i eth0  port 8888
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
17:38:17.797373 IP 10.23.185.135.48096 > 106.53.211.6.8888: Flags [S], seq 734888645, win 65044, options [mss 1414,sackOK,TS val 1928888411 ecr 0,nop,wscale 7], length 0
17:38:17.830081 IP 106.53.211.6.8888 > 10.23.185.135.48096: Flags [S.], seq 1632166146, ack 734888646, win 28960, options [mss 1412,sackOK,TS val 588838281 ecr 1928888411,nop,wscale 7], length 0
17:38:17.830139 IP 10.23.185.135.48096 > 106.53.211.6.8888: Flags [.], ack 1, win 509, options [nop,nop,TS val 1928888444 ecr 588838281], length 0

通过发送时间上看到:

1.先是在17:38:17.797373的时候客户端向服务器发送SYN序列,序列号是734888645( Falgs[S] 表明是SYN同步标识 )

2.服务器在17:38:17.816221的时候收到客户端的请求SYN序列734888645( Falgs[S] 表明是SYN同步标识 ),接着服务器向客户端发送序列号seq 1632166146, ack 734888646,  此时客户端在17:38:17.830081的时候收到了该次SYN同步标识以及确认[S]的ACK,seq 1632166146, ack 734888646。

3.客户端收到SYN同步标识以及确认[S]的ACK之后,在17:38:17.830139向服务器发送ACK确认,ack 1。  此时服务器也收到该次确认17:38:17.848272 IP 120.132.11.203.48096 > VM_0_9_centos.ddi-tcp-1: Flags [.], ack 1 

整个三次握手就是这样建立的。

2.4.2数据发送

客户端:

17:38:46.885233 IP 10.23.185.135.48096 > 106.53.211.6.8888: Flags [P.], seq 1:11, ack 1, win 509, options [nop,nop,TS val 1928917499 ecr 588838281], length 10
17:38:46.918039 IP 106.53.211.6.8888 > 10.23.185.135.48096: Flags [.], ack 11, win 227, options [nop,nop,TS val 588867369 ecr 1928917499], length 0

服务器:

17:38:46.904117 IP 120.132.11.203.48096 > VM_0_9_centos.ddi-tcp-1: Flags [P.], seq 1:11, ack 1, win 509, options [nop,nop,TS val 1928917499 ecr 588838281], length 10
17:38:46.904182 IP VM_0_9_centos.ddi-tcp-1 > 120.132.11.203.48096: Flags [.], ack 11, win 227, options [nop,nop,TS val 588867369 ecr 1928917499], length 0

顺水推舟,这里就不赘述了,想必大家也根据Flags看到当前的状态,以及发送的包长 (发送的是”helloworld“ ,所以length是10)

2.4.3 四次挥手

客户端:

18:08:10.116986 IP 10.23.185.135.48206 > 106.53.211.6.8888: Flags [F.], seq 1, ack 1, win 509, options [nop,nop,TS val 1930680740 ecr 590615825], length 0
18:08:10.147985 IP 106.53.211.6.8888 > 10.23.185.135.48206: Flags [.], ack 2, win 227, options [nop,nop,TS val 590630604 ecr 1930680740], length 0

服务器:

18:08:10.138686 IP 120.132.11.203.48206 > VM_0_9_centos.ddi-tcp-1: Flags [F.], seq 1, ack 1, win 509, options [nop,nop,TS val 1930680740 ecr 590615825], length 0
18:08:10.139077 IP VM_0_9_centos.ddi-tcp-1 > 120.132.11.203.48206: Flags [.], ack 2, win 227, options [nop,nop,TS val 590630604 ecr 1930680740], length 0

由于此时是客户端主动断开连接,向服务器发送了FIN结束连接 ,而且服务器端也没有需要给客户端发送的数据处理,因此直接断开连接发送ACK确认。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!