tcp的发送端一个小包就能打破对端的delay_ack么?

3.10内核,反向合入4.9的bbr。

最近分析bbr的时候,收集了线上的一些报文,其中有一个疑问一直在我脑海里面,如下:

本身处于delay_ack状态的客户端,大概40ms回复一个delay_ack,当收到一个490字节的小包之后,立刻回复了ack。且不止出现,是有规律的出现:

我是如何确定这个ack一定是打破了delay_ack的呢,除了在时间上和发包的时间相隔很短,我还特意确认了一下,之后报文的ack是否立刻回复的,结果确定

都是立刻回复的,也就是进入了quick_ack的模式,回复快速ack的数量也刚好是16,因为 tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK);

中,对shinfo->gso_segs = 1;这样在减少quick阈值的时候,每次 tcp_event_ack_sent 只是将quick减去1,这样就是说,一旦打破delay_ack,那么至少两个,

至多16个quick ack,也就是符合代码:

icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS);

根据接收窗口和mss,以及

/* Maximal number of ACKs sent quickly to accelerate slow-start. */
#define TCP_MAX_QUICKACKS   16U
我铁定确定了这个是打破了原本的delay_ack.它既不属于乱序报文,又没有out of window,且收包窗口也没有变化,也不是收到一个已经被ack过的报文,
且乱序队列中并没有数据,为啥它就能打破delay_ack呢?你说它到底满足哪一条呢?
/** Check if sending an ack is needed.*/
static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
{struct tcp_sock *tp = tcp_sk(sk);/* More than one full frame received... */if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss &&/* ... and right edge of window advances far enough.* (tcp_recvmsg() will send ACK otherwise). Or...*/__tcp_select_window(sk) >= tp->rcv_wnd) ||/* We ACK each frame or... */tcp_in_quickack_mode(sk) ||/* We have out of order data. */(ofo_possible && !RB_EMPTY_ROOT(&tp->out_of_order_queue))) {/* Then ack it now */tcp_send_ack(sk);} else {/* Else, send delayed ack. */tcp_send_delayed_ack(sk);}
}

 然后我搜索代码,看什么时候调用 tcp_enter_quickack_mode,发现没有收获,这个包不满足条件。

这个包的神奇之处在哪?走查了delay_ack打破的条件,没法理解这个代码逻辑,关于delay_ack的出现场景,在另一篇博客中有描述《https://www.cnblogs.com/10087622blog/p/10315410.html》

我点击这个报文详细分析:

发现它和其他报文的区别是,它带了push标志,带了走查了代码,也没看出来,为啥push标志的报文会在delay_ack的情况下,能立刻发送ack。

最后,再回到报文,看到一点, 那就是这个小包与上一个ack之间的间隔为230ms左右,直觉感觉这个时间偏大,然后走查收包的代码:

/* There is something which you must keep in mind when you analyze the* behavior of the tp->ato delayed ack timeout interval.  When a* connection starts up, we want to ack as quickly as possible.  The* problem is that "good" TCP's do slow start at the beginning of data* transmission.  The means that until we send the first few ACK's the* sender will sit on his end and only queue most of his data, because* he can only send snd_cwnd unacked packets at any given time.  For* each ACK we send, he increments snd_cwnd and transmits more of his* queue.  -DaveM*/
static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
{struct tcp_sock *tp = tcp_sk(sk);struct inet_connection_sock *icsk = inet_csk(sk);u32 now;inet_csk_schedule_ack(sk);tcp_measure_rcv_mss(sk, skb);tcp_rcv_rtt_measure(tp);now = tcp_time_stamp;if (!icsk->icsk_ack.ato) {/* The _first_ data packet received, initialize* delayed ACK engine.*/tcp_incr_quickack(sk);icsk->icsk_ack.ato = TCP_ATO_MIN;} else {int m = now - icsk->icsk_ack.lrcvtime;if (m <= TCP_ATO_MIN / 2) {/* The fastest case is the first. */icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + TCP_ATO_MIN / 2;} else if (m < icsk->icsk_ack.ato) {icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + m;if (icsk->icsk_ack.ato > icsk->icsk_rto)icsk->icsk_ack.ato = icsk->icsk_rto;} else if (m > icsk->icsk_rto) {---------------------------进入这个流程/* Too long gap. Apparently sender failed to* restart window, so that we send ACKs quickly.*/tcp_incr_quickack(sk);----------------------------------这个修改了quickack的发包数量sk_mem_reclaim(sk);}}icsk->icsk_ack.lrcvtime = now;tcp_ecn_check_ce(tp, skb);if (skb->len >= 128)tcp_grow_window(sk, skb);
}

