45 | 发送网络包(上):如何表达我们想让合作伙伴做什么?
刘超
该思维导图由 AI 生成,仅供参考
上一节,我们通过 socket 函数、bind 函数、listen 函数、accept 函数以及 connect 函数,在内核建立好了数据结构,并完成了 TCP 连接建立的三次握手过程。
这一节,我们接着来分析,发送一个网络包的过程。
解析 socket 的 Write 操作
socket 对于用户来讲,是一个文件一样的存在,拥有一个文件描述符。因而对于网络包的发送,我们可以使用对于 socket 文件的写入系统调用,也就是 write 系统调用。
write 系统调用对于一个文件描述符的操作,大致过程都是类似的。在文件系统那一节,我们已经详细解析过,这里不再多说。对于每一个打开的文件都有一个 struct file 结构,write 系统调用会最终调用 stuct file 结构指向的 file_operations 操作。
对于 socket 来讲,它的 file_operations 定义如下:
按照文件系统的写入流程,调用的是 sock_write_iter。
在 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
《趣谈 Linux 操作系统》,新⼈⾸单¥68
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(14)
- 最新
- 精选
- 是男人就开巴巴托斯有一次分别在服务器端和客户端抓包 服务器端的包都是好几k 十几k. 客户端的包是1400多 一开始没弄明白都mtu了为什么还有好几k的包 后来查到内核可以配置网络参数,不把拆包交给网卡固件,自己分包。
作者回复: 赞,学以致用
2019-08-13510 - 佳俊sk_buff已经对mss做了分片处理了,为什么还要在ip再做一次分片处理。sk_buff有最大的限制吗?
作者回复: 就是mss的限制呀
2020-05-2431 - W.jyao老师,请教一个问题,为什么流媒体服务器发送的rtp包都要小于1500左右,也就是小于MTU,理论上不是大于1500会分片吗?但是好像实现的代码都会小于Mtu,为什么呢?
作者回复: 分片再组合会增加时延
2019-07-1121 - 一梦如是老师好,请教一个困惑很久的问题,cpu的L1,L2,L3级cache,缓存的数据是以内存的页为单位的吗 oracle sga在大内存时,通常会配置hugepage以减少TLB的压力和swap的交换用来提高性能,linux(centos)下默认是2M,而一般cpu L1是32+32K,L2是256K,是不是就意味着没法使用这两级缓存了
作者回复: Hugepage不会将页面放到缓存里面的,而是TLB缓存减少不命中的概率。
2019-07-112 - 谛听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-2428
- 忆水寒从网络协议专栏看完过来的,tcp协议实际上很熟悉,所以看这篇文章大概都懂。但是每次读都能有新的体会。2020-02-096
- stackWarn作为一个运维,这节算是这里面听的最轻松的一次了,之前看过这部分的代码,函数名都有点印象哈哈2020-10-131
- 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
收起评论