点击上方 "编程技术圈"关注, 星标或置顶一起成长

后台回复“大礼包”有惊喜礼包!

日英文

Do not deliberately pursue certain things, falling leaves, belongs to me, it'll always be back.

不去刻意追求某些东西,落叶归根,属于我的,它总会回来。

每日掏心话

风还是一样的吹,花还是一样地开,我相信所谓的命运不过是一个人的生理,心理,情感,性格等等因素所造成的一个人行动的最终结果。

责编:乐乐 | 来自:木木匠 | 链接:url.cn/5ER9kt2

编程技术圈(ID:study_tech)第 1198 次推文

往日回顾:推荐一个高仿微信的项目 有点屌!!

     

   正文   

今天这篇文章我们用抓包分析工具来分析 HTTP 请求是怎么样的?环境准备本来是想找个网站进行抓包分析的,但是正式环境的网站 HTTP 请求太多,干扰太多,对分析不太友好,所以简单些了一个 demo,对 HTTP 请求返回字符串。
环境:
1.响应http请求的服务demo
2.客户端ip:192.168.2.135
3.服务端:45.76.105.92
4.抓包工具:Wireshark
把 demo部署到服务器,启动成功访问如下:打开抓包工具 Wireshark 进行抓包,抓包结果如下:从上图我们已经看到成功抓包到一次 HTTP 请求和响应了,但是我们看到却有很多 TCP请求,接下来我们来分析下这些 TCP 请求是做什么的?
抓包分析A) 三次握手最开始是本地发送了2次请求到服务器,这里为什么会有两次请求,稍后再说,我们先主要看 HTTP 对应的端口请求,如下:
192.168.2.135:60738---->45.76.105.92:8081
看上面的截图我们知道这是 TCP 协议的第一次握手,熟悉 TCP 协议的同学肯定知道 TCP 建立连接有三次握手,断开连接有四次挥手。
我们先看第一次请求:
60738 -> 8081 [SYN] Seq=0Win=64240Len=0Mss=1460Ws=256 SACK_PERM=1
我们来解析下这段包请求信息:
60783->8081 端口号:源端口--->目标端口
[SYN] :同步握手信号
Seq : 消息编号
Win: TCP 窗口大小
Len: 消息长度
Mss: 最大报文段长度
Ws: 窗口缩放调整因子
SACK_PERM : SACK选项,这里等于1表示开启 SACK。
对于上面的概念,这里简单解释下,再介绍之前我们先看 TCPHeader 的数据结构图,对 TCP 头部数据结构有个直观的了解
搜索公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。1. Win: TCP 窗口大小,是指 TCP传输能接受的最大字节数,这个可以进行动态调节,也就是 TCP的滑动窗口,通过动态调整窗口大小,来控制发送数据的速率。上图中占用 2个字节,也就是 16位,那么可以支持的最大数就是 2^16=65536,所以默认情况下 TCP头部标记能支持的最大窗口数是 65536字节,也就是 64KB。
2. Len: 消息长度 就是指数据报文段,因为整个 TCP报文 = Header + packSize,所以这个消息长度就是指要传送的数据包总共长度,在本次分析中也就是 HTTP报文的大小。
3. Mss: 最大报文段长度:这个就是规定最大的能传输报文的长度,为了达到最佳的传输效能, TCP 协议在建立连接的时候通常要协商双方的 MSS 值,这个值 TCP 协议在实现的时候往往用 MTU 值代替(需要减去 IP数据包包头的大小 20Bytes和 TCP数据段的包头 20Bytes)所以一般 MSS 值 1460,这也和我们抓包图中的值一致。
4. Ws: 窗口缩放调整因子:在前面说 TCP 窗口大小中我们说到,默认情况下, TCP 窗口大小最大只能支持 64KB的缓冲数据,在今天这个高速上网时代,这个大小肯定不满足条件了,所以,为了能够支持更多的缓冲数据 RFC 1323中就规定了 TCP 的扩展选项,其中窗口缩放调整因子就是其中之一,这个是如何起作用的呢?首先说明,这个参数是在 [SYN] 同步阶段进行协商的,我们结合上面抓包数据分析下。我们看到第一次请求协商的结果是 WS=256,然后再 ACK 阶段扩展因子生效,调整了窗口大小。生效的抓包如下:
60738 ->8081   [ACK] Seq=1 ACK=1Win=66560Len=0
我们发现这个窗口变成了 66560,比默认的窗口要大,我们查看报文详情:我们发现,实际请求声明的窗口是 260, WS扩展因子是 256,最终计算的窗口大小是 66560,所以我们知道了,这个扩展因子的作用就是,用原窗口大小乘以扩展因子,得到最终的窗口大小,也就是 260*256=66560.
5. SACK_PERM:SACK选项 ,我们知道 TCP 传输有包的确认机制,默认情况下,接受端接受到一个包后,发送 ACK 确认,但是,默认只支持顺序的确认,也就是说,发送 A, B, C 个包,如果我收到了 A, C的包, B没有收到,那么对于 C,这个包我是不会确认的,需要等 B这个包收到后再确认,那么 TCP有超时重传机制,如果一个包很久没有确认,就会当它丢失了,进行重传,这样会造成很多多余的包重传,浪费传输空间。为了解决这个问题, SACK就提出了选择性确认机制,启用 SACK 后,接受端会确认所有收到的包,这样发送端就只用重传真正丢失的包了。
简单介绍了上面的基础概念后,我们来根据抓包梳理下 HTTP 请求的过程,根据 HTTP 请求本地端口是 60378,梳理的流程如下:
------------------------请求连接--------------------------
1) 60738 -> 8081 [SYN] Seq=0Win=64240Len=0Mss=1460Ws=256 SACK_PERM=1
2) 8081 -> 60738 [SYN,ACK] Seq=0 ACK =1Win=29200Len=0 MSS=1420 SACK_PERM=1 WS=128
3) 60738 -> 8081  [ACK] Seq=1 ACK=1Win=66560Len=0
4) Get /test HTTP/1.1
5) 8081 -> 60738  [ACK] Seq=1 ACK=396Win=30336Len=0
6) HTTP/1.1200 (text/html)
7) 60738 -> 8081  [ACK] Seq=396 ACK=120Win=66560Len=0
------------------断开连接-----------------------------
8) 60738 -> 8081 [FIN ACK] Seq=396Ack=120Win=66560Len=0
9) 8081 -> 60738  [FIN ACK] Seq=120Ack=397Win=30336Len=0
10) 60738 -> 8081 [ACK] Seq=397Ack=121Win=66560Len=0
我们根据上面的流程梳理,可以知道, 序号1- 序号3是明显的三次握手,然后 序号4进行了一次 HTTP 请求,接着 序号5是对 HTTP 请求的一次接收确认, 序号6是响应 HTTP 请求, 序号7是对响应请求的确认。
B) 四次挥手上述序号 8, 9, 10 是我关闭浏览器后抓到的包,既然是关闭浏览器,我们肯定知道就是 TCP 连接的断开了。这里有同学应该已经发现了问题了,我们的断开是 4次挥手,你这抓的包只有三条记录,是你写错了吧?我要告诉你的是,我没有写错,这是真实的抓包抓的,至于为什么是三次,我们来分析一下:
正常情况下,连接断开是 4次挥手的, 4次挥手过程如下图:我们分析这图,挥手流程是这样的:
1. 客户端发起一个断开请求,进入 FIN-WAIT 状态
2. 服务端确认断开请求
3. 服务端立即发送一个断开请求,进入 CLOSE-WAIT 状态
4. 客户端确认服务端断开请求,进入 TIME-WAIT 状态
我们发现上面的 流程2和 流程3都是由服务端发起的,那么有没有可能合并这两个请求,一次发送给客户端?答案是 可以。在 RFC 2581中的 4.2 节有提到, ack可以延迟确认,只要求保证在 500ms之内保证确认包到达即可。在这样的标准下, TCP确认是有可能进行合并延迟确认的,所以,根据这一点,我们推断下面这个包:
9) 8081 -> 60738  [FIN ACK] Seq=120Ack=397Win=30336Len=0
合并了对客户端的 ack确认以及服务端发送的 FIN断开信号包。我们点击该包详情如下:这里红框中体现了,这个 9号包是对 Frame500 的 ACK 确认,我们根据最开始的截图可以知道,这个包就是 8号包
8) 60738 -> 8081 [FIN ACK] Seq=396Ack=120Win=66560Len=0并且 9号包 本身自己是发送的 FIN 信号包,所以,我们可以认为 9号包合并了 ACK 和 FIN 的内容,所以通常的 4次挥手,经过合并后变成了 3次挥手。
以上就是一个 HTTP 完整的请求,整个流程用图表示如下:C) Keep-Alive这里肯定有同学会问,既然这是一次完整的 HTTP 请求,那么是不是每次请求都会有三次握手吗?
答案是:目前的协议是不用的
在 HTTP0.9 版本和 HTTP1.0 版本中,每次请求响应都是要三次握手的, 但是 HTTP1.0 开始尝试持续连接,也就是 Keep-Alive 参数,但是官方还没有正式支持,在 HTTP1.1协议中,官方默认就是支持 Keep-Alive 参数的,默认是持续连接。 Keep-Alive 的作用主要有两点:
1.检查死节点
2.防止连接由于不活跃而断开
检查死节点
主要是为了让连接快速失败被发现,可以进行重新连接,比如 A 和 B 两端已经建立了连接, B节点因为 异常原因挂掉了,同时 A 节点并不知道,这时候有两种情况:
1.假设 B 节点还没有恢复,那么 B 节点不会回复 ACK, A节点就会一直重试,重试到一定次数才能知道 B 节点是死节点。
2. B节点在 A发送数据之前重启成功了,这个时候 A节点发送数据, B节点并不会接受,而是会发送一个 RST 信号(在一个已关闭的 socket 上收到数据时,将发送 RST数据包,要求对端关闭异常连接且对端不需要回复 ACK),然后 A 才知道 B 节点需要重连了。
以上两种情况,都会导致只有到发送数据的时候才知道对方已经出异常了。而 Keep-Alive 每隔一段时间就会发送心跳,就可以很快的知道服务端节点的情况。
防止连接由于不活跃而断开
我们知道,网络连接的建立和维持是消耗资源的,一个服务器上能建立的连接是有限的,所以像防火墙或者操作系统中会为了节省资源会释放掉不活跃的连接,而 Keep-Alive 每隔一段时间发送一个心跳包,就是告诉防火墙或者操作系统,我这个连接是活跃的,不要杀我。
后来重新抓了一次带有 Keep-Alive 的包,截图如下:在上图中最后两个包就是发的 Keep-Alive 包,然后服务端进行 ACK 确认,我们看到 keep-alive 包,实际上是会发带有一个字节的包,这就是 keep-alive 的实现。
说完 Keep-Alive,我们回到最开始的问题,为啥一次 HTTP 请求会有进行两个端口的握手呢?其实,这个和协议本身没有任何关系,第一个抓包的截图是用谷歌浏览器访问的,最后一个抓包图是用火狐浏览器访问的,仔细对比我们发现,火狐浏览器只有一个端口三次握手。所以这种情况的发生就是浏览器自身的实现,谷歌浏览器为什么会这么实现,猜测是:尽可能的保证HTTP访问的可用性,当某个端口不可用,可以立即切换到另外一个端口,完成HTTP的请求和响应。(个人猜测,如果有权威解答,可以评论区交流)
总结
HTTP 请求是依托于 TCP 连接的,第一次连接的时候会进行 TCP 的三次握手。
HTTP 通过 Keep-Alive 来进行持久连接,通过定时发送一个心跳包,来告诉服务端自己还活跃。
HTTP 连接的断开也会导致 TCP的四次挥手,但是如果服务器判断满足条件,会合并 ACK 和 FIN 信号,进而转化为三次挥手。PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!欢迎加入后端架构师交流群,在后台回复“学习”即可。在这里,我为大家准备了一份2021年最新最全BAT等大厂Java面试经验总结
别找了,想获取史上最简单的Java大厂面试题学习资料
扫下方二维码回复「手册」就好了猜你还想看
阿里、腾讯、百度、华为、京东最新面试题汇集
HashMap 面试二十一问!看它就够了!新版Win10来了!网友:丑哭了面试这样回答Java调优,至少加1000块!!!嘿,你在看吗?

