前面的文章分析了接收端如何发送ack给发送端,总结一下就是立即ack,捎带ack和延迟ack,现在看一下tcp的发送端是如何处理ack的,本质上tcp所谓的有连接就是双方对于seq和ack的处理,对于seq,发送方是主动的,而接收端是被动的,但是对于ack则相反,因此参照tcp的流控以及拥塞控制加之性能因素的需要,首先要设计接收端如何发送ack,其次再来设计发送端如何处理,linux采纳了rfc的建议(好像没有不采纳的OS,除非它猛到自己定义标准)。对于发送ack,前面已经说过了,对于如何处理ack,完全就是应付一下,要简单的多,简单的说,接收端只会发送按序报文的最后一个未被确认的报文的seq作为其ack,但是对于发送端收到这个ack后如何处理,虽然比发送ack的逻辑和策略要简单,但是也要彻底理解协议才能看懂代码:
static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
{
...
if (after(ack, tp->snd_nxt))
goto uninteresting_ack;
if (before(ack, prior_snd_una))
goto old_ack;
if (!(flag&FLAG_SLOWPATH) && after(ack, prior_snd_una)) { //非冗余的ack,正常,不进入快速重传
tcp_update_wl(tp, ack, ack_seq);
tp->snd_una = ack;
tcp_westwood_fast_bw(sk, skb);
flag |= FLAG_WIN_UPDATE;
} else {
if (ack_seq != TCP_SKB_CB(skb)->end_seq) //说明是捎带ack
flag |= FLAG_DATA;
flag |= tcp_ack_update_window(sk, tp, skb, ack, ack_seq); //flag可能置update位
if (TCP_SKB_CB(skb)->sacked) //如果是sack,则说明可能丢包了,有可能置上sack位,选择确认接收端已经收到的报文,sack完全是为了提高性能的,实际上在分析代码的时候可以忽略这种情况,只有确认丢失报文的时候才会选择确认(sack)
flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th)) //路由器通知丢包,置上ece位
flag |= FLAG_ECE;
...
}
...
flag |= tcp_clean_rtx_queue(sk, &seq_rtt); //尽量清除所有已经被确认的报文,如果有被确认的报文,则置上acked位
...
if (tcp_ack_is_dubious(tp, flag)) { //如果没有设置acked位,也没有设置data位也没有设置update位,或者存在sack或者ece位,则说明可能已经丢失报文,这里判断比较复杂,注意||运算符,只要第一个比较对象返回真就返回,依次类推,flag如果有data位或者acked位,我们也不能确定就一定没有丢失报文,因为ack由对端发送,可能的方式有好几种,不仅仅是裸ack,还可能是捎带ack,对于设置了acked位的flag也不能说就一定没有丢失报文,因为虽然该ack确认一部分报文,但是后面的报文可能丢失,复杂的情况下还可能出现选择确认-sack,因此还需要进一步判断ece和sack标志,但是反过来可以说的是,如果既没有data位,也没有acked位,也没有update位,则一定要进入重传。
...//进入拥塞控制,快速重传
tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
}
...//否则正常返回
return 1;
...
}
其中最麻烦的就是sack的相关逻辑了,前面说了,sack完全是为性能考虑的一个可选的机制,它可以使得发送端只重传丢失的报文,而不必重传已经发来的有选择的乱序的确认报文,这是通过tcp头的选项进行配置的。使用sack机制前要允许sack选项,在冗余ack发来的时候,它携带一些信息,这些信息包含哪些乱序的报文已经安全正确接收且被暂存在接收端了,如此一来发送端重传报文的时候就不必再传输这些已经确认的乱序报文了,具体可以看一下tcp_sacktag_write_queue的代码。
linux关于tcp协议ack的实现--发送端对ack的处理
原创
©著作权归作者所有:来自51CTO博客作者dog250的原创作品,请联系作者获取转载授权,否则将追究法律责任
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
linux之TCP协议
linux下TCP协议的认识,包括确认应答,超时重传,流量控制,滑动窗口,拥塞控制,三次握手四次挥手等。
TCP 面向字节流 可靠性 有连接 滑动窗口 -
解析TCP /UDP协议的 socket 调用的过程TCP 服务端 UDP
-
18-TCP 协议(迟到的 ACK—— Linux)
在上一篇文章中已经分析了 windows 在回复确认时的情况,在接收到 TCP 段的情况下,等待 200ms 再回复 ack,除非
linux delayedack tcp 数据 服务器 -
17-TCP 协议(迟到的 ACK —— Windows )
1. 引言我们知道,TCP 协议中,需要对接收到 TCP 段进行确认。有两种方式可以减少 TCP 报文段. 一种是累积确认,另一种是捎带确同数
tcp unp DelayedACK 延时的ack 数据 -
TCP的核心系列 — ACK的处理(一)#define 重传 数据 数据段 sed