正是因为发包的间隔大于了 icsk->icsk_rto,所以接收端觉得很长时间没有收到包了,那么尽快给对方回复ack。icsk->icsk_ack.quick 已经大于0了。

static bool tcp_in_quickack_mode(struct sock *sk)
{const struct inet_connection_sock *icsk = inet_csk(sk);const struct dst_entry *dst = __sk_dst_get(sk);return (dst && dst_metric(dst, RTAX_QUICKACK)) ||(icsk->icsk_ack.quick && !icsk->icsk_ack.pingpong);
}

那么还需要一个条件就是,icsk->icsk_ack.pingpong 要为0,才行,否则单独增加 icsk->icsk_ack.quick 的值并不能保证立刻回复ack。

而我们目前这个流,明显是一个单向的发包流,并不是pingpong模式,所以这个值肯定为0,那么我们就满足了 tcp_in_quickack_mode 的条件,

打破了本端的delay_ack模式。

 

总结:

我只是搜索了tcp_enter_quickack_mode 的代码流程,没有注意到 tcp_incr_quickack 的调用,导致这个问题查了小半天。业务不精。

如果连续两个小包,加起来超过mss了,则可能会触发对端在delay_ack模式下立即回复ack,但是如果一个小包就打破了对端的delay_ack,则需要关注这个

小包的发包间隔了。

那么问题来了,为什么会相隔这么长时间发送小包?后面会继续探讨。

 

转载于:https://www.cnblogs.com/10087622blog/p/10423118.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/449363.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

设置 git pull 无需输入账号和密码

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 如果你用git从远程pull拉取代码&#xff0c;每次都要输入密码&#xff0c;那么执行下面命令即可 git config --global credential.help…

Git 诞生记

你可能有过这样的经历&#xff1a;在 debug 的时候这里加一句&#xff0c;那里减一句&#xff0c;顺便改改参数&#xff0c;不一会你的程序就从一个 bug 增加到了无数个 bug 。最重要的是&#xff0c;你完全想不起来自己到底改了几个地方&#xff0c;原来的程序到底长什么样子了…

使用pandas进行量化回测(akshare)

本人看法&#xff0c;也就比excel高级一点&#xff0c;距离backtrader这些框架又差一点。做最基础的测试可以&#xff0c;如果后期加入加仓功能&#xff0c;或者是止盈止损等功能&#xff0c;很不合适。只能做最简单的技术指标测试。所以别太当回事。 导包&#xff0c;常用包导…

【BZOJ4543】【POI2014】Hotel加强版(长链剖分)

传送门 题意&#xff1a;求树上满足三点之间距离两两相等的三元组个数 n≤1e5n\le 1e5n≤1e5 原题数据是n≤5000n\le5000n≤5000 考虑怎么做f[u][i]f[u][i]f[u][i]表示uuu为根&#xff0c;深度为iii的点的个数g[u][i]g[u][i]g[u][i]表示uuu为根&#xff0c;满足2点到lcalcalca的…

使用vue+webpack从零搭建项目

vue到现在已经成为一个热门的框架&#xff0c;在项目实践当中&#xff0c;如果想要创建一个新项目&#xff0c;通常都会使用vue-cli的脚手架工具&#xff0c;毋容置疑能够方便很多&#xff0c;很多东西也不需要自己亲自去配置。都知道&#xff0c;脚手架其实是vue结合webpack去…

CentOS 6 和 CentOS 7 防火墙的关闭

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。CentOS6.5查看防火墙的状态&#xff1a; 1[linuxidclocalhost ~]$service iptable status显示结果&#xff1a; 12345[linuxidclocalhost …

怎样从Linux终端管理进程:10个你必须知道的命令

本文由 极客范 - Ben Zhang 翻译自 Chris Hoffman。欢迎加入极客翻译小组&#xff0c;同我们一道翻译与分享。转载请参见文章末尾处的要求。Linux终端有一系列有用的命令。它们可以显示正在运行的进程、杀死进程和改变进程的优先级。本文列举了一些经典传统的命令和一些有用新…

易盛极星多合约回测(问题很多)

注意&#xff0c;使用此函数&#xff0c;在考虑手续费时&#xff0c;无法做到统一。 import talib import numpy as np import EsTalib from EsSeries import NumericSeries# 策略参数字典 g_params[p1] 5 g_params[p2] 10 g_params[p3] 120 g_params[ZQ] 5 #交易周期…

Qt 程序获取程序所在路径、用户目录路径、临时文件夹等特殊路径的方法

