linux关于tcp协议ack的实现--发送端对ack的处理

简介:
前面的文章分析了接收端如何发送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的代码。


 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1271788

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
27天前
|
JSON Kubernetes Linux
Linux环境签发CA证书和K8s需要的证书
Linux环境签发CA证书和K8s需要的证书
29 0
|
3月前
|
网络协议 Linux
拿来即用的Linux上TCP服务端程序
拿来即用的Linux上TCP服务端程序
|
3月前
|
网络协议 Linux C++
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
57 0
|
2月前
|
传感器 网络协议 物联网
在Linux中搭建Mosquitto MQTT协议消息服务端并结合内网穿透工具实现公网访问
Mosquitto是一个开源的消息代理,它实现了MQTT协议版本3.1和3.1.1。它可以在不同的平台上运行,包括Windows、Linux、macOS等。mosquitto可以用于物联网、传感器、移动应用程序等场景,提供了一种轻量级的、可靠的、基于发布/订阅模式的消息传递机制。
|
4月前
|
Kubernetes Shell Linux
linux|shell脚本|有趣的知识---格式化输出日志和脚本调试方法以及kubernetes集群核心服务重启和集群证书备份脚本
linux|shell脚本|有趣的知识---格式化输出日志和脚本调试方法以及kubernetes集群核心服务重启和集群证书备份脚本
62 0
|
3月前
|
网络协议 Linux C++
Linux C/C++ 开发(学习笔记十一 ):TCP服务器(并发网络网络编程 一请求一线程)
Linux C/C++ 开发(学习笔记十一 ):TCP服务器(并发网络网络编程 一请求一线程)
39 0
|
9天前
|
网络协议 Java API
深度剖析:Java网络编程中的TCP/IP与HTTP协议实践
【4月更文挑战第17天】Java网络编程重在TCP/IP和HTTP协议的应用。TCP提供可靠数据传输,通过Socket和ServerSocket实现;HTTP用于Web服务,常借助HttpURLConnection或Apache HttpClient。两者结合,构成网络服务基础。Java有多种高级API和框架(如Netty、Spring Boot)简化开发,助力高效、高并发的网络通信。
|
11天前
|
网络协议 Ubuntu Unix
Linux 下使用 socket 实现 TCP 客户端
Linux 下使用 socket 实现 TCP 客户端
|
1月前
|
Linux 网络安全
Linux NFS协议详解
Linux NFS协议详解
33 5
|
2月前
|
网络协议 关系型数据库 MySQL
Linux下的网络编程——C/S模型TCP(二)
Linux下的网络编程——C/S模型TCP(二)
33 0
Linux下的网络编程——C/S模型TCP(二)