设为首页 加入收藏

TOP

探讨Linux kernel中对序列号超前的ACK包的处理
2014-11-24 07:40:26 】 浏览:7295
Tags:探讨 Linux kernel 序列号 超前 ACK 包的 处理

在开发的内核模块中遇到这样一个问题:一个数据包有多个请求,每次只让服务器处理一个请求,所以在将请求交到上层的时候需要拆包,只将部分数据交到上层。为了防止客户端重传数据包,要预先给客户端发送一个对完整数据包的确认。这样就会造成一个问题,客户端发送的ACK包的序列号,会比协议栈中期望的序列号大。


假设完整数据包的起始序列号分别为1883458390、1883458821,上层协议栈拿到的数据包的起始序列号为1883458390、1883458476,这时服务器端sock结构的rcv_nxt应该为1883458476,但是由于我们事先多发送了一个ACK,所以这时客户端的ACK包的序列号为1883458821,而不是1883458476。下面是抓包的部分截图,根据抓包情况来看,这样的ACK包,内核接受了这样的确认包,如图所示(客户端:192.168.9.188;服务器端:192.168.9.191):



OK,现在我们开始来看看内核中是如何处理这样的数据包,为什么会接受这样的ACK包。


TCP协议的接收函数为tcp_v4_rcv(),该函数SKB进行必要的检查,如数据的长度、校验和初始化等,初始化TCP控制块中的值;接着会调用__inet_lookup_skb()函数在tcp_hashinfo散列表中来查找是否存在对应的传输控制块。如果找到,则调用tcp_v4_do_rcv()来处理(这里我们忽略了Netfilter、IPSec、DMA等细节,这些跟我们探讨的内容无关),基本的代码流程如下图所示:



我们的ACK包的校验和、首部长度是没有问题,所以它可以轻松的通过tcp_v4_rcv()的检查,接下来看tcp_v4_do_rcv()中处理。tcp_v4_do_rcv()中会首先检查SKB包对应的sock结构的状态,如果是ESTABLISHED状态,则会调用tcp_rcv_established()来处理,代码片段如下:


int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
{
......


if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
TCP_CHECK_TIMER(sk);
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
rsk = sk;
goto reset;
}
TCP_CHECK_TIMER(sk);
return 0;
}

......
}


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇TIME_WAIT状态下对接收到的数据包.. 下一篇Java 获取可用 UDP 端口号的方法

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目