带你理解Linux内核理解socket的本质

一口Linux 2025-04-14 10:54

击左上方蓝色“一口Linux”,选择“设为星标

第一时间看干货文章 

【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式知识点-思维导图-免费获取
【就业】一个可以写到简历的基于Linux物联网综合项目
【就业】简历模版


图片


本文将从一个初学者的角度开始聊起,让大家了解 Socket 是什么以及它的原理和内核实现。

一、Socket 的概念

 Socket 就如同我们日常生活中的插头与插座的连接关系。在网络编程中,Socket 是一种实现网络通信的接口或机制。 想象一下,插头插入插座后,电流得以流通,实现了能量的传递。而在网络世界里,当一个程序使用 Socket 与另一台机子建立“连接”时,就如同插头成功插入了插座,数据能够在两者之间进行流通和交换。

图片


例如,当我们在网上聊天时,发送方的程序通过 Socket 将消息发送出去,接收方的程序通过对应的 Socket 接收这些消息。又比如在下载文件时,下载程序通过 Socket 与提供文件的服务器建立连接,从而能够获取到所需的文件数据。总之,它是网络通信的端点,用于在不同的计算机进程之间进行通信,而计算机中通过五元组:协议类型、源IP地址、源端口号、目标IP地址、目标端口号,通过五元组来唯一

二、Socket 的使用场景

我们想要将数据从 A 电脑的某个进程发到 B 电脑的某个进程。如果需要确保数据能发给对方,就选可靠的 TCP 协议;如果数据丢了也没关系,就选择不可靠的 UDP 协议。初学者一般首选 TCP。

这时就需要用 socket 进行编程,首先创建关于 TCP 的 socket:

#include #include #include #include  int main() {    int sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    if (sock_fd == -1) {        std::cerr << "Failed to create socket" << std::endl;        return 1;    }     // 后续代码...     return 0;}

这个方法会返回 sock_fd,它是 socket 文件的句柄。

对于服务端,得到 sock_fd 后,依次执行 bind()、listen()、accept() 方法,等待客户端的连接请求;对于客户端,得到 sock_fd 后,执行 connect() 方法向服务端发起建立连接的请求,此时会发生 TCP 三次握手。

连接建立完成后,客户端可以执行 send() 方法发送消息,服务端可以执行 recv() 方法接收消息,反之亦然。

图片


三、Socket 的设计

现在我们抛开socket,重新设计一个内核网络传输功能。我们想要将数据从 A 电脑的某个进程发到 B 电脑的某个进程,从操作上来看,就是发数据给远端和从远端接收数据,也就是写数据和读数据。

但这里有两个问题:

  1. 接收端和发送端可能不止一个,因此需要用 IP 和端口做区分,IP 用来定位是哪台电脑,端口用来定位是这台电脑上的哪个进程。

  2. 发送端和接收端的传输方式有很多区别,如可靠的 TCP 协议、不可靠的 UDP 协议,甚至还需要支持基于 icmp 协议的 ping 命令。


为了支持这些功能,需要定义一个数据结构 sock,在 sock 里加入 IP 和端口字段。这些协议虽然各不相同,但有一些功能相似的地方,可以将不同的协议当成不同的对象类(或结构体),将公共的部分提取出来,通过“继承”的方式复用功能。

于是,定义了一些数据结构:

sock 是最基础的结构,维护一些任何协议都有可能会用到的收发数据缓冲区。

在 Linux 内核 2.6 相关的源码中,sock 结构体的定义可能类似于:

