前面的文章分析了接收端如何发送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/IP协议族的各个层次,包括链路层、网络层、传输层以及应用层。 1. 链路层:在这个层次,主要涉及的是以太网协议,如Ethernet和ARP(地址...
关于TCP的输出处理,Linux内核提供了数据发送接口如tcp_sendmsg和tcp_sendmsg_fastopen。这些接口在发送数据时会经过一系列复杂的处理流程,以保证数据能准确可靠地传送到接收端。TCP层的输出处理还包括如何将数据...
Linux内核中的TCP/IP协议栈是操作系统的心脏,负责处理所有网络通信。它是一套复杂的软件,用于实现互联网协议族,使得Linux系统能够与其他设备进行数据传输。在本资料"Linux内核TCP/IP协议栈分析"中,我们将深入...
《Linux内核TCP/IP协议栈源码分析》 在深入探讨Linux内核的TCP/IP协议栈之前,我们先理解一下TCP/IP协议栈的基本结构。TCP/IP协议栈是互联网通信的核心,它将网络通信分为四层:应用层、传输层、网络层和数据链路层...
《Linux内核TCP协议栈部分,下册》深入解析了Linux操作系统中TCP协议栈的实现细节,涵盖了TCP协议从启动到控制发送的全过程,以及不启用DSACK(duplicate SACK,重复确认选择)等相关主题。这本书是理解网络通信底层...
对于Linux系统而言,其内核中的TCP/IP协议栈是实现网络通信的基础,它负责解析、处理并转发网络数据。本文将深入探讨Linux协议栈实现的细节,特别是与TCP/IP协议流程相关的部分。 首先,TCP/IP协议栈可以分为四层,...
在Linux系统中,这些层次由不同的模块实现,如socket接口对应应用层,TCP和UDP协议处理传输层,IP协议处理网络层,而ARP和以太网驱动则属于数据链路层。 2. **TCP(传输控制协议)** TCP是面向连接的、可靠的传输...
《Linux内核源码剖析 TCP/IP实现》是樊东东和莫澜合著的一本深入解析Linux内核网络协议栈的书籍,主要关注TCP/IP协议的实现细节。这本书上册的内容,将引领读者深入理解Linux操作系统如何处理网络通信,特别是TCP/IP...
可用于传输文件和网络编程的学习”,意味着提供的代码示例可以直接在Linux环境中编译和执行,并且这些示例不仅展示了TCP通信的基础,还可能涉及到了文件的发送与接收,这对于学习网络编程和理解TCP协议的工作原理...
在Linux操作系统中,尤其是在2.6版本的内核中,TCP的实现涉及多个层次的函数调用与处理过程,本文将重点分析从用户空间到内核空间的TCP包发送流程。 ### 插口层系统调用 在Linux中,网络通信的API主要通过socket...
在Linux操作系统中,TCP/IP协议栈是网络通信的核心部分,对于任何系统级别的开发者或网络工程师而言,理解其工作原理和实现细节至关重要。本资源提供的"Linux下TCP/IP服务器实现源码解析(含源码)"正是这样一个面向...
与三次握手类似,TCP关闭连接采用四次挥手(FIN-ACK-FIN-ACK)的机制。这个过程涉及到TCP套接字状态的多次变迁,例如从FIN_WAIT1到TIME_WAIT,再到CLOSED。 五、安全性与优化 在实际应用中,TCP连接可能会受到各种...
通过对Linux TCP服务器在连接时发不出数据的问题进行详细分析,我们发现主要问题在于服务器端的线程同步机制不完善以及TCP/IP协议栈的配置不当。通过加强线程间的同步控制、优化TCP/IP协议栈配置以及改进数据包的...
在Linux系统中,TCP/IP协议的实现是操作系统的一部分,负责处理网络连接、数据传输和网络接口交互等任务。本篇将深入探讨TCP/IP协议的基本原理,特别是传输控制协议TCP在Linux环境下的应用。 首先,我们了解OSI参考...
Linux轻量协议栈是针对嵌入式设备设计的一套精简版TCP/IP协议实现,它在保持核心功能的同时,降低了资源占用,适用于内存有限、计算能力较弱的系统。源代码分析有助于深入理解TCP/IP协议的工作原理,对于嵌入式开发...
在Linux环境下,TCP(Transmission Control Protocol)是一种广泛用于网络通信的传输层协议,它提供了面向连接、可靠的数据传输服务。TCP程序设计是网络编程的重要组成部分,涵盖了连接建立、数据传输和连接关闭等...
在这个"TCP实现的文件发送与接收"的项目中,我们将探讨如何利用TCP协议来构建文件的发送与接收程序。 首先,TCP建立连接的过程称为三次握手。当客户端想要向服务器发送文件时,它会发送一个SYN(同步)包到服务器,...
标题"linux tcp_tcp"可能是指在Linux环境下对TCP协议的深入理解和应用。以下将详细阐述Linux中的TCP相关知识点: 1. **TCP连接建立**:TCP连接是通过三次握手(Three-Way Handshake)来建立的。客户端发送一个SYN...