一次 HTTP 请求到底经历了什么?相关推荐

  1. wx.chooseimage 超过了最大请求长度_一次 HTTP 请求到底经历了什么?

    作者:木木匠 链接:https://url.cn/5ER9kt2 今天这篇文章我们用抓包分析工具来分析 HTTP 请求是怎么样的? 环境准备 本来是想找个网站进行抓包分析的,但是正式环境的网站 HTT ...

  2. android tab pageview,Android Fragment在ViewPager中到底经历了什么?

    2017年05月30 最后的懒加载写的不好,推荐请叫我大苏同学写的Fragment懒加载博客, [Android]再来一篇Fragment的懒加载(只加载一次哦) 在大苏同学的博客评论里,看到了另一个 ...

  3. 从输入URL到浏览器显示页面到底经历了什么?

    文章目录 从输入URL到浏览器显示页面到底经历了什么? DNS解析 1.DNS解析过程 2.DNS优化 建立TCP连接 1.什么是TCP? 2.TCP的连接建立--三次握手 3.为什么是三次握手? 发 ...

  4. 从曾经的无比辉煌,到如今彻底凉凉,万能充到底经历了什么?

    | 作者:手机教授 本文经授权转载自公众号:手机教授(ID:sj9983) 说起万能充,应该是很多80.90后的独特记忆了,当年的万能充可是风靡大街小巷的充电神器,几乎人手一个,后来却逐渐衰落了,如今 ...

  5. 天啦,从Mongo到ClickHouse我到底经历了什么?

    前言: 在实现前端监控系统的最初,使用了 Mongo 作为日志数据存储库.文档型存储,在日志字段扩展和收缩上都能非常方便.天生的 JSON 格式和 NodeJs 配合也非常贴合.就这样度过了几个月的蜜 ...

  6. 一个完整的 Web 请求到底发生了什么

    阅读本文大概需要 7 分钟. 一.从输入一个网址开始 当我们在浏览器输入一个网址,然后按下回车,接下来浏览器显示了页面.网速好的话这之间可能就一秒,但在这一秒内到底发生了什么? 本文主要内容是试图记录 ...

  7. HTTP一次完整的http请求所经历的步骤

    当我们在浏览器的地址栏键入www.linux178.com,然后回车,从回车这一刻到看到页面到底发生了什么呢? 域名解析 发起TCP3次握手 建立TCP连接后发起http请求 服务器响应请求,返回结果 ...

  8. 从URL到页面渲染,到底经历了些啥

    1.构建请求行 GET / HTTP/1.1 2.查找强缓存 命中 -> 使用缓存,返回200 3.DNS解析 检查浏览器自身缓存是否有该域名对应的IP 检查本地host文件网址映射 检查TCP ...

  9. 985毕业的“搬砖人”,从“挂科废材”到程序员,这样的意外崛起,他到底经历了什么?

    背景 大学毕业那年,当同学们要么已然在其它的高校开始研究生生涯,要么在各大厂拿着月薪过万的工资,我只能目送一个个舍友收拾行李离开学校开始新的生活,独自一人呆在宿舍,准备等待 9 月开学后的补考. 我每 ...

