首页 » 网站建设 » phpcurl抓包技巧_一文教会实战收集抓包和分析包

phpcurl抓包技巧_一文教会实战收集抓包和分析包

访客 2024-12-17 0

扫一扫用手机浏览

文章目录 [+]

#显形“不可见”的网络包

网络天下中的数据包交互我们肉眼是看不见的,它们就彷佛隐形了一样,我们对着教材学习打算机网络的时候就会以为非常的抽象,加大了学习的难度。

phpcurl抓包技巧_一文教会实战收集抓包和分析包

但莫慌,自从有了两大剖析网络包的利器:tcpdump 和 Wireshark,我们“看不见”的数据包,再也没有那么神秘了。

phpcurl抓包技巧_一文教会实战收集抓包和分析包
(图片来自网络侵删)

唉,当初大学学习计网的时候,假如能知道这两个工具,就不会学的一脸懵逼。

tcpdump 和 Wireshark 有什么差异?

tcpdump 和 Wireshark 便是最常用的网络抓包和剖析工具,更是剖析网络性能必不可少的利器。

tcpdump 仅支持命令行格式利用,常用在 Linux 做事器中抓取和剖析网络包。
Wireshark 除了可以抓包外,还供应了可视化剖析网络包的图形页面。

以是,这两者实际上是搭配利用的,先用 tcpdump 命令在 Linux 做事器上抓包,接着把抓包的文件拖出到 Windows 电脑后,用 Wireshark 可视化剖析。

当然,如果你是在 Windows 上抓包,只须要用 Wireshark 工具就可以。

tcpdump 在 Linux 下如何抓包?

tcpdump 供应了大量的选项以及各式各样的过滤表达式,来帮助你抓取指定的数据包,不过不要担心,只须要节制一些常用选项和过滤表达式,就可以知足大部分场景的须要了。

假设我们要抓取下面的 ping 的数据包:

要抓取上面的 ping 命令数据包,首先我们要知道 ping 的数据包是 icmp 协议,接着在利用 tcpdump 抓包的时候,就可以指定只抓 icmp 协议的数据包:

那么当 tcpdump 抓取到 icmp 数据包后, 输出格式如下:

从 tcpdump 抓取的 icmp 数据包,我们很清楚的看到 icmp echo 的交互过程了,首先发送方发起了 ICMP echo request 要求报文,吸收方收到后回了一个 ICMP echo reply 相应报文,之后 seq 是递增的。

我在这里也帮你整理了一些最常见的用法,并且绘制成了表格,你可以参考利用。

首先,先来看看常用的选项类,在上面的 ping 例子中,我们用过 -i 选项指定网口,用过 -nn 选项不对 IP 地址和端口名称解析。
其他常用的选项,如下表格:

接下来,我们再来看看常用的过滤表用法,在上面的 ping 例子中,我们用过的是 icmp and host 183.232.231.174,表示抓取 icmp 协议的数据包,以及源地址或目标地址为 183.232.231.174 的包。
其他常用的过滤选项,我也整理成了下面这个表格。

说了这么多,你该当也创造了,tcpdump 虽然功能强大,但是输出的格式并不直不雅观。

以是,在事情中 tcpdump 只是用来抓取数据包,不用来剖析数据包,而是把 tcpdump 抓取的数据包保存成 pcap 后缀的文件,接着用 Wireshark 工具进行数据包剖析。

Wireshark 工具如何剖析数据包?

Wireshark 除了可以抓包外,还供应了可视化剖析网络包的图形页面,同时,还内置了一系列的汇总剖析工具。

比如,拿上面的 ping 例子来说,我们可以利用下面的命令,把抓取的数据包保存到 ping.pcap 文件

接着把 ping.pcap 文件拖到电脑,再用 Wireshark 打开它。
打开后,你就可以看到下面这个界面:

是吧?在 Wireshark 的页面里,可以更加直不雅观的剖析数据包,不仅展示各个网络包的头部信息,还会用不同的颜色来区分不同的协议,由于这次抓包只有 ICMP 协议,以是只有紫色的条款。

接着,在网络包列表中选择某一个网络包后,在其下面的网络包详情中,可以更清楚的看到,这个网络包在协议栈各层的详细信息。
比如,以编号 1 的网络包为例子:

