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

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
Linux 网络安全 iOS开发
SecureCRT & SecureFX 9.6.3 for macOS, Linux, Windows - 跨平台的多协议终端仿真和文件传输
SecureCRT & SecureFX 9.6.3 for macOS, Linux, Windows - 跨平台的多协议终端仿真和文件传输
2490 4
SecureCRT & SecureFX 9.6.3 for macOS, Linux, Windows - 跨平台的多协议终端仿真和文件传输
|
12月前
|
安全 网络协议 Linux
Linux网络应用层协议展示:HTTP与HTTPS
此外,必须注意,从HTTP迁移到HTTPS是一项重要且必要的任务,因为这不仅关乎用户信息的安全,也有利于你的网站评级和粉丝的信心。在网络世界中,信息的安全就是一切,选择HTTPS,让您的网站更加安全,使您的用户满意,也使您感到满意。
366 18
|
存储 网络协议 Ubuntu
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
720 2
|
负载均衡 网络协议 Linux
在Linux中,如何理解VRRP协议?
在Linux中,如何理解VRRP协议?
|
安全 算法 网络协议
【在Linux世界中追寻伟大的One Piece】HTTPS协议原理
【在Linux世界中追寻伟大的One Piece】HTTPS协议原理
221 2
|
监控 网络协议 安全
使用 Scapy 库编写 TCP ACK 洪水脚本
使用 Scapy 库编写 TCP ACK 洪水脚本
|
监控 网络协议 网络安全
使用 Scapy 库编写 TCP SYN-ACK 反射脚本
使用 Scapy 库编写 TCP SYN-ACK 反射脚本
|
存储 Linux 网络安全
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
【Azure 存储服务】如何把开启NFS 3.0协议的Azure Blob挂载在Linux VM中呢?(NFS: Network File System 网络文件系统)
256 0
|
网络协议 Linux 网络安全
在Linux中,我们都知道FTP协议有两种工作模式,它们的大概的⼀个工作流程是怎样的?
在Linux中,我们都知道FTP协议有两种工作模式,它们的大概的⼀个工作流程是怎样的?