struct sock {    // 相关字段    struct sk_buff_head sk_receive_queue; // 接收数据缓冲区    struct sk_buff_head sk_write_queue;  // 发送数据缓冲区    // 其他可能的字段};

inet_sock 特指用了网络传输功能的 sock,在 sock 的基础上还加入了 TTL、端口、IP 地址这些跟网络传输相关的字段信息。比如 Unix domain socket,用于本机进程之间的通信,直接读写文件,不需要经过网络协议栈。

可能的定义:

struct inet_sock {    struct sock sk; // 继承自 sock    __be32 port;    // 端口    __be32 saddr;   // IP 地址    // 其他相关字段};

inet_connection_sock 是指面向连接的 sock,在 inet_sock 的基础上加入面向连接的协议里相关字段,比如 accept 队列、数据包分片大小、握手失败重试次数等。虽然现在提到面向连接的协议就是指 TCP,但设计上 Linux 需要支持扩展其他面向连接的新协议。

例如:

struct inet_connection_sock {    struct inet_sock inet; // 继承自 inet_sock    struct request_sock_queue accept_queue; // accept 队列    // 其他相关字段};

tcp_sock 就是正儿八经的 TCP 协议专用的 sock 结构,在 inet_connection_sock 基础上还加入了 TCP 特有的滑动窗口、拥塞避免等功能。同样 UDP 协议也会有一个专用的数据结构,叫 udp_sock

大概如下:

struct tcp_sock {    struct inet_connection_sock icsk; // 继承自 inet_connection_sock    // TCP 特有的字段,如滑动窗口、拥塞避免等相关字段};
图片


有了这套数据结构,将它跟硬件网卡对接一下,就实现了网络传输的功能。

四、提供 Socket 层

由于这里面的代码复杂,还操作了网卡硬件,需要较高的操作系统权限,再考虑到性能和安全,于是将它放在操作系统内核里。

为了让用户空间的应用程序使用这部分功能,将这部分功能抽象成简单的接口,将内核的 sock 封装成文件。创建 sock 的同时也创建一个文件,文件有个文件描述符 fd,通过它可以唯一确定是哪个 sock。将fd暴露给用户,用户就可以像操作文件句柄那样去操作这个 sock 。

struct file{    //文件相关的字段    .....    void *private_data; //指向sock}

创建socket时,其实就是创建了一个文件结构体,并将private_data字段指向sock。

图片


有了 sock_fd 句柄后,提供了一些接口,如 send()、recv()、bind()、listen()、connect() 等,这些就是 socket 提供出来的接口。

所以说,socket 其实就是个代码库或接口层,它介于内核和应用程序之间,提供了一堆接口,让我们去使用内核功能,本质上就是一堆高度封装过的接口。

我们平时写的应用程序里代码里虽然用了socket实现了收发数据包的功能,但其 实真正执行网络通信功能的,不是应用程序,而是linux内核。

图片


在操作系统内核空间里,实现网络传输功能的结构是sock,基于不同的协议和应用场景,会被泛化为各种类型的xx_sock,它们结合硬件,共同实现了网络传输功能。为了将这部分功能暴露给用户空间的应用程序使用,于是引入了socket层,同时将sock嵌入到文件系统的框架里,sock就变成了一个特殊的文件,用户就可以在用户空间使用文件句柄,也就是socket_fd来操作内核sock的网络传输能力。

五、Socket 如何实现网络通信

以最常用的 TCP 协议为例,实现网络传输功能分为建立连接和数据传输两个阶段。

(一)建立连接

在客户端,执行 socket 提供的 connect(sockfd, "ip:port") 方法时,会通过 sockfd 句柄找到对应的文件,再根据文件里的信息指向内核的 sock 结构,通过这个 sock 结构主动发起三次握手。

在服务端,握手次数还没达到“三次”的连接叫半连接,完成好三次握手的连接叫全连接,它们分别会用半连接队列和全连接队列来存放,这两个队列会在执行 listen() 方法的时候创建好。当服务端执行 accept() 方法时,就会从全连接队列里拿出一条全连接。

虽然都叫队列,但半连接队列其实是个哈希表,而全连接队列其实是个链表。

在 Linux 内核 2.6 版本的源码中,相关的代码实现可能位于网络子系统的部分。例如,建立连接的过程可能涉及到 tcp_connect() 等函数。

(二)数据传输

为了实现发送和接收数据的功能,sock 结构体里带了一个发送缓冲区和一个接收缓冲区,其实就是个链表,上面挂着一个个准备要发送或接收的数据。

当应用执行 send() 方法发送数据时,会通过 sock_fd 句柄找到对应的文件,根据文件指向的 sock 结构,找到这个 sock 结构里带的发送缓冲区,将数据放到发送缓冲区,然后结束流程,内核看心情决定什么时候将这份数据发送出去。

图片

接收数据流程也类似,当数据送到 Linux 内核后,先放在接收缓冲区中,等待应用程序执行 recv() 方法来拿。

当应用进程执行 recv() 方法尝试获取(阻塞场景下)接收缓冲区的数据时,如果有数据,取走就好;如果没数据,就会将自己的进程信息注册到这个 sock 用的等待队列里,然后进程休眠。如果这时候有数据从远端发过来了,数据进入到接收缓冲区时,内核就会取出 sock 的等待队列里的进程,唤醒进程来取数据。

图片


当多个进程通过 fork 的方式 listen 了同一个 socket_fd,在内核它们都是同一个 sock,多个进程执行 listen() 之后,都会将自身的进程信息注册到这个 socket_fd 对应的内核 sock 的等待队列中。在 Linux 2.6 以前,会唤醒等待队列里的所有进程,但最后其实只有一个进程会处理这个连接请求,其他进程又重新进入休眠,会消耗一定的资源,这就是惊群效应。在 Linux 2.6 之后,只会唤醒等待队列里的其中一个进程,这个问题被修复了。

服务端 listen 的时候,那么多数据到一个 socket 怎么区分多个客户端的?以 TCP 为例,服务端执行 listen 方法后,会等待客户端发送数据来。客户端发来的数据包上会有源 IP 地址和端口,以及目的 IP 地址和端口,这四个元素构成一个四元组,可以用于唯一标记一个客户端。服务端会创建一个新的内核 sock,并用四元组生成一个 hash key,将它放入到一个 hash 表中。下次再有消息进来的时候,通过消息自带的四元组生成 hash key 再到这个 hash 表 里重新取出对应的 sock 就好了。

图片


六、Socket 怎么实现“继承”

Linux 内核是 C 语言实现的,而 C 语言没有类也没有继承的特性,是通过结构体里的内存是连续的这一特点来实现“继承”的效果。将要继承的“父类”,放到结构体的第一位,然后通过结构体名的长度来强行截取内存,这样就能转换结构体,从而实现类似“继承”的效果。

图片


例如:

struct tcp_sock {    /* inet_connection_sock has to be the first member of tcp_sock */    struct inet_connection_sock inet_conn;    // 其他字段}; struct inet_connection_sock {    /* inet_sock has to be the first member! */    struct inet_sock icsk_inet;    // 其他字段}; // sock 转为 tcp_sockstatic inline struct tcp_sock *tcp_sk(const struct sock *sk) {    return (struct tcp_sock *)sk;}

七、总结