可以在数据链路层,看到 MAC 包头信息,如源 MAC 地址和目标 MAC 地址等字段;可以在 IP 层,看到 IP 包头信息,如源 IP 地址和目标 IP 地址、TTL、IP 包长度、协议等 IP 协议各个字段的数值和含义;可以在 ICMP 层,看到 ICMP 包头信息,比如 Type、Code 等 ICMP 协议各个字段的数值和含义;

Wireshark 用了分层的办法,展示了各个层的包头信息,把“不可见”的数据包,清清楚楚的展示了给我们,还有情由学不好打算机网络吗?是不是相见恨晚?

从 ping 的例子中,我们可以看到网络分层就像有序的分工,每一层都有自己的任务范围和信息,上层协议完成事情后就交给下一层,终极形成一个完全的网络包。

#解密 TCP 三次握手和四次挥手

既然学会了 tcpdump 和 Wireshark 两大网络剖析利器,那我们快马加鞭,接下来用它俩抓取和剖析 HTTP 协议网络包,并理解 TCP 三次握手和四次挥手的事情事理。

本次例子,我们将要访问的 http://192.168.3.200 做事端。
在终端一用 tcpdump 命令抓取数据包:

接着,在终端二实行下面的 curl 命令:

末了,回到终端一,按下 Ctrl+C 停滞 tcpdump,并把得到的 http.pcap 取出到电脑。

利用 Wireshark 打开 http.pcap 后,你就可以在 Wireshark 中,看到如下的界面:

我们都知道 HTTP 是基于 TCP 协议进行传输的,那么:

最开始的 3 个包便是 TCP 三次握手建立连接的包中间是 HTTP 要乞降相应的包而末了的 3 个包则是 TCP 断开连接的挥手包

Wireshark 可以用时序图的办法显示数据包交互的过程,从菜单栏中,点击 统计 (Statistics) -> 流量图 (Flow Graph),然后,在弹出的界面中的「流量类型」选择 「TCP Flows」,你可以更清晰的看到,全体过程中 TCP 流的实行过程:

你可能会好奇,为什么三次握手连接过程的 Seq 是 0 ?

实际上是由于 Wireshark 工具帮我们做了优化,它默认显示的是序列号 seq 是相对值,而不是真实值。

如果你想看到实际的序列号的值,可以右键菜单, 然后找到「协议首选项」,接着找到「Relative Seq」后,把它给取消,操作如下:

取消后,Seq 显示的便是真实值了:

可见,客户端和做事真个序列号实际上是不同的,序列号是一个随机值。

这实在跟我们书上看到的 TCP 三次握手和四次挥手很类似,作为比拟,你常日看到的 TCP 三次握手和四次挥手的流程,基本是这样的:

为什么抓到的 TCP 挥手是三次,而不是书上说的四次?

当被动关闭方(上图的做事端)在 TCP 挥手过程中,「没有数据要发送」并且「开启了 TCP 延迟确认机制」,那么第二和第三次挥手就会合并传输,这样就涌现了三次挥手。

而常日情形下,做事器端收到客户真个 FIN 后,很可能还没发送完数据,以是就会先回答客户端一个 ACK 包,稍等一下子,完成所有数据包的发送后,才会发送 FIN 包,这也便是四次挥手了。

#TCP 三次握手非常情形实战剖析

TCP 三次握手的过程相信大家都背的滚瓜烂熟,那么你有没有想过这三个非常情形:

TCP 第一次握手的 SYN 丢包了,会发生了什么?TCP 第二次握手的 SYN、ACK 丢包了,会发生什么?TCP 第三次握手的 ACK 包丢了,会发生什么?

有的小伙伴可能说:“很大略呀,包丢了就会重传嘛。

那我在连续问你:

那会重传几次?超时重传的韶光 RTO 会如何变革?在 Linux 下如何设置重传次数?....

是不是哑口无言,无法回答?

不知道没紧要,接下里我用三个实验案例,带大家一起探究探究这三种非常。

#实验场景

本次实验用了两台虚拟机,一台作为做事端,一台作为客户端,它们的关系如下:

客户端和做事端都是 CentOs 6.5 Linux,Linux 内核版本 2.6.32做事端 192.168.12.36,apache web 做事客户端 192.168.12.37

#实验一:TCP 第一次握手 SYN 丢包

