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

45 | 发送网络包(上):如何表达我们想让合作伙伴做什么?

ip_queue_xmit函数
struct inet_connection_sock
tcp_transmit_skb函数
tcp_write_xmit函数
tcp_sendmsg函数
struct sock
inet_sendmsg函数
struct socket
sock_write_iter函数
write系统调用
IP层
TCP层
Sock层
Socket层
VFS层
课堂练习
解析socket的Write操作
发送网络包的过程是什么样的?

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

上一节,我们通过 socket 函数、bind 函数、listen 函数、accept 函数以及 connect 函数,在内核建立好了数据结构,并完成了 TCP 连接建立的三次握手过程。
这一节,我们接着来分析,发送一个网络包的过程。

解析 socket 的 Write 操作

socket 对于用户来讲,是一个文件一样的存在,拥有一个文件描述符。因而对于网络包的发送,我们可以使用对于 socket 文件的写入系统调用,也就是 write 系统调用。
write 系统调用对于一个文件描述符的操作,大致过程都是类似的。在文件系统那一节,我们已经详细解析过,这里不再多说。对于每一个打开的文件都有一个 struct file 结构,write 系统调用会最终调用 stuct file 结构指向的 file_operations 操作。
对于 socket 来讲,它的 file_operations 定义如下:
static const struct file_operations socket_file_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read_iter = sock_read_iter,
.write_iter = sock_write_iter,
.poll = sock_poll,
.unlocked_ioctl = sock_ioctl,
.mmap = sock_mmap,
.release = sock_close,
.fasync = sock_fasync,
.sendpage = sock_sendpage,
.splice_write = generic_splice_sendpage,
.splice_read = sock_splice_read,
};
按照文件系统的写入流程,调用的是 sock_write_iter。
static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct file *file = iocb->ki_filp;
struct socket *sock = file->private_data;
struct msghdr msg = {.msg_iter = *from,
.msg_iocb = iocb};
ssize_t res;
......
res = sock_sendmsg(sock, &msg);
*from = msg.msg_iter;
return res;
}
在 sock_write_iter 中,我们通过 VFS 中的 struct file,将创建好的 socket 结构拿出来,然后调用 sock_sendmsg。而 sock_sendmsg 会调用 sock_sendmsg_nosec。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入解析了网络包发送过程中的关键环节,通过对socket的Write操作进行分析,详细阐述了发送一个网络包的内部实现细节。文章首先介绍了socket类似文件的存在,具有文件描述符,可利用write系统调用进行网络包发送。随后,通过对文件系统写入流程的解析,展示了sock_write_iter调用sock_sendmsg,最终调用inet_sendmsg的过程。在inet_sendmsg中,通过socket结构获取更底层的sock结构,然后调用sk_prot的sendmsg方法。文章还深入解析了tcp_sendmsg函数的实现细节,包括数据拷贝到内核协议栈、MSS计算、struct sk_buff的分配和数据拷贝等关键步骤。整体而言,本文通过深入的技术分析,清晰地展示了网络包发送的内部实现细节,对于理解网络通信的底层原理具有重要意义。文章内容涉及TCP层、IP层的细节,对于网络通信技术人员具有较高的参考价值。

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

