Linux源码解读(三十四):网络通信简介——UDP协议实现与性能优化

1. 从“寄信”到“发快递”:理解UDP的本质

聊网络协议,很多人一上来就讲TCP,什么三次握手、流量控制、拥塞避免,听得人头大。但在我看来,想真正理解网络通信,从UDP入手反而是一条捷径。为什么?因为它足够简单、纯粹,就像我们生活中的“发快递”一样直观。

你可以把TCP想象成一次需要签收、确认、甚至中途可以修改地址的“挂号信”服务。而UDP呢?它就是一个“普通快递”。你把数据包(包裹)交给内核(快递员),告诉它目的地地址(IP和端口),然后内核就帮你发出去了。至于这个包裹能不能送到、会不会丢、顺序会不会乱,UDP协议本身一概不管。这种“尽力而为”的交付模式,听起来好像很不靠谱,对吧?但实际上,正是这种“不靠谱”的特性,让UDP在特定场景下变得极其高效和不可或缺。

想想看,你在玩在线竞技游戏时,角色的位置信息需要以每秒几十次甚至上百次的频率发送。如果每次移动都用TCP来确保可靠,一次丢包就要重传、等待,你的游戏角色早就卡成幻灯片了。这时候,UDP的“发了就不管”反而成了优势:旧的位置信息丢了没关系,下一秒新的位置信息又发过来了,体验依然流畅。再比如视频直播、语音通话(VoIP)、DNS查询,这些场景都对延迟极其敏感,偶尔丢一两个数据包(画面花一下、声音卡顿零点几秒)是可以接受的,但绝不能容忍TCP那种重传机制带来的延迟抖动。

所以,理解UDP,首先要放下对“可靠性”的执念,拥抱它的“简单”和“快速”。在Linux内核里,UDP的实现也贯彻了这一哲学:代码路径短,处理逻辑直接,没有那些复杂的缓冲区管理和状态机。接下来,我们就钻进源码里,看看这个“快递员”到底是怎么工作的,以及我们如何能让它跑得更快、更稳。

2. 内核中的UDP快递站:核心数据结构与发送流程

要搞懂UDP的实现,我们得先认识几个关键的内核数据结构。如果你看过这个系列前面关于网络的文章,应该对 sk_buff 和 sock 不陌生。它们同样是UDP舞台上的主角。

struct sock: 这个结构体代表一个网络端点,对于UDP来说,它存储了本地IP、端口,对端IP、端口(如果已连接),以及一堆协议相关的状态和回调函数。UDP有自己专属的 struct udp_sock,它内嵌了一个 struct inet_sock(再内嵌 struct sock),增加了一些UDP特有的字段,比如校验和覆盖开关、组播相关的信息等。但本质上,内核操作时,大部分时间还是在用 struct sock 这个通用接口。

struct sk_buff (skb): 这是网络数据包的“万能容器”。一个数据包从用户空间到网卡驱动,或者反方向过来,其一生都“住”在这个结构体里。它非常精妙,通过 head, data, tail, end 几个指针,实现了协议头的灵活添加和剥离。UDP发送数据时,就是先申请一个skb,把用户数据填进去,然后在前面“挤”出空间来添加UDP头、IP头,最后交给下层发送。

现在,我们跟着一个数据包,走一遍发送流程。当你调用 sendto() 系统调用时,旅程就开始了。

  1. 系统调用入口: 在 net/socket.c 中,sendto() 会调用 sock_sendmsg(),最终落到协议族的发送函数上。对于UDP,这个函数是 inet_sendmsg()。
  2. 协议层分发: inet_sendmsg() 根据socket的类型,找到UDP对应的发送函数 udp_sendmsg()。这个函数在 net/ipv4/udp.c 中,是UDP发送的核心。
  3. 构造消息
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值