为了仿照 TCP 第一次握手 SYN 丢包的情形,我是在拔掉做事器的网线后,急速在客户端实行 curl 命令:

其间 tcpdump 抓包的命令如下:

过了一会, curl 返回了超时连接的缺点:

从 date 返回的韶光,可以创造在超时靠近 1 分钟的韶光后,curl 返回了缺点。

接着,把 tcp_sys_timeout.pcap 文件用 Wireshark 打开剖析,显示如下图:

从上图可以创造, 客户端发起了 SYN 包后,一贯没有收到做事真个 ACK ,以是一贯超时重传了 5 次,并且每次 RTO 超时时间是不同的:

第一次是在 1 秒超时重传第二次是在 3 秒超时重传第三次是在 7 秒超时重传第四次是在 15 秒超时重传第五次是在 31 秒超时重传

可以创造,每次超时时间 RTO 是指数(翻倍)上涨的,当超过最大重传次数后,客户端不再发送 SYN 包。

在 Linux 中,第一次握手的 SYN 超时重传次数,是如下内核参数指定的:

tcp_syn_retries 默认值为 5,也便是 SYN 最大重传次数是 5 次。

接下来,我们连续做实验,把 tcp_syn_retries 设置为 2 次:

$ echo 2 > /proc/sys/net/ipv4/tcp_syn_retries

重传抓包后,用 Wireshark 打开剖析,显示如下图:

实验一的实验小结

通过实验一的实验结果,我们可以得知,当客户端发起的 TCP 第一次握手 SYN 包,在超时时间内没收到做事真个 ACK,就会在超时重传 SYN 数据包,每次超时重传的 RTO 是翻倍上涨的,直到 SYN 包的重传次数到达 tcp_syn_retries 值后,客户端不再发送 SYN 包。

#实验二:TCP 第二次握手 SYN、ACK 丢包

为了仿照客户端收不到做事端第二次握手 SYN、ACK 包,我的做法是在客户端加上防火墙限定,直接粗暴的把来自做事真个数据都丢弃,防火墙的配置如下:

接着,在客户端实行 curl 命令:

从 date 返回的韶光前后,可以算出大概 1 分钟后,curl 报错退出了。

客户端在这其间抓取的数据包,用 Wireshark 打开剖析,显示的时序图如下:

从图中可以创造:

客户端发起 SYN 后,由于防火墙屏蔽了做事真个所有数据包,以是 curl 是无法收到做事真个 SYN、ACK 包,当发生超时后,就会重传 SYN 经办事端收到客户的 SYN 包后,就会回 SYN、ACK 包,但是客户端一贯没有回 ACK,做事端在超时后,重传了 SYN、ACK 包,接着一会,客户端超时重传的 SYN 包又抵达了做事端,做事端收到后,然后回了 SYN、ACK 包,但是SYN、ACK包的重传定时器并没有重置,还持续在重传,由于第二次握手在没收到第三次握手的 ACK 确认报文时,就会重传到最大次数。
末了,客户端 SYN 超时重传次数达到了 5 次(tcp_syn_retries 默认值 5 次),就不再连续发送 SYN 包了。

以是,我们可以创造,当第二次握手的 SYN、ACK 丢包时,客户端会超时重发 SYN 包,做事端也会超时重传 SYN、ACK 包。

咦?客户端设置了防火墙,屏蔽了做事真个网络包,为什么 tcpdump 还能抓到做事真个网络包?

添加 iptables 限定后, tcpdump 是否能抓到包 ,这要看添加的 iptables 限定条件:

如果添加的是 INPUT 规则,则可以抓得到包如果添加的是 OUTPUT 规则,则抓不到包

网络包进入主机后的顺序如下:

进来的顺序 Wire -> NIC -> tcpdump -> netfilter/iptables出去的顺序 iptables -> tcpdump -> NIC -> Wire

tcp_syn_retries 是限定 SYN 重传次数,那第二次握手 SYN、ACK 限定最大重传次数是多少?

TCP 第二次握手 SYN、ACK 包的最大重传次数是通过 tcp_synack_retries 内核参数限定的,其默认值如下:

$ cat /proc/sys/net/ipv4/tcp_synack_retries5

是的,TCP 第二次握手 SYN、ACK 包的最大重传次数默认值是 5 次。