最新文章

  1. php方行图片裁剪为圆形,如何将图片裁成圆形、矩形……各种形状?
  2. 6 OC中 isa 和 superclass 的总结
  3. python网格搜索核函数_机器学习笔记——模型调参利器 GridSearchCV(网格搜索)参数的说明...
  4. deepin15.7挂载/home到单独的分区:
  5. history 历史命令记录功能如何防坏人(高级)
  6. 视觉、语音、NLP、ML、AI安全,一家金融科技公司等你来
  7. PTA:图的理论习题集
  8. 物联网卡云平台如何分析信息数据
  9. Mac串口工具(COMTool)
  10. idea 部署 web tomcat
  11. 计算机那种专业包括vr,VR技术的大学专业有哪些
  12. SVG 与 Canvas:如何选择
  13. 多个源文件进行编译,即 makefile 的编写
  14. 免费的局域网协作办公方式—onlyoffice文档协作
  15. 【渝粤教育】电大中专中医基础知识 (3)作业 题库
  16. 去除PDF文件中的斜体文字水印
  17. VUE3(二十四)自定义alert弹窗组件
  18. Android - kotlin 协程极简入门
  19. CLAHE中双线性插值理解
  20. 蓝色微立体图表合集4PPT模板

热门文章

  1. CPA十六--债务重组日的确定(转载)
  2. 【Angular】技术入门
  3. 室内定位程序_高精度室内外一体定位,有怎样的应用前景?
  4. 如何在Github Pages上生成部署简历
  5. 非华为电脑安装华为电脑管家多屏协同
  6. dequeue(enqueue和dequeue)
  7. Pro Android学习笔记 四八 ActionBar 1 Home图标区
  8. 西门子控制东元伺服电机----古月金真
  9. 服务器项目怎么控标,控标参数.doc
  10. 三菱PLC 状态继电器