趣谈 Linux 操作系统
刘超
前网易杭州研究院云计算技术部首席架构师
85459 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 72 讲
趣谈 Linux 操作系统
15
15
1.0x
00:00/00:00
登录|注册

48 | 接收网络包(下):如何搞明白合作伙伴让我们做什么?

数据包处理
状态处理
队列处理
TCP层
Sock层
Socket层
VFS层
TCP层处理
IP层处理
四次挥手
滑动窗口
拥塞控制
发送和接收的连接维护
三次握手
TCP协议
用户态读取网络包的过程
网络协议栈处理
软中断处理
网卡驱动程序
中断处理
硬件网卡接收
课堂练习
接收网络包的过程

该思维导图由 AI 生成,仅供参考

上一节,我们解析了网络包接收的上半部分,从硬件网卡到 IP 层。这一节,我们接着来解析 TCP 层和 Socket 层都做了哪些事情。

网络协议栈的 TCP 层

从 tcp_v4_rcv 函数开始,我们的处理逻辑就从 IP 层到了 TCP 层。
int tcp_v4_rcv(struct sk_buff *skb)
{
struct net *net = dev_net(skb->dev);
const struct iphdr *iph;
const struct tcphdr *th;
bool refcounted;
struct sock *sk;
int ret;
......
th = (const struct tcphdr *)skb->data;
iph = ip_hdr(skb);
......
TCP_SKB_CB(skb)->seq = ntohl(th->seq);
TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + skb->len - th->doff * 4);
TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
TCP_SKB_CB(skb)->tcp_tw_isn = 0;
TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph);
TCP_SKB_CB(skb)->sacked = 0;
lookup:
sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source, th->dest, &refcounted);
process:
if (sk->sk_state == TCP_TIME_WAIT)
goto do_time_wait;
if (sk->sk_state == TCP_NEW_SYN_RECV) {
......
}
......
th = (const struct tcphdr *)skb->data;
iph = ip_hdr(skb);
skb->dev = NULL;
if (sk->sk_state == TCP_LISTEN) {
ret = tcp_v4_do_rcv(sk, skb);
goto put_and_return;
}
......
if (!sock_owned_by_user(sk)) {
if (!tcp_prequeue(sk, skb))
ret = tcp_v4_do_rcv(sk, skb);
} else if (tcp_add_backlog(sk, skb)) {
goto discard_and_relse;
}
......
}
在 tcp_v4_rcv 中,得到 TCP 的头之后,我们可以开始处理 TCP 层的事情。因为 TCP 层是分状态的,状态被维护在数据结构 struct sock 里面,因而我们要根据 IP 地址以及 TCP 头里面的内容,在 tcp_hashinfo 中找到这个包对应的 struct sock,从而得到这个包对应的连接的状态。
接下来,我们就根据不同的状态做不同的处理,例如,上面代码中的 TCP_LISTEN、TCP_NEW_SYN_RECV 状态属于连接建立过程中。这个我们在讲三次握手的时候讲过了。再如,TCP_TIME_WAIT 状态是连接结束的时候的状态,这个我们暂时可以不用看。
接下来,我们来分析最主流的网络包的接收过程,这里面涉及三个队列:
backlog 队列
prequeue 队列
sk_receive_queue 队列
为什么接收网络包的过程,需要在这三个队列里面倒腾过来、倒腾过去呢?这是因为,同样一个网络包要在三个主体之间交接。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了网络包接收的过程,重点分析了TCP层和Socket层的工作。在TCP层,详细介绍了TCP协议的功能和作用,以及在接收网络包过程中的具体操作。同时,对Socket层的工作也进行了深入剖析,包括Socket的创建、绑定和监听等步骤。文章还介绍了网络包在三个队列中的倒腾过程,解释了为什么需要在这三个队列中进行处理。此外,还详细分析了网络包在不同状态下的处理方式,以及乱序包的处理过程。 在接收网络包的过程中,从硬件网卡接收到网络包到内核接收网络包的过程,经历了多个层次的处理。从硬件网卡接收到网络包后,通过DMA技术放入Ring Buffer,然后通过中断通知CPU新的网络包的到来,接着由网卡驱动程序注册中断处理函数,再通过软中断触发接下来的处理过程,最终进入内核网络协议栈,经过多层处理后,进入用户态读取网络包的过程。 此外,文章还提到了对TCP协议、三次握手、发送和接收的连接维护、拥塞控制、滑动窗口等内容进行了解析,唯独四次挥手没有解析,鼓励读者自行尝试解析四次挥手的过程。 通过本文的阅读,读者可以全面了解网络包接收的全过程,深入理解各个层级的工作原理和功能,为进一步深入网络编程和网络技术打下坚实基础。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《趣谈 Linux 操作系统》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(21)

  • 最新
  • 精选
  • 免费的人
    从kernel doc里发现这个说明: tcp_low_latency - BOOLEAN This is a legacy option, it has no effect anymore. 这个选项没用了?

    作者回复: 4.13里面是tcp_low_latency - BOOLEAN If set, the TCP stack makes decisions that prefer lower latency as opposed to higher throughput. By default, this option is not set meaning that higher throughput is preferred. An example of an application where this default should be changed would be a Beowulf compute cluster. Default: 0 5.0里面就是 cp_low_latency - BOOLEAN This is a legacy option, it has no effect anymore.

    2019-07-17
    6
  • 免费的人
    老师有计划讲epoll的实现吗?

    作者回复: 讲不了了,要不这个专栏就太长了。在网络协议里面大致讲了一下epoll的内核实现,但是分析的不细

    2019-07-17
    5
  • D
    这个 out_of_order_queue 是怎么实现的, 假如5,6已结到了,下个期待7,8,但是从队头拿出的是9,10,怎么办,重新入队吗,这样效率有点低吧,老师能讲讲吗

    作者回复: 红黑树,可以先判断一把再拿

    2019-07-17
    4
  • 取名字好麻烦
    大概也就看了五六七八遍

    作者回复: 赞,加油

    2019-08-16
    2
  • wjh_all_in
    老师,prequeue 队列和 backlog 队列需要做乱序的保证吗?如果没有,怎么保证可靠性?

    作者回复: 要的,如果判断接不上,就回退到默认流程

    2019-08-30
    3
    1
  • 没心没肺
    终于快结束了🙄

    作者回复: 终于....

    2019-07-17
    1
  • 许童童
    老师写得好!

    作者回复: 谢谢

    2019-07-17
  • Geek_ty
    这里说一下,在17年后的Linux版本中已经取消了prequeue以及相关的操作,如果阅读较新的Linux内核的同学们请不要误解。现在只剩2个队列了。
    2020-08-15
    3
    13
  • Geek_jikuo
    问题:三层上送四层的时候,数据包是怎样知道自己属于哪个sock的? 答:tcp_v4_rcv() -> __inet_lookup_skb 根据数据包的ip+端口从tcp_hashinfo中找到,会有两个hash表:listening_hash和establish_hash哈希表 (注:参考文中一条笔记)
    2021-08-21
    3
  • 深海极光
    请问下老师,是linux协议栈通过tcp解析完成,放入到receive queue或者backlog queue 再去唤醒用户进程来读的吗,我们一般都是epoll读,而epoll是根据事件变化的,也是在fd的等待队列上睡眠,就是这一步是怎么关联的
    2020-04-11
    2
收起评论
显示
设置
留言
21
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部