为了验证 SYN、ACK 包最大重传次数是 5 次,我们连续做下实验,我们先把客户真个 tcp_syn_retries 设置为 1,表示客户端 SYN 最大超时次数是 1 次,目的是为了防止多次重传 SYN,把做事端 SYN、ACK 超时定时看重置。

接着,还是如上面的步骤:

客户端配置防火墙屏蔽做事真个数据包客户端 tcpdump 抓取 curl 实行时的数据包

把抓取的数据包,用 Wireshark 打开剖析,显示的时序图如下:

从上图,我们可以剖析出:

客户真个 SYN 只超时重传了 1 次,由于 tcp_syn_retries 值为 1做事端应答了客户端超时重传的 SYN 包后,由于一贯收不到客户真个 ACK 包,以是做事端一贯在超时重传 SYN、ACK 包,每次的 RTO 也是指数上涨的,一共超时重传了 5 次,由于 tcp_synack_retries 值为 5

接着,我把 tcp_synack_retries 设置为 2,tcp_syn_retries 依然设置为 1:

$ echo 2 > /proc/sys/net/ipv4/tcp_synack_retries$ echo 1 > /proc/sys/net/ipv4/tcp_syn_retries

依然保持一样的实验步骤进行操作,接着把抓取的数据包,用 Wireshark 打开剖析,显示的时序图如下:

可见:

客户真个 SYN 包只超时重传了 1 次,符合 tcp_syn_retries 设置的值;做事真个 SYN、ACK 超时重传了 2 次,符合 tcp_synack_retries 设置的值

实验二的实验小结

通过实验二的实验结果,我们可以得知,当 TCP 第二次握手 SYN、ACK 包丢了后,客户端 SYN 包会发生超时重传,做事端 SYN、ACK 也会发生超时重传。

客户端 SYN 包超时重传的最大次数,是由 tcp_syn_retries 决定的,默认值是 5 次;做事端 SYN、ACK 包时重传的最大次数,是由 tcp_synack_retries 决定的,默认值是 5 次。

#实验三:TCP 第三次握手 ACK 丢包

为了仿照 TCP 第三次握手 ACK 包丢,我的实验方法是在做事端配置防火墙,屏蔽客户端 TCP 报文中标志位是 ACK 的包,也便是当做事端收到客户真个 TCP ACK 的报文时就会丢弃。

iptables 配置命令如下:

接着,在客户端实行如下 tcpdump 命令:

然后,客户端向做事端发起 telnet,由于 telnet 命令是会发起 TCP 连接,以是用此命令做测试:

此时,由于做事端收不到第三次握手的 ACK 包,以是一贯处于 SYN_RECV 状态:

而客户端是已完成 TCP 连接建立,处于 ESTABLISHED 状态:

过了 1 分钟后,不雅观察创造做事真个 TCP 连接不见了:

过了 30 分钟,客户端依然还是处于 ESTABLISHED 状态:

接着,在刚才客户端建立的 telnet 会话,输入 123456 字符,进行发送:

持续「好长」一段韶光,客户真个 telnet 才断开连接:

以上便是本次的实现三的征象,这里存在两个疑点:

为什么做事端原来处于 SYN_RECV 状态的连接,过 1 分钟后就消逝了?为什么客户端 telnet 输入 123456 字符后,过了好长一段韶光,telnet 才断开连接?

不焦急,我们把刚抓的数据包,用 Wireshark 打开剖析,显示的时序图如下:

上图的流程:

客户端发送 SYN 包给做事端,做事端收到后,回了个 SYN、ACK 包给客户端,此时做事真个 TCP 连接处于 SYN_RECV 状态;客户端收到做事真个 SYN、ACK 包后,给做事端回了个 ACK 包,此时客户真个 TCP 连接处于 ESTABLISHED 状态;由于做事端配置了防火墙,屏蔽了客户真个 ACK 包,以是做事端一贯处于 SYN_RECV 状态,没有进入 ESTABLISHED 状态,tcpdump 之以是能抓到客户真个 ACK 包,是由于数据包进入系统的顺序是前辈入 tcpudmp,后经由 iptables;接着,做事端超时重传了 SYN、ACK 包,重传了 5 次后,也便是超过 tcp_synack_retries 的值(默认值是 5),然后就没有连续重传了,此时做事真个 TCP 连接主动中止了,以是刚才处于 SYN_RECV 状态的 TCP 连接断开了,而客户端依然处于ESTABLISHED 状态;虽然做事端 TCP 断开了,但过了一段韶光,创造客户端依然处于ESTABLISHED 状态,于是就在客户真个 telnet 会话输入了 123456 字符;由于做事真个防火墙配置了屏蔽所有携带 ACK 标志位的 TCP 报文,客户端发送的数据报文,做事端并不会吸收,而是丢弃(如果做事端没有设置防火墙,由于做事端已经断开连接,此时收到客户的发来的数据报文后,会回 RST 报文)。
客户端由于一贯收不到数据报文的确认报文,以是触发超时重传,在超时重传过程中,每一次重传,RTO 的值是指数增长的,以是持续了好长一段韶光,客户真个 telnet 才报错退出了,此时共重传了 15 次,然后客户真个也断开了连接。

