• 对于注定会优秀的人来说,他所需要的,只是时间!
  • 手懒得,必受贫穷,手勤的,必得富足----《圣经》
  • 帮助别人,成就自己。愿君在本站能真正有所收获!
  • 如果你在本站中发现任何问题,欢迎留言指正!
  • 宝剑锋从磨砺出,梅花香自苦寒来!

实践一次抓包看到TCP的三次握手与四次挥手及其他

系统与优化 eryajf 7个月前 (04-06) 768°C 已收录 0个评论
本文预计阅读时间 11 分钟

1,前言

直到现在,我甚至都没有真正地去实际操作过抓包这个事儿,可能对一个运维工作者来说,这是不可想象的,然而事实就是这样。

我从来没打算逃避自己不会抓包这事儿,这一点在同事们经常脱口而出抓A抓B,而我往往都默不作声即可验证。当然,另一方面,我也从来没打算完全放弃学习抓包,当工作内容越往网络与协议等的深入,我就越觉得这是一个不可回避的事情了。

前几天一个同事分享了《wireshark网络分析的艺术》这本书给我,让我一下子燃起了对抓包以及网络分析的热情,于是就有了这篇文章。

TCP协议的相关内容非常多非常深,不过面试时三次握手四次挥手则是经常出现的问题,工作中我们在面对以及处理一些TCP相关问题时,也都需要用到这些知识,我始终都不敢说自己掌握的多么熟练,今天,借助于第一次抓包的经历,来分享一下TCP的三次握手以及四次挥手。

2,抓包

通过在主机上使用tcpdump进行抓包,将抓包内容保存到文件中,然后再用wireshark进行分析。

localhost —-> http://eryajf.net/1040.html

以本地作为客户端,然后请求远程网站。

先在本机起一个监听程序:

tcpdump -i ens33 -s 0 -n -S host eryajf.net -w eryajf.cap

然后在本机请求远程主机:

curl http://eryajf.net/1040.html

接着停掉抓包程序,将抓包文件down下来,使用wireshark打开。

image-20200406171706472

图中凭借着个人目前对TCP知识的理解,用红框划分了三个阶段,这三个阶段展示了完整的TCP请求的流程。

1–3:是建联时的TCP三次握手。

4–7:进入到HTTP请求与响应的数据交互过程。

8–11:是结束连接的四次挥手流程。

3,见图知意

接下来用大白话浅显的针对每条数据包进行一下简单分析,分析内容中将会依据如上三个阶段进行讲解,并且,因为在这整个过程中,TCP的状态是在不断变化的,往常我们碰到主机TIME_WAIT或者CLOSE_WAIT过多的时候,经常头疼于这些名词的含义,因此争取在这次讲解当中也能够将TCP的状态对应上,以帮助我们理解那些名词。

讲解之前,先引用两张超级厉害的动图来进行一下概括,首先说明,图来自于 https://blog.csdn.net/qzcsu/article/details/72861891 ,人家已经画的足够好,自己就不必在这上头浪费精力了。

三次握手:

format,png

通过三次握手成功建立连接,两端进入数据传输过程。

四次挥手:

format,png-20200406175022701

4,流程浅析

详细说明如下,为了便于对比抓包数据,再次把wireshark的图搬过来:

image-20200406171706472

  • 1.client发起TCP建联请求,通过本机的临时端口34362与远程server80端口通信。标志位为SYN,序列号为seq=x(0), 此处SYN表示客户端请求建立连接。然后,客户端进入SYN_SEND(同步已发送状态)状态,等待服务器的确认。
  • 2.server收到建联请求,通过web端口80client34362端口通信。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1(1),同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN_RCVD(同步收到)状态。
  • 3.TCP客户进程收到确认后,再次向服务器发出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。
    此时可看下图帮助理解
    三次挥手
    图源网络
  • 4.握手完毕,两端都进入ESTABLISHED状态,可以看到client向server端发起了一个HTTP协议(HTTP建联是基于TCP协议的)的GET请求。
  • 5.从info中我们看到了ACK的标志,说明这个包是server回应给client上一个包的请求。
  • 6.这个包同样是从server流向client的,我们在info中看到了,HTTP 301 Moved Permanently,301是一个重定向的状态码,Moved Permanently表明server将请求的资源反馈给client端。前后许多动作都是为了这一步,我们也可以看到这个包的长度为363,是整个请求流程中最大的,表明这次的真正的数据传输。
  • 7.从info中我们再次看到了ACK的标志,说明这个包是client回应给server端表明自己收到了上一个包。整个你来我往的流程就是这样客气。
    注意:当数据传输完毕,客户端不再发起请求,就会进入四次分手阶段。注意分手的话不一定都是客户端先说,因此下边将双方用主机A和主机B来表示。
  • 8.主机A设置Seq和Ack,向主机B发送一个FIN报文段,FIN是关闭连接的标志。此时,主机A进入到FIN_WAIT_1状态,这表示主机A没有数据要发送给主机B了。
    注意:到这个地方需要注意一个细节,因为一些请求的发生时机并非完全顺序执行的,因此可能会有包的记录时间先后顺序不规范的情况。这个地方9与10两个包就应该换一下位置才符合正常分手的程序,不然就成了两个人同时说分手,然后一拍两散了。
  • 9.主机B收到了主机A发送的FIN报文段,向主机A回一个ACK报文段,Ack为Seq都加1,此时主机B进入到CLOSE_WAIT状态,表示我“同意”你的关闭请求。
  • 10.主机A收到B的确认之后,进入FIN_WAIT_2状态,是半关闭状态,即主机A失去发送能力,但是主机B却还能向A发送数据,并且A可以接收数据。此时主机B占主导位置了,如果需要继续关闭则需要主机B来操作了,于是,它操作了,它向主机A发送FIN报文段,请求关闭连接,同时主机B进入LAST_ACK状态。
  • 11.主机A接收到请求后发送ACK确认,然后进入TIME_WAIT状态,等待2MSL之后进入CLOSED状态,而主机B则在接受到确认后即进入CLOSED状态。
    此时可看下图帮助理解
    四次分手
    图源网络