全部留言(14)

  • 最新
  • 精选
  • 是男人就开巴巴托斯
    有一次分别在服务器端和客户端抓包 服务器端的包都是好几k 十几k. 客户端的包是1400多 一开始没弄明白都mtu了为什么还有好几k的包 后来查到内核可以配置网络参数,不把拆包交给网卡固件,自己分包。

    作者回复: 赞,学以致用

    2019-08-13
    5
    10
  • 佳俊
    sk_buff已经对mss做了分片处理了,为什么还要在ip再做一次分片处理。sk_buff有最大的限制吗?

    作者回复: 就是mss的限制呀

    2020-05-24
    3
    1
  • W.jyao
    老师,请教一个问题,为什么流媒体服务器发送的rtp包都要小于1500左右,也就是小于MTU,理论上不是大于1500会分片吗?但是好像实现的代码都会小于Mtu,为什么呢?

    作者回复: 分片再组合会增加时延

    2019-07-11
    2
    1
  • 一梦如是
    老师好,请教一个困惑很久的问题,cpu的L1,L2,L3级cache,缓存的数据是以内存的页为单位的吗 oracle sga在大内存时,通常会配置hugepage以减少TLB的压力和swap的交换用来提高性能,linux(centos)下默认是2M,而一般cpu L1是32+32K,L2是256K,是不是就意味着没法使用这两级缓存了

    作者回复: Hugepage不会将页面放到缓存里面的,而是TLB缓存减少不命中的概率。

    2019-07-11
    2
  • 谛听
    VFS: 拿到 file 中的 socket,进而得到 sock,进而调用 tcp_sendmsg tcp_sendmsg: 将用户数据拷到 sk_buff,不断循环发送,发送过程中计算 MSS,拆分成一个个的 Segment 放在一个个的 IP 包里面,数据可拷贝到连续的区域,也可以拷到不连续的区域 ( 需要网络设备支持分散聚合),最后调用 tcp_write_xmit 发送网络包 tcp_write_xmit:TSO--分段可由内核做,比较耗CPU,也延迟到网卡做; 拥塞窗口--避免把网络塞满; 滑动窗口--避免把接收端塞满 tcp_transmit_skb:填充tcp报文,发送网络包
    2019-11-24
    2
    8
  • 忆水寒
    从网络协议专栏看完过来的,tcp协议实际上很熟悉,所以看这篇文章大概都懂。但是每次读都能有新的体会。
    2020-02-09
    6
  • stackWarn
    作为一个运维,这节算是这里面听的最轻松的一次了,之前看过这部分的代码,函数名都有点印象哈哈
    2020-10-13
    1
  • Mr小公熊
    在 Linux 内核的 TCP/IP 协议栈中,tcp_sendmsg 函数用于发送 TCP 数据。这个函数会处理数据的包装和发送,包括将数据分割成多个片段(如果需要的话)以及构造适当的网络数据包(sk_buff)。 struct skb_shared_info 是否在 tcp_sendmsg 中使用,并不是由硬件决定的。这个决策完全取决于内核协议栈的逻辑。具体来说,当 TCP 数据的大小超过一个网络数据包的最大传输单元(MTU)时,内核需要将数据分割成多个片段来发送。在这种情况下,struct skb_shared_info 就会被用来存储关于这些额外片段的信息。 以下是一些关键点: 数据分片:如果 TCP 数据的大小超过了 MTU,tcp_sendmsg 会调用 tcp_fragment 函数来分割数据。这个函数会创建多个 sk_buff 结构体,并使用 struct skb_shared_info 来管理这些片段。 硬件无关:这个决策过程完全在软件层面进行,与硬件无关。硬件只负责发送和接收原始的网络数据包,而不知道或不关心这些数据包是如何在软件中被构造和管理的。 协议栈逻辑:tcp_sendmsg 和相关函数根据当前的 TCP 连接状态、可用缓冲区大小、MTU 等因素来决定是否使用 struct skb_shared_info。 因此,struct skb_shared_info 在 tcp_sendmsg 中的使用是由内核协议栈的逻辑决定的,而不是由硬件决定的。这是内核网络栈处理数据包分割和发送的一部分,旨在优化数据传输效率和处理大型或分段的数据包。 好像是否存入shared里不是由软硬件决定的啊。。。
    2024-03-06归属地:上海
  • Geek_2b44d4
    请教一下,这里进行分段后,每个段是否时类似链表结构?分包发送的时候,是不是每个包里面都标记了上一个与下一个的标识,这样接收方收到后就可以重排了,不知道是不是这样?
    2022-05-12
  • 程序员老王
    send 很大数据。假如网络正常,回失败吗?skb回自动增加,没有阻塞和阻塞者 一说吧?
    2022-05-02
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部