通过这一波剖析,刚才的两个疑点已经解除了:

做事端在重传 SYN、ACK 包时,超过了最大重传次数 tcp_synack_retries,于是做事真个 TCP 连接主动断开了。
客户端向做事端发送数据报文时,如果迟迟没有收到数据包的确认报文,也会触发超时重传,一共重传了 15 次数据报文, 末了 telnet 就断开了连接。

TCP 第一次握手的 SYN 包超时重传最大次数是由 tcp_syn_retries 指定,TCP 第二次握手的 SYN、ACK 包超时重传最大次数是由 tcp_synack_retries 指定,那 TCP 建立连接后的数据包最大超时重传次数是由什么参数指定呢?

TCP 建立连接后的数据包传输,最大超时重传次数是由 tcp_retries2 指定,默认值是 15 次,如下:

$ cat /proc/sys/net/ipv4/tcp_retries215

如果 15 次重传都做完了,TCP 就会见告运用层说:“搞不定了,包怎么都传不过去!

那如果客户端不发送数据,什么时候才会断开处于 ESTABLISHED 状态的连接?

这里就须要提到 TCP 的 保活机制。
这个机制的事理是这样的:

定义一个韶光段,在这个韶光段内,如果没有任何连接干系的活动,TCP 保活机制会开始浸染,每隔一个韶光间隔,发送一个「探测报文」,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到相应,则认为当前的 TCP 连接已经去世亡,系统内核将缺点信息关照给上层运用程序。

在 Linux 内核可以有对应的参数可以设置保活韶光、保活探测的次数、保活探测的韶光间隔,以下都为默认值:

net.ipv4.tcp_keepalive_time=7200net.ipv4.tcp_keepalive_intvl=75 net.ipv4.tcp_keepalive_probes=9tcp_keepalive_time=7200:表示保活韶光是 7200 秒(2小时),也就 2 小时内如果没有任何连接干系的活动,则会启动保活机制tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;tcp_keepalive_probes=9:表示检测 9 次无相应,认为对方是不可达的,从而中断本次的连接。

也便是说在 Linux 系统中,最少须要经由 2 小时 11 分 15 秒才可以创造一个「去世亡」连接。

这个韶光是有点长的,以是如果我抓包足够久,或许能抓到探测报文。

实验三的实验小结

在建立 TCP 连接时,如果第三次握手的 ACK,做事端无法收到,则做事端就会短暂处于 SYN_RECV 状态,而客户端会处于 ESTABLISHED 状态。

由于做事端一贯收不到 TCP 第三次握手的 ACK,则会一贯重传 SYN、ACK 包,直到重传次数超过 tcp_synack_retries 值(默认值 5 次)后,做事端就会断开 TCP 连接。

而客户端则会有两种情形:

如果客户端没发送数据包,一贯处于 ESTABLISHED 状态,然后经由 2 小时 11 分 15 秒才可以创造一个「去世亡」连接,于是客户端连接就会断开连接。
如果客户端发送了数据包,一贯没有收到做事端对该数据包的确认报文,则会一贯重传该数据包,直到重传次数超过 tcp_retries2 值(默认值 15 次)后,客户端就会断开 TCP 连接。

#TCP 快速建立连接

客户端在向做事端发起 HTTP GET 要求时,一个完全的交互过程,须要 2.5 个 RTT 的时延。

由于第三次握手是可以携带数据的,这时如果在第三次握手发起 HTTP GET 要求,须要 2 个 RTT 的时延。