Qt 程序获取程序所在路径、用户目录路径、临时文件夹等特殊路径的方法 经常我们的程序中需要访问一些特殊的路径&#xff0c;比如程序所在的路径、用户目录路径、临时文件夹等。在 Qt 中实现这几个功能所用的方法虽然都不难&#xff0c;但是各不相同&#xff0c;每次用到时还要…

搞了个30天学习量化的数据资料,可以bt做全球。数据链接白送

待会上传代码,资料,打包好了,拿来就能用。累死我了,搞了两天,必须收费,绝不允许白嫖。不然对不起我熬夜,那么辛苦。 确定后,扫描百度网盘 链接:https://pan.baidu.com/s/1C0k6zkjHchFVQaHe4nRMsg?pwd=kkgb 提取码:kkgb 如何回测k线图 如何根据形态选股

解决 springboot + JPA + MySQL 表名全大写 出现 “表不存在” 问题(Table ‘XXX.xxx‘ doesn‘t exist)

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 项目中使用 JPA 和 mysql 。表名是全大写的。 出现 如下报错&#xff1a; java.sql.SQLSyntaxErrorException: Table XXX_ms.work_tas…

自学Linux命令的四种方法

本文由 极客范 - 小道空空 翻译自 Danny Stieben。欢迎加入极客翻译小组&#xff0c;同我们一道翻译与分享。转载请参见文章末尾处的要求。如果你想成为Linux高手&#xff0c;那么掌握一些Linux命令是必不可少的。下面是自学Linux命令的四种方法。 每日提示 学习Linux命令的…

第五周学习总结

第六章&#xff1a; 主要内容: 1.接口 2.实现接口 3.理解接口 4.接口回调 5.接口与多态 6.接口变量做参数 7.面向接口编程 Example6_1: Example6_2: Example6_3: Example6_4: Example6_5: Example6_6: 总结&#xff1a;这章节没有较大问题&#xff0c;例题也都做了一遍。蛮顺利…

Android 设备的CPU类型(通常称为”ABIs”)

armeabiv-v7a: 第7代及以上的 ARM 处理器。2011年15月以后的生产的大部分Android设备都使用它.arm64-v8a: 第8代、64位ARM处理器&#xff0c;很少设备&#xff0c;三星 Galaxy S6是其中之一。armeabi: 第5代、第6代的ARM处理器&#xff0c;早期的手机用的比较多。x86: 平板、模…

国信证券学习系列(1)

软件不错&#xff0c;满足了我对股票&#xff0c;期货&#xff0c;期权的全部要求。而且数据可以提供下载&#xff0c;简直没话说了。 数据清洗问题&#xff0c;我其实很早以前就在思考这个问题&#xff0c;回测&#xff0c;到底在测什么&#xff1f;什么样的数据可以用来回测&…

JNA—JNI终结者

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.介绍 给大家介绍一个最新的访问本机代码的Java框架—JNA。 JNA(Java Native Access)框架是一个开源的Java框架&#xff0c;是SUN公司…

FIFO存储器

FIFO( First Input First Output)简单说就是指先进先出。由于微电子技术的飞速发展&#xff0c;新一代FIFO芯片容量越来越大&#xff0c;体积越来越小&#xff0c;价格越来越便宜。作为一种新型大规模集成电路&#xff0c;FIFO芯片以其灵活、方便、高效的特性&#xff0c;逐渐在…

通过8个技巧让你成为一个超强的Linux终端用户

本文由 极客范 - minejo 翻译自 Chris Hoffman。欢迎加入极客翻译小组&#xff0c;同我们一道翻译与分享。转载请参见文章末尾处的要求。使用Linux终端不仅仅是只输入命令。学习这些基本的技巧&#xff0c;你就会逐渐掌握Bash shell&#xff0c;这个在大多数Linux发行版上默认…

国信证券学习系列(2)

获取指数池&#xff1a; def init(ContextInfo):#设置股票池stock300 ContextInfo.get_stock_list_in_sector(沪深300)ContextInfo.stock300_weight {}stock300_symbol []stock300_weightlist [] ContextInfo.index_code ContextInfo.stockcode"."ContextInfo.m…

旅游服务商Bikego完成A轮融资,共建创投、马蜂窝投资

2月26日消息&#xff0c;近日Bikego宣布完成A轮融资&#xff0c;共建创投、北京马蜂窝之旅国际旅行社投资。目前金额尚未公开。 bikego领趣旅行成立于2016年&#xff0c;是一家目的地日游服务运营商。从内容切入&#xff0c;提供国内自由行客户的白天玩法解决方案&#xff0c;…