`
totoxian
  • 浏览: 1074671 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

linux关于tcp协议ack以及乱序报文暂存的实现--立即ack/延迟ack/捎带ack

 
阅读更多

tcp需要ack,可是为了效率,并不是每发送一个数据都要等待ack,而是尽可能利用窗口机制,积累发送ack的,当然在某些特殊情况下还是需要马上发送ack的,比如接收到乱序的数据,这种情况下,虽然接收端可以将乱序的数据包暂存,但是接收方必须发送一个ack号为按序的期望的序列号的ack给发送端,另外就是接收窗口需要调整,此时就要立刻发送ack,否则则可以延迟发送ack,看一下linux的这方面的代码:
static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible)
{
struct tcp_sock *tp = tcp_sk(sk);
//rcv_mss是估算的对端的mss,它对本端接收窗口的计算也有很大意义
if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss //如果接收到了大于一个的报文,那么就发送ack,一下子确认两个报文
&& __tcp_select_window(sk) >= tp->rcv_wnd) || //需要调整窗口,最大化吞吐量
tcp_in_quickack_mode(sk) ||
(ofo_possible && //收到乱序的包
skb_peek(&tp->out_of_order_queue))) {
tcp_send_ack(sk);
} else {
tcp_send_delayed_ack(sk);
}
}
大体上,上述的函数实现了RFC1122和RFC2581的关于ack的建议。
不是说ack可以在send数据的时候捎带发送吗?确实是这样,每当发送数据的时候,ack都会被发送,但是发送数据是应用层的事,如果应用层不发送呢?那岂不是永远都无法ack了吗?所以还必须有传输层本身的一套机制来支持ack的发送,捎带ack仅仅是一个补充,传输层的ack发送就是立即模式和延迟模式,正如上面的__tcp_ack_snd_check所展示的那样。
发送ack其实很简单,就是填写一个tcp数据,ack字段设置为接收窗口最左边的那个数据的序列号加1,延迟发送不怕和捎带发送重复,RFC2581规定每个到来的报文只能生成一个ack,除非需要发送端重传才会发送冗余ack,如果tcp进入了等待延迟发送ack的状态,当接收端有数据要发送的时候就会将ack捎带到发送端,同时清除延迟ack定时器的pendding,如此延迟ack定时器到期后就不会再发送ack了。
稳定的理想情况下,接收端的窗口也是稳定的,不需要调整的,如果接收端不发送数据只是接收数据,ack几乎全部以延迟的方式发送给发送端,如果接收端同时也发送数据,那么ack就会以捎带的方式发给发送端,立即ack只会在几种特殊的异常情况才发送。
一种是收到了一个以上的完整的tcp段,并且可能要放大窗口,为了使得吞吐量最大化,放大的窗口决不能浪费掉,于是需要立即发送ack给发送端,发送端接收到这个ack以后就会继续发送其发送窗口中后面的数据了。发送端的mss和接收端的窗口大小相关联,接收端的窗口设定为发送端mss的整数倍比较好,这样内存的利用率最高,确定好接收端可以承受的窗口大小之后,如果其比当前窗口大,那么立即发送ack使得发送端可以尽快发送数据。
另外一种是在所谓的quick模式,quick模式并不是经常的,只有在非交互的tcp连接才可能进入quick模式,因为交互的连接表明ack已经足够快了,没有必要立即发送ack了,一般都是捎带ack或者延迟发送ack的,那么如何判断是否是交互连接呢?内核中tcp_opt结构体中有一个ack子结构体,内部有一个quick和pingpong两个字段,其中pingpong就是判断交互连接的,内核会在很多地方进行抉择,根据很多参数,比如收发间隔或者用户配置等判断是否一个连接是交互的,如果不是交互的,那么就存在一系列问题:1.由于用户进程长期不取出收到的数据导致一系列的问题,于是需要协议栈瞬间回复ack,2.积压的ack没有回复,影响了发送端的发送速率。此时就会给quick赋予一定的数值,每发送一个ack就会消耗掉一些quick值,直到用尽了quick而进入延迟模式,quick的值和窗口相关,因为接收端最多只能确认接收窗口这么大的数据。
立即ack的最后一种可能就是收到乱序包,表明数据已经可能丢失了,那么应该尽快地进入补救阶段,就是说要尽快进入快速重传,此时ack也要立即发送(内核发现越界包[和乱序包有区别]后会调用tcp_send_dupack发送一个ack后丢次报文而返回),内核收到乱序报文后会在out_of_order_queue队列缓存该乱序报本,最后会调用tcp_ack_snd_check再次发送一个ack,这个ack确认的是按序报文的最后一个,以前应该发送过该ack,这样接收端收到乱序报文后就会发送一个冗余的ack,如果下次接收的数据仍然是乱序的,那么就再发送一个前两个相同的ack,这样发送端可能就会连续接收到三个一模一样的ack,在接收端,第三次接收到的仍然是乱序报文时,再次发送冗余ack,只有这第4个ack被发送端收到后才会进行快速重传。这里的一个细节就是发送端收到了4个相同的ack(3个冗余ack),从而作为进入快速重传的标志,linux是这么实现的,符合了rfc的建议,但是这种实现所依赖的是其背后的一个思想。
一个报文谈不上顺序,最少两个报文才有顺序的概念,正如字节序一样,utf8以一个字节为编码单位,因此就没有字节序的问题,同样的,仅仅来了一个报文也不能说它对于当前按序的报文来讲是乱序的,只有当第二个报文到来的时候,如果当前按序报文,第一个报文,第二个报文拼不成顺序才能说明后来的这两个报文是乱序的,当然这也是一种权衡的结果,正如三次握手为何是三次一样,即使接收端收到了第三个乱序报文,仍有可能被第四个填充后成为按序报文,没完没了等下去是不行的,必须在发送端接收到确定的,不是很大的数目冗余ack的时候进入快速重传,同时也不能频繁的快速重传,因此就选择了3个冗余ack,当然这个数字是可以配置的。
最后看一下乱序报文的重新调整。linux的协议栈实现中将乱序的报文按照序列号大小顺序插入到一个队列当中,此队列是基于连接的,如果该乱序队列有报文暂存的话,每接收到一个报文都会尝试调用tcp_ofo_queue函数,它的意义在于努力将乱序的报文顺序化,正如上述冗余ack相关的背后的思想,每个新的报文都有可能填补按序报文和乱序报文之间的缺口,换句话说,每一个新到的报文都可能直接拼接到按序报文队列最后一个的后面,同时也有可能完成这种拼接后,和后面的乱序队列的最前面一个或者几个或者全部的报文拼接,最终成为一系列按序的报文:
static void tcp_ofo_queue(struct sock *sk)
{
struct tcp_opt *tp = tcp_sk(sk);
__u32 dsack_high = tp->rcv_nxt;
struct sk_buff *skb;
while ((skb = skb_peek(&tp->out_of_order_queue)) != NULL) {
if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) //最前面的skb都拼不上
break;
...
if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
__skb_unlink(skb, skb->list); //曾经接收的报文段,继续
__kfree_skb(skb);
continue;
}
__skb_unlink(skb, skb->list); //可以拼接,更新tp的rcv_next字段
__skb_queue_tail(&sk->sk_receive_queue, skb);
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
...
}
}

分享到:
评论

相关推荐

    tcp_ack_check.rar_opnet tcp_tcp协议ack机制在opnet中实现

    - 对于`tcp_ack_check.cpp`文件,这可能是一个OPNET C++模块,实现了TCP协议的ACK处理函数。它会根据接收到的TCP段更新内部状态,并生成相应的ACK段。 - 在OPNET中,你需要定义数据包的生命周期,包括发送、接收、...

    linux-1.2.13 网络协议栈源码

    在Linux内核中,网络协议栈是负责处理网络数据传输的关键部分,它实现了TCP/IP协议族的各个层次,包括链路层、网络层、传输层以及应用层。 1. 链路层:在这个层次,主要涉及的是以太网协议,如Ethernet和ARP(地址...

    Linux下TCP/IP服务器实现源码解析(含源码)

    2. **TCP连接的建立与关闭**:TCP的三次握手和四次挥手过程是其核心特性,源码会解释这些流程在内核中的实现,包括SYN、SYN+ACK、ACK以及FIN和FIN+ACK等报文的交互。 3. **TCP状态机**:TCP连接有多种状态,如...

    TCP协议的模拟实现--源代码

    TCP(Transmission Control Protocol)协议是互联网上应用最广泛的一种网络协议,它为两台计算机之间的数据传输提供了可靠性和顺序保证。TCP协议通过一系列复杂的机制确保了数据的正确传输,包括三次握手建立连接、...

    Internet协议分析-TCP报文分析

    TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在TCP/IP网络通信中,TCP报文承载了数据传输的控制信息和数据内容,其在源与目标间传输前,需要通过三次握手建立连接,传输完毕后则通过...

    TCP 协议栈的防攻击方法

    《TCP协议栈的防攻击方法》 TCP协议是互联网中广泛使用的传输层协议,它确保了数据的可靠传输。然而,TCP协议的一些特性也可能被恶意利用,例如通过ACK(Acknowledgment,确认)攻击来篡改网络流量。ACK攻击主要是...

    ack-2.14-single-file

    在本文中,我们将深入探讨 `ack` 的核心功能、使用方法以及如何通过提供的单文件版本 `ack-2.14-single-file` 进行安装和操作。 1. **ack 的优势** - **源码优先**:`ack` 主要针对文本文件,特别是源代码文件,...

    TCP报文发送接收测试工具

    这款工具可以模拟客户端与服务器端的角色,实现双向通信,从而对TCP协议的各个方面进行深度测试。 在TCP通信中,数据被分割成多个报文段(Segments),每个报文段包含一个首部和数据部分。首部包含了诸如源端口号、...

    Linux内核TCP-IP协议栈分析.rar

    Linux内核中的TCP/IP协议栈是操作系统的心脏,负责处理所有网络通信。它是一套复杂的软件,用于实现互联网协议族,使得Linux系统能够与其他设备进行数据传输。在本资料"Linux内核TCP/IP协议栈分析"中,我们将深入...

    TCP协议分析网络实验报告

    ### TCP协议分析网络实验报告知识点总结 #### 一、实验背景及目的 本实验报告针对TCP协议进行深入分析,旨在帮助学生理解TCP协议的工作原理及其在网络通信中的作用。实验通过实际操作的方式,让学生掌握如何使用...

    用Java实现对IP/TCP协议数据包的拦截和分析

    在IT领域,网络通信是核心部分之一,而IP/TCP协议是互联网协议栈中的关键层次。本文将深入探讨如何利用Java编程语言实现对IP和TCP协议数据包的拦截与分析,以便获取IP地址的详细信息。 首先,我们需要理解IP...

    传输协议 TCP UDP ACK SEQ

    传输层协议TCP与UDP在计算机网络中扮演着至关重要的角色,它们为运行在不同主机上的应用程序进程提供逻辑通信。在这一领域,理解运输层服务的基本原理、多路复用与分用、无连接与面向连接的传输以及拥塞控制是至关...

    TCP协议特点和TCP报文段1

    TCP协议特点和TCP报文段解析 TCP(Transmission Control Protocol)是一种可靠的、面向连接的传输层协议,它是Internet协议族中最重要的协议之一。TCP协议的主要特点是: 1. 连接性:TCP是一个面向连接的协议,在...

    Linux内核 tcp ip协议栈源码分析

    Linux内核的TCP/IP协议栈还包括了多种优化措施,如快速重传、快速恢复、延迟确认等,以提高网络性能和响应速度。 通过阅读和分析Linux 2.6.18内核的TCP/IP协议栈源码,我们可以深入了解网络通信的底层原理,这对于...

    TCP-TIMEOUT.rar_ tcp timeo_CFG TCP/IP TIMEOUT_TCP 超时_超时三次

    在TCP/IP协议栈中,TCP(传输控制协议)是一种面向连接的、可靠的传输协议,它通过复杂的机制确保数据能够正确无误地传输。本篇主要围绕“TCP超时”这一主题进行深入探讨,重点关注TCP的三次握手过程以及TCP/IP超时...

    TCP协议及工作原理浅析

    ### TCP协议及工作原理浅析 #### 一、TCP/IP整体构架 TCP/IP协议作为互联网的核心协议之一,虽然没有完全遵循OSI的七层参考模型,但它自成一体的四层模型却成为了事实上的标准。为了更好地理解TCP/IP的工作方式,...

    TCP报文分析--三次握手 四次挥手

    TCP 报文分析是计算机网络中的重要内容, TCP(Transmission Control Protocol)是一种面向连接的传输控制协议,它提供了可靠的数据传输服务。在这个过程中,三次握手和四次挥手是 TCP 报文分析的核心内容。 面向...

    Ch5_TCP协议特点和TCP报文段1

    TCP(Transmission Control Protocol)传输控制协议是互联网协议栈中非常重要的一部分,主要负责在两台通信设备之间提供可靠的、面向连接的数据传输服务。TCP的特点和报文段结构是其核心概念,下面将详细展开讨论。 ...

    linux TCP/IP协议源码

    Linux TCP/IP协议源码是操作系统内核的一部分,用于实现网络通信的基本功能。它是一个复杂的、高度优化的软件组件,负责在网络层(IP)和传输层(TCP)处理数据的发送和接收。本主题将深入探讨Linux TCP/IP协议栈的...

Global site tag (gtag.js) - Google Analytics