本文基于个人目前对TCP相关知识的理解而写,可能会有错漏的地方,如果有人发现,欢迎指出交流。

5,思维扩展

关于上边内容的与实际工作的关联,我能想到的大概有如下几点。

1,端口

以往对这块儿的理解不够深入,以为server就启动一个80的服务,然后client直接请求server的这个端口就好了,没想过本机也要启动一个端口。不过话说回来,在理解了之后,就想到端对端通信肯定是要基于两个端口来的,不可能对方起一个80端口,自己就硬生生去请求数据了。

基于此,再扩展一下来看,我们可以通过如下命令查看到CentOS中默认情况下的临时端口分配范围:

[root@eryajf ~]$cat /proc/sys/net/ipv4/ip_local_port_range
32768   60999

可以看到默认给出的范围是32768-60999,而面对一些实际生产环境,这个范围的端口可能是不够用的,如果不够用,那么超过这个范围的请求就会受到影响。于是,我们可以通过调整内核参数来进行修改:

# 添加如下配置
echo "net.ipv4.ip_local_port_range=10240 65000" >> /etc/sysctl.conf
# 重载生效
sysctl -p

正是基于如上知识的了解以及理解,这里才能够体会此处内核参数调优(特意把这个标红,是为了把这个高大上的词汇平凡化)的意义所在。

2,关注TCP状态

正如前边提到的,以往在我听到TIME_WAIT之类的词汇,常常是有一些迷糊的,并不能准确的定位这个状态是发生在整个请求流程的哪一步了,包括CLOST_WAITESTABLISHED等名词。于是,这次在整理本文时,我特地将各个状态在整个流程中标明,以帮助理解。

基于如上理解,也可以扩展一下,实际生产业务当中,有哪些状态是需要我们重点关注的呢?这些状态的数值究竟达到多少才是我们应该去处理的呢?处理的时候应该怎样操作配置才能对症下药呢?

事实上在过去半年多的工作当中,我们曾多次以TCPPrometheus中的对应状态的波动,来倒推开发回头审视自己的代码中的bug的,以及我们自己对一些配置项的合理度。

这里举几个实际生产中的例子来进行说明,某一天,在进行监控巡检的时候,忽的看到有机器的TCP状态如下图所示:

image-20200406201008485

最开始看到的是当前的数值相当大,接着把时间跨度拉大,发现这一现象是从某一刻开始的,而并非一直这么大,后来开发一查代码,果然是在调用连接池的时候,忘记关闭了,如此一来,连接数自然就会越堆越多了。

还有一个例子是我针对一组服务器的TIME_WAIT状态过多地探析与研究,具体可以参考一下CentOS系统里TCP状态中TIME_WAIT超过3万的分析与建议这篇文章。

再有一次就是某组web服务的机器ESTABLISHED状态相当的多,高峰时几乎接近四万,如果不进行处理,如果某一天突然一大波流量进来,可能直接就占满了,从而系统无法处理超出的连接。

其实连接数过多无非也就那么几种情况,要么是真实连接的确多,要么是没有及时将连接关闭导致,因为是web服务,极有可能配置在NGINX那里控制着,果不其然,我看到了配置中的 keepalive_timeout定义的是300(5分钟),尽管这可能不算很长,但是针对请求量本身就很大的主机来说,显然也是不合理的。

于是我将这个情况与开发进行沟通,表明这个数值需要调小,是否会影响对应的实际业务(针对一些特殊长链的场景,如果猛然调小超时时间,可能会带来其他不可知问题),得到的回应是不会影响,于是果断将超时时间改为60(1分钟),没过多久,就在监控中看到了相应的效果。

image-20200406202728030

很多内容是在我们不经意之间串联着的,当我们一直奔忙在实际工作的任务时,可能有时候反而容易忽略一些简单的东西。

好了,这篇文字东扯葫芦西扯瓢地已经说了不少,该去做点饭填补一下空虚的肚皮了。

5,参考


weinxin
扫码订阅本站,第一时间获得更新
微信扫描二维码,订阅我们网站的动态,另外不定时发送WordPress小技巧,你可以随时退订,欢迎订阅哦~

二丫讲梵 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明实践一次抓包看到TCP的三次握手与四次挥手及其他
喜欢 (5)
[如果想支持本站,可支付宝赞助]
分享 (0)
eryajf
关于作者:
学无止境,我愿意无止境学。书山有路,我愿意举身投火,淬炼成金!永远不要忘记,激情的奋进,就是美好的未来!

您必须 登录 才能发表评论!