但是不才一次(不是同个 TCP 连接的下一次)发起 HTTP GET 要求时,经历的 RTT 也是一样,如下图:

在 Linux 3.7 内核版本中,供应了 TCP Fast Open 功能,这个功能可以减少 TCP 连接建立的时延。

在第一次建立连接的时候,做事端在第二次握手产生一个 Cookie (已加密)并通过 SYN、ACK 包一起发给客户端,于是客户端就会缓存这个 Cookie,以是第一次发起 HTTP Get 要求的时候,还是须要 2 个 RTT 的时延;不才次要求的时候,客户端在 SYN 包带上 Cookie 发给做事端,就提前可以跳过三次握手的过程,由于 Cookie 中掩护了一些信息,做事端可以从 Cookie 获取 TCP 干系的信息,这时发起的 HTTP GET 要求就只须要 1 个 RTT 的时延;

注:客户端在要求并存储了 Fast Open Cookie 之后,可以不断重复 TCP Fast Open 直至做事器认为 Cookie 无效(常日为过期)

在 Linux 上如何打开 Fast Open 功能?

可以通过设置 net.ipv4.tcp_fastopn 内核参数,来打开 Fast Open 功能。

net.ipv4.tcp_fastopn 各个值的意义:

0 关闭1 作为客户端利用 Fast Open 功能2 作为做事端利用 Fast Open 功能3 无论作为客户端还是做事器,都可以利用 Fast Open 功能

TCP Fast Open 抓包剖析

不才图,数据包 7 号,客户端发起了第二次 TCP 连接时,SYN 包会携带 Cooike,并且长度为 5 的数据。

做事端收到后,校验 Cooike 合法,于是就回了 SYN、ACK 包,并且确认应答收到了客户真个数据包,ACK = 5 + 1 = 6

#TCP 重复确认和快速重传

当吸收方收到乱序数据包时,会发送重复的 ACK,以便奉告发送方要重发该数据包,当发送方收到 3 个重复 ACK 时,就会触发快速重传,急速重发丢失数据包。

TCP 重复确认和快速重传的一个案例,用 Wireshark 剖析,显示如下:

数据包 1 期望的下一个数据包 Seq 是 1,但是数据包 2 发送的 Seq 却是 10945,解释收到的是乱序数据包,于是回了数据包 3 ,还是同样的 Seq = 1,Ack = 1,这表明是重复的 ACK;数据包 4 和 6 依然是乱序的数据包,于是依然回了重复的 ACK;当对方收到三次重复的 ACK 后,于是就快速重传了 Seq = 1 、Len = 1368 的数据包 8;当收到重传的数据包后,创造 Seq = 1 是期望的数据包,于是就发送了个确认收到快速重传的 ACK

把稳:快速重传和重复 ACK 标记信息是 Wireshark 的功能,非数据包本身的信息。

以上案例在 TCP 三次握手时协商开启了选择性确认 SACK,因此一旦数据包丢失并收到重复 ACK ,纵然在丢失数据包之后还成功吸收了其他数据包,也只须要重传丢失的数据包。
如果不启用 SACK,就必须重传丢失包之后的每个数据包。

如果要支持 SACK,必须双方都要支持。
在 Linux 下,可以通过 net.ipv4.tcp_sack 参数打开这个功能(Linux 2.4 后默认打开)。

#TCP 流量掌握

TCP 为了防止发送方无脑的发送数据,导致吸收方缓冲区被填满,以是就有了滑动窗口的机制,它可利用吸收方的吸收窗口来掌握发送方要发送的数据量,也便是流量掌握。

吸收窗口是由吸收方指定的值,存储在 TCP 头部中,它可以见告发送方自己的 TCP 缓冲空间区大小,这个缓冲区是给运用程序读取数据的空间:

如果运用程序读取了缓冲区的数据,那么缓冲空间区就会把被读取的数据移除如果运用程序没有读取数据,则数据会一贯滞留在缓冲区。

吸收窗口的大小,是在 TCP 三次握手中协商好的,后续数据传输时,吸收方发送确认应答 ACK 报文时,会携带当前的吸收窗口的大小,以此来奉告发送方。

假设吸收方吸收到数据后,运用层能很快的从缓冲区里读取数据,那么窗口大小会一贯保持不变,过程如下:

但是现实中做事器会涌现繁忙的情形,当运用程序读取速率慢,那么缓存空间会逐步被占满,于是为了担保发送方发送的数据不会超过缓冲区大小,做事器则会调度窗口大小的值,接着通过 ACK 报文关照给对方,奉告现在的吸收窗口大小,从而掌握发送方发送的数据大小。

#零窗口关照与窗口探测

假设吸收方处理数据的速率跟不上吸收数据的速率,缓存就会被占满,从而导致吸收窗口为 0,当发送方吸收到零窗口关照时,就会停滞发送数据。

如下图,可以看到吸收方的窗口大小在不断的紧缩至 0:

接着,发送方会定时发送窗口大小探测报文,以便及时知道吸收方窗口大小的变革。

以下图 Wireshark 剖析图作为例子解释:

发送方发送了数据包 1 给吸收方,吸收方收到后,由于缓冲区被占满,回了个零窗口关照;发送方收到零窗口关照后,就不再发送数据了,直到过了 3.4 秒后,发送了一个 TCP Keep-Alive 报文,也便是窗口大小探测报文;当吸收方收到窗口探测报文后,就立马回一个窗口关照,但是窗口大小还是 0;发送方创造窗口还是 0,于是连续等待了 6.8(翻倍) 秒后,又发送了窗口探测报文,吸收方依然还是回了窗口为 0 的关照;发送方创造窗口还是 0,于是连续等待了 13.5(翻倍) 秒后,又发送了窗口探测报文,吸收方依然还是回了窗口为 0 的关照;

可以创造,这些窗口探测报文以 3.4s、6.5s、13.5s 的间隔涌现,解释超时时间会翻倍递增。

这连接停息了 25s,想象一下你在打王者的时候,25s 的延迟你还能上王者吗?

#发送窗口的剖析

在 Wireshark 看到的 Windows size 也便是 " win = ",这个值表示发送窗口吗?

这不是发送窗口,而是在向对方声明自己的吸收窗口。

你可能会好奇,抓包文件里有「Window size scaling factor」,它实在是算呈现实窗口大小的乘法因子,「Window size value」实际上并不是真实的窗口大小,真实窗口大小的打算公式如下:

「Window size value」 「Window size scaling factor」 = 「Caculated window size 」

对应的下图案例,也便是 32 2048 = 65536。

实际上是 Caculated window size 的值是 Wireshark 工具帮我们算好的,Window size scaling factor 和 Windos size value 的值是在 TCP 头部中,个中 Window size scaling factor 是在三次握手过程中确定的,如果你抓包的数据没有 TCP 三次握手,那可能就无法算出真实的窗口大小的值,如下图:

如何在包里看出发送窗口的大小?

很遗憾,没有大略的办法,发送窗口虽然是由吸收窗口决定,但是它又可以被网络成分影响,也便是拥塞窗口,实际上发送窗口是值是 min(拥塞窗口,吸收窗口)。

发送窗口和 MSS 有什么关系?

发送窗口决定了一口气能发多少字节,而 MSS 决定了这些字节要分多少包才能发完。

举个例子,如果发送窗口为 16000 字节的情形下,如果 MSS 是 1000 字节,那就须要发送 1600/1000 = 16 个包。

发送方在一个窗口发出 n 个包,是不是须要 n 个 ACK 确认报文?

不一定,由于 TCP 有累计确认机制,以是当收到多个数据包时,只须要应答末了一个数据包的 ACK 报文就可以了。

#TCP 延迟确认与 Nagle 算法

当我们 TCP 报文的承载的数据非常小的时候,例如几个字节,那么全体网络的效率是很低的,由于每个 TCP 报文中都会有 20 个字节的 TCP 头部,也会有 20 个字节的 IP 头部,而数据只有几个字节,以是在全体报文中有效数据霸占的比重就会非常低。

这就彷佛快递员开着大货车送一个小包裹一样摧残浪费蹂躏。

那么就涌现了常见的两种策略,来减少小报文的传输,分别是:

Nagle 算法延迟确认

Nagle 算法是如何避免大量 TCP 小数据报文的传输?

Nagle 算法做了一些策略来避免过多的小数据报文发送,这可提高传输效率。

Nagle 伪代码如下:

if 有数据要发送 { if 可用窗口大小 >= MSS and 可发送的数据 >= MSS { 急速发送MSS大小的数据 } else { if 有未确认的数据 { 将数据放入缓存等待吸收ACK } else { 急速发送数据 } }}