  • socket 中文套接字,可理解为一套用于连接的数字。

  • sock 在内核,socket_fd 在用户空间,socket 层介于内核和用户空间之间。

  • 在操作系统内核空间里,实现网络传输功能的结构是 sock,基于不同的协议和应用场景,会被泛化为各种类型的 xx_sock,它们结合硬件,共同实现了网络传输功能。为了将这部分功能暴露给用户空间的应用程序使用,于是引入了 socket 层,同时将 sock 嵌入到文件系统的框架里,sock 就变成了一个特殊的文件,用户就可以在用户空间使用文件句柄,也就是 socket_fd 来操作内核 sock 的网络传输能力。

  • 服务端可以通过四元组来区分多个客户端。

  • 内核通过 C 语言“结构体里的内存是连续的”这一特点实现了类似继承的效果。

end



一口Linux 


关注,回复【1024】海量Linux资料赠送


精彩文章合集

文章推荐

【专辑】ARM
【专辑】粉丝问答
【专辑】所有原创
专辑linux入门
专辑计算机网络
专辑Linux驱动
【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式所有知识点-思维导图

一口Linux 写点代码,写点人生!
评论 (0)
  • 据国际精益六西格玛研究所(ILSSI)成员大卫·哈钦斯(David Hutchins)的回忆,在“六西格玛”名称出现前,摩托罗拉组建了约100个质量改进团队,接受朱兰博士制作的16盘录像带培训,名为《朱兰论质量改进》(Juran on Quality Improvement),为了推广这种严谨的分析方法(朱兰博士视频中的核心内容),摩托罗拉前首席执行官鲍勃·加尔文创造了“六西格玛”这一标签,用以表彰这种“最顶尖"的方法。大卫·哈钦斯(David Hutchins)是朱兰博士的好友,也为他的工作做
    优思学院 2025-04-22 12:03 73浏览
  •   北京华盛恒辉机场保障能力评估系统软件深度解析   在航空运输业快速发展的背景下,机场保障任务愈发复杂,传统人工评估方式已无法满足高效精准的管理需求。机场保障能力评估系统软件作为提升机场运行效率、保障飞行安全的关键工具,其重要性日益凸显。   应用案例   目前,已有多个机场保障能力评估系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润机场保障能力评估系统。这些成功案例为机场保障能力评估系统的推广和应用提供了有力支持。   一、系统功能模块   数据采集与整合模块  
    华盛恒辉l58ll334744 2025-04-22 10:28 100浏览
  • 引言:老龄化社会的健康守护需求随着全球老龄化进程加速,老年人的健康管理与生活质量成为社会焦点。记忆衰退、用药混乱、日程遗漏等问题频发,催生了智能健康设备的市场需求。WTR096录音语音芯片,凭借其高度集成的录放音、计时时钟与计划管理功能,为老年人量身打造了一站式健康管理方案,重新定义智能语音时钟的价值。功能亮点:1. 用药安全守护:多维度提醒,拒绝遗忘多时段精准提醒:支持一天内设置多个用药时间(如早、中、晚),适配复杂用药需求。个性化语音定制:家属可录制专属提醒语音(如“上午9点,请服用降压药”
    广州唯创电子 2025-04-22 08:41 104浏览
  • 近期,金融界消息称,江西万年芯微电子有限公司申请一项名为“基于预真空腔体注塑的芯片塑封方法及芯片”的专利。此项创新工艺的申请,标志着万年芯在高端芯片封装领域取得重要突破,为半导体产业链提升注入了新动能。专利摘要显示,本发明公开了一种基于预真空腔体注塑的芯片塑封方法,方法包括将待塑封的大尺寸芯片平铺于下模盒腔体内的基板并将大尺寸芯片的背向表面直接放置于基板上以进行基板吸附;将上模盒盖合于下模盒形成塑封腔,根据基板将塑封腔分为上型腔以及下型腔;将下型腔内壁与大尺寸芯片间的空隙进行树脂填充;通过设置于
    万年芯 2025-04-22 13:28 75浏览
  • 在汽车行业的变革浪潮中,智界汽车的诞生备受瞩目。作为华为与奇瑞两大巨头携手合作的结晶,智界汽车自孕育之初便承载着众人的期待,被视为融合前沿科技与卓越制造的典范,有望在竞争激烈的新能源汽车市场中开辟出一片新天地。2024年,智界品牌首款车型智界S7正式上市,凭借华为的技术赋能,如先进的鸿蒙智能座舱、强大的HUAWEI ADS高阶智能驾驶辅助系统,以及奇瑞多年积累的深厚造车底蕴,在上市前赚足了眼球。智界S7的亮相,犹如一颗投入平静湖面的石子,激起了层层涟漪,消费者对其充满了好奇与期待,行业内也纷纷将
    用户1742991715177 2025-04-21 20:28 82浏览
  •   北京华盛恒辉基于GIS的电磁态势可视化系统软件是将地理空间信息与电磁态势数据相结合,通过图形化手段直观展示电磁环境态势的系统。这类软件在军事、通信、无线电管理等领域具有广泛应用,能够辅助用户进行电磁频谱分析、干扰监测、态势研判和决策支持。以下是关于此类系统的详细介绍:   应用案例   目前,已有多个电磁态势可视化系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁态势可视化系统。这些成功案例为电磁态势可视化系统的推广和应用提供了有力支持。   一、系统功能   电磁
    华盛恒辉l58ll334744 2025-04-22 11:44 78浏览
  • 4 月 19 日,“增长无界・智领未来” 第十六届牛商大会暨电子商务十大牛商成果报告会在深圳凤凰大厦盛大举行。河南业之峰科技股份有限公司总经理段利强——誉峰变频器强哥凭借在变频器领域的卓越成就,荣膺第十六届电子商务十大牛商,携誉峰变频器品牌惊艳亮相,以十几年如一日的深耕与创新,书写着行业传奇。图 1:誉峰变频器强哥在牛商大会领奖现场,荣耀时刻定格牛商大会现场,誉峰变频器强哥接受了多家媒体的专访。面对镜头,他从容分享了自己在变频器行业二十年的奋斗历程与心路感悟。谈及全域营销战略的成功,誉峰变频器强
    电子与消费 2025-04-22 13:22 103浏览
  •   电磁兼容(EMC)故障诊断系统软件解析   北京华盛恒辉电磁兼容故障诊断系统软件是攻克电子设备电磁干扰难题的专业利器。在电子设备复杂度攀升、电磁兼容问题频发的背景下,该软件于研发、测试、生产全流程中占据关键地位。以下为其详细介绍:   应用案例   目前,已有多个电磁兼容故障诊断系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁兼容故障诊断系统。这些成功案例为电磁兼容故障诊断系统的推广和应用提供了有力支持。   一、软件核心功能   干扰与敏感分析:深度剖析电磁干
    华盛恒辉l58ll334744 2025-04-22 14:53 95浏览
  •   电磁干扰抑制系统平台深度解析   一、系统概述   北京华盛恒辉电磁干扰抑制系统在电子技术快速发展、电磁环境愈发复杂的背景下,电磁干扰(EMI)严重影响电子设备性能、稳定性与安全性。电磁干扰抑制系统平台作为综合性解决方案,通过整合多元技术手段,实现对电磁干扰的高效抑制,确保电子设备稳定运行。   应用案例   目前,已有多个电磁干扰抑制系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁干扰抑制系统。这些成功案例为电磁干扰抑制系统的推广和应用提供了有力支持。   二
    华盛恒辉l58ll334744 2025-04-22 15:27 99浏览
  •   电磁兼容故障诊断系统平台深度解析   北京华盛恒辉电磁兼容(EMC)故障诊断系统平台是解决电子设备在复杂电磁环境下性能异常的核心工具。随着电子设备集成度提升与电磁环境复杂化,EMC 问题直接影响设备可靠性与安全性。以下从平台架构、核心功能、技术实现、应用场景及发展趋势展开全面剖析。   应用案例   目前,已有多个电磁兼容故障诊断系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁兼容故障诊断系统。这些成功案例为电磁兼容故障诊断系统的推广和应用提供了有力支持。  
    华盛恒辉l58ll334744 2025-04-22 14:29 90浏览
  •   卫星通信效能评估系统平台全面解析   北京华盛恒辉卫星通信效能评估系统平台是衡量卫星通信系统性能、优化资源配置、保障通信服务质量的关键技术工具。随着卫星通信技术的快速发展,特别是低轨卫星星座、高通量卫星和软件定义卫星的广泛应用,效能评估系统平台的重要性日益凸显。以下从技术架构、评估指标、关键技术、应用场景及发展趋势五个维度进行全面解析。   应用案例   目前,已有多个卫星通信效能评估系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润卫星通信效能评估系统。这些成功案例为卫
    华盛恒辉l58ll334744 2025-04-22 16:34 82浏览
  • 引言:工业安全与智能化需求的双重驱动在工业安全、环境保护及家庭安防领域,气体泄漏引发的安全事故始终是重大隐患。随着传感器技术、物联网及语音交互的快速发展,气体检测报警器正朝着智能化、低成本、高可靠的方向演进。WT588F02B-8S语音芯片,以“离在线语音更换+多协议通信”为核心优势,为气体检测报警器提供了一套高效、灵活的低成本语音解决方案,助力开发者快速响应市场需求。产品功能与市场需求1. 核心功能:从监测到预警的全流程覆盖实时气体监测:支持一氧化碳、臭氧、硫化氢等多种气体浓度检测,精度可达p
    广州唯创电子 2025-04-22 09:14 73浏览
  • 在消费金融的赛道上,马上消费曾是备受瞩目的明星企业。自2015年成立以来,它以年均 30% 的净利润增速一路狂奔,成为持牌消费金融公司的标杆,2023年更是斩获19.82亿元净利润,风光无限。然而,2024年却成了马上消费的一道分水岭。2024年上半年,其营收为77.38亿元,同比下降2.11%;净利润更是同比骤降20.66%,仅为10.68亿元,创下历史最大跌幅 。与此同时,不良贷款率攀升至2.5%,不良余额高达16.54亿元,核心资本充足率降至12.72%,融资
    用户1742991715177 2025-04-21 21:29 107浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