利用 Nagle 算法,该算法的思路是延时处理,只有知足下面两个条件中的任意一个条件,才能可以发送数据:

条件一:要等到窗口大小 >= MSS 并且 数据大小 >= MSS;条件二:收到之前发送数据的 ack 回包;

只要上面两个条件都不知足,发送方一贯在囤积数据,直到知足上面的发送条件。

上图右侧启用了 Nagle 算法,它的发送数据的过程:

一开始由于没有已发送未确认的报文,以是就急速发了 H 字符;接着,在还没收到对 H 字符的确认报文时,发送方就一贯在囤积数据,直到收到了确认报文后,此时没有已发送未确认的报文,于是就把囤积后的 ELL 字符一起发给了吸收方;待收到对 ELL 字符的确认报文后,于是把末了一个 O 字符发送了出去

可以看出,Nagle 算法一定会有一个小报文,也便是在最开始的时候。

其余,Nagle 算法默认是打开的,如果对付一些须要小数据包交互的场景的程序,比如,telnet 或 ssh 这样的交互性比较强的程序,则须要关闭 Nagle 算法。

可以在 Socket 设置 TCP_NODELAY 选项来关闭这个算法(关闭 Nagle 算法没有全局参数,须要根据每个运用自己的特点来关闭)。

那延迟确认又是什么?

事实上当没有携带数据的 ACK,它的网络效率也是很低的,由于它也有 40 个字节的 IP 头 和 TCP 头,但却没有携带数据报文。

为理解决 ACK 传输效率低问题,以是就衍生出了 TCP 延迟确认。

TCP 延迟确认的策略:

当有相应数据要发送时,ACK 会随着相应数据一起急速发送给对方当没有相应数据要发送时,ACK 将会延迟一段韶光,以等待是否有相应数据可以一起发送如果在延迟等待发送 ACK 期间,对方的第二个数据报文又到达了,这时就会急速发送 ACK

延迟等待的韶光是在 Linux 内核中定义的,如下图:

关键就须要 HZ 这个数值大小,HZ 是跟系统的时钟频率有关,每个操作系统都不一样,在我的 Linux 系统中 HZ 大小是 1000,如下图:

知道了 HZ 的大小,那么就可以算出:

最大延迟确认韶光是 200 ms (1000/5)最短延迟确认韶光是 40 ms (1000/25)

TCP 延迟确认可以在 Socket 设置 TCP_QUICKACK 选项来关闭这个算法。

延迟确认 和 Nagle 算法稠浊利用时,会产生新的问题

当 TCP 延迟确认 和 Nagle 算法稠浊利用时,会导致时耗增长,如下图:

发送方利用了 Nagle 算法,吸收方利用了 TCP 延迟确认会发生如下的过程:

发送方先发出一个小报文,吸收方收到后,由于延迟确认机制,自己又没有要发送的数据,只能干等着发送方的下一个报文到达;而发送方由于 Nagle 算法机制,在未收到第一个报文的确认前,是不会发送后续的数据;以是吸收方只能等待最大韶光 200 ms 后,才回 ACK 报文,发送方收到第一个报文的确认报文后,也才可以发送后续的数据。

很明显,这两个同时利用会造成额外的时延,这就会使得网络"很慢"的觉得。

要办理这个问题,只有两个办法:

要不发送方关闭 Nagle 算法要不吸收方关闭 TCP 延迟确认

参考资料:

[1] Wireshark网络剖析的艺术.林沛满.公民邮电出版社.

[2] Wireshark网络剖析就这么大略.林沛满.公民邮电出版社.

[3] Wireshark数据包剖析实战.Chris Sanders .公民邮电出版社.读者问答

标签:

相关文章

php为无色透明技巧_水货钻石其实也还行

从各种钻石中,可以看到大大小小的“包裹体” 图片来源:参考文献包裹体的种类多样。比钻石形成更早的包裹体,叫“原生包裹体”;与钻石同...

网站建设 2024-12-19 阅读0 评论0

phpstudy发送gbk技巧_php的文件上传

这里首先声明一下这一章的内容比较多,比较难,你要抱着和自己去世磕的态度。细微之处不放过,多敲多练是王道。 学习就像爬山,得一步一步...

网站建设 2024-12-19 阅读0 评论0