用户空间与内核通信(二)

news2025/1/16 19:05:13

在这里插入图片描述

文章:用户空间与内核通信(一)介绍了系统调用(System Call),内核模块参数和sysfs,sysctl函数方式进行用户空间和内核空间的访问。本章节我将介绍使用netlink套接字和proc文件系统实现用户空间对内核空间的访问。

netlink套接字

netlink是一种基于socket的通信机制,用于在用户空间与内核空间之间进行小量数据的及时交互。netlink套接字允许用户空间程序与内核空间程序建立连接,并通过发送和接收消息来进行通信。

内核模块:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>

#define NETLINK_USER 31
#define MSG_LEN 1024

struct sock *nl_sock = NULL;

// 接收用户空间消息的回调函数
static void nl_recv_msg(struct sk_buff *skb) {
    struct nlmsghdr *nlh;
    char msg[MSG_LEN];

    // 从skb中获取消息头
    nlh = nlmsg_hdr(skb);
    if (nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
        netlink_skb_valid(skb, nlh->nlmsg_len)) {
        // 拷贝消息数据到msg缓冲区
        strncpy(msg, NLMSG_DATA(nlh), MSG_LEN);
        // 打印接收到的消息
        printk(KERN_INFO "Received message from user space: %s\n", msg);
    }
}

// 模块初始化函数
static int __init init_netlink(void) {
    // 创建Netlink套接字
    nl_sock = netlink_kernel_create(&init_net, NETLINK_USER, 0, nl_recv_msg, NULL, THIS_MODULE);
    if (!nl_sock) {
        printk(KERN_ERR "Failed to create netlink socket\n");
        return -1;
    }
    printk(KERN_INFO "Netlink socket created\n");
    return 0;
}

// 模块退出函数
static void __exit exit_netlink(void) {
    if (nl_sock)
        netlink_kernel_release(nl_sock);
    printk(KERN_INFO "Netlink socket released\n");
}

module_init(init_netlink);
module_exit(exit_netlink);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");


用户空间应用程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>

#define NETLINK_USER 31
#define MSG_LEN 1024

int main() {
    int sockfd;
    struct sockaddr_nl src_addr, dest_addr;
    struct nlmsghdr *nlh = NULL;
    struct iovec iov;
    struct msghdr msg;

    sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_USER);
    if (sockfd < 0) {
        perror("socket");
        return -1;
    }

    memset(&src_addr, 0, sizeof(src_addr));
    src_addr.nl_family = AF_NETLINK;
    src_addr.nl_pid = getpid();  // This is the source's port number

    bind(sockfd, (struct sockaddr*)&src_addr, sizeof(src_addr));

    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0;  // To kernel
    dest_addr.nl_groups = 0;

    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MSG_LEN));
    memset(nlh, 0, NLMSG_SPACE(MSG_LEN));
    nlh->nlmsg_len = NLMSG_SPACE(MSG_LEN);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    strcpy(NLMSG_DATA(nlh), "Hello from user space");

    iov.iov_base = (void *)nlh;
    iov.iov_len = nlh->nlmsg_len;
    memset(&msg, 0, sizeof(msg));
    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    sendmsg(sockfd, &msg, 0);

    close(sockfd);
    free(nlh);

    return 0;
}

编译内核模块:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

加载内核模块:

sudo insmod your_module.ko

编译用户空间程序:

gcc user_program.c -o user_program

运行用户空间程序:

sudo ./user_program

proc文件系统

proc是一个虚拟文件系统,用于导出内核和进程的状态信息。用户空间程序可以通过读取proc文件系统中的文件来获取内核和进程的信息,也可以通过写入proc文件来向内核发送指令或修改配置。

这些机制为用户空间与内核空间之间的通信提供了灵活和多样化的方式,使得用户程序能够与操作系统内核进行交互,获取系统服务并完成各种任务。

下面的示例,演示了如何使用proc文件系统在用户空间和内核空间之间进行通信。在此示例中,我们将创建一个proc文件,并使用它来向内核发送和接收数据。

首先,让我们创建一个名为"proc_example"的内核模块,该模块将在/proc目录下创建一个名为"proc_example"的文件。用户可以通过读取和写入此文件来与内核通信。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

#define PROC_ENTRY_NAME "proc_example"
#define BUFFER_SIZE 1024

static struct proc_dir_entry *proc_entry;
static char proc_buffer[BUFFER_SIZE];

// 读取proc文件的回调函数
static ssize_t proc_read(struct file *file, char __user *buffer, size_t count, loff_t *offset) {
    ssize_t len = strlen(proc_buffer);
    if (*offset >= len) {
        return 0; // 已经读取完毕
    }
    if (count > len - *offset) {
        count = len - *offset; // 如果请求的数据超过了剩余的数据量,则只读取剩余的数据量
    }
    if (copy_to_user(buffer, proc_buffer + *offset, count) != 0) {
        return -EFAULT; // 复制数据失败
    }
    *offset += count; // 更新偏移量
    return count;
}

// 写入proc文件的回调函数
static ssize_t proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *offset) {
    if (count >= BUFFER_SIZE) {
        return -EINVAL; // 写入的数据过大
    }
    if (copy_from_user(proc_buffer, buffer, count) != 0) {
        return -EFAULT; // 复制数据失败
    }
    proc_buffer[count] = '\0'; // 添加字符串结束符
    return count;
}

// 模块初始化函数
static int __init init_proc_example(void) {
    proc_entry = proc_create(PROC_ENTRY_NAME, 0666, NULL, &proc_fops);
    if (!proc_entry) {
        printk(KERN_ERR "Failed to create /proc/%s\n", PROC_ENTRY_NAME);
        return -ENOMEM;
    }
    printk(KERN_INFO "/proc/%s created\n", PROC_ENTRY_NAME);
    return 0;
}

// 模块退出函数
static void __exit exit_proc_example(void) {
    if (proc_entry) {
        remove_proc_entry(PROC_ENTRY_NAME, NULL);
        printk(KERN_INFO "/proc/%s removed\n", PROC_ENTRY_NAME);
    }
}

// 定义proc文件操作结构体
static const struct file_operations proc_fops = {
    .read = proc_read,
    .write = proc_write,
};

module_init(init_proc_example);
module_exit(exit_proc_example);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");

编译和加载模块后,你可以在/sys/kernel/debug/proc_example中读取和写入数据。例如,你可以使用cat和echo命令:

$ echo "Hello from user space" > /proc/proc_example
$ cat /proc/proc_example
Hello from user space

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1458783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《白话C++》第10章 STL和boost,Page101 10.4.6 std::weak_ptr

2.基本功能 “柔弱的”weak_ptr专门用来解决上述设计中必须面对的循环指向问题。 weak_ptr并不是真正的智能指针&#xff0c;它必须依附于shared_ptr存在。对应前面的C1、C2&#xff0c;我们写一个弱引用版本的C3和C4的例子&#xff1a; struct C4; struct C3 {~C3(){cout…

社区店运营方案全攻略,助你实现商业梦想

在如今竞争激烈的商业环境中&#xff0c;成功运营一家社区店需要全面的规划和策略。 作为一名在社区开鲜奶吧5年的创业者&#xff0c;我将为你提供一份全面的社区店运营方案攻略&#xff0c;帮助你实现商业梦想。 1、市场调研&#xff1a; 在选择社区店的位置之前&#xff0c…

Java使用Redis实现消息队列

近期刷Java面试题刷到了“如何使用Redis实现消息队列”&#xff0c;解答如下&#xff1a; 一般使用 list 结构作为队列&#xff0c; rpush 生产消息&#xff0c; lpop 消费消息。当 lpop 没有消息的时候&#xff0c;要适当sleep 一会再重试。若不使用sleep&#xff0c;则可以用…

【C++】STL- > string类(超详解!!!)

文章目录 前言1、string类的出现1.1 C语言中的字符串1.2 平时使用 2. 标准库中的string类2.1 string类的常用文档&#xff08;重要&#xff09;&#xff01;&#xff01;&#xff01;&#xff01;2.2 string类的常用接口说明(接口原型我这里就不展示了&#xff0c;文档中都有可…

springcloud-远程调用

微服务的远程调用 RestTemplate 在项目中&#xff0c;当我们需要远程调用一个 HTTP 接口时&#xff0c;我们经常会用到 RestTemplate 这个类。这个类是 Spring 框架提供的一个工具类。 实例化RestTemplate 创建配置类&#xff0c;实例化RestTemplate Configuration public clas…

ubuntu解决“E: Unable to locate package lrzsz“

今天在ubuntu上安装rzsz包时报错&#xff0c;提示无法定位包&#xff0c;提示如下 出现这个问题是因为apt的源没有更新&#xff0c;我们直接说解决办法 把下面的命令执行一遍即可 sudo add-apt-repository main sudo add-apt-repository universe sudo add-apt-repository re…

【漏洞复现】H3C 路由器多系列信息泄露漏洞

Nx01 产品简介 H3C路由器是一款高性能的路由器产品&#xff0c;具有稳定的性能和丰富的功能。它采用了先进的路由技术和安全机制&#xff0c;可以满足不同用户的需求&#xff0c;广泛应用于企业、运营商和数据中心等领域。 Nx02 漏洞描述 H3C路由器多系列存在信息泄露漏洞&…

“薪”的一年程序员裁员潮技术变革情况下 程序员就业机会在哪里?

引言&#xff1a;一对来自中国的工程师夫妻在美国的不幸身亡&#xff0c;疑似与谷歌的裁员有关&#xff0c;这一事件再次引发了人们对技术变革下裁员对程序员影响的关注。 一、针对裁员潮的一些看法 在我看来&#xff0c;技术变革对程序员的影响是双面的。一方面&#xff0c;…

抛弃chatgpt,使用微软的Cursor提升coding效率

Whats Cursor? Cursor编辑器是一个基于GPT-4的代码编辑器&#xff0c;它可以根据用户的自然语言指令或者正在编辑的代码上下文为用户提供代码建议&#xff0c;支持多种编程语言&#xff0c;如Python、Java、C/C#、go等。Cursor编辑器还可以帮助用户重构、理解和优化代码&…

管式土壤墒情监测仪

TH-GTS04随着农业技术的不断进步&#xff0c;土壤墒情监测在农业生产中的作用越来越突出。管式土壤墒情监测仪作为一种先进的土壤水分测量工具&#xff0c;为农业生产提供了准确、实时的土壤水分数据&#xff0c;为科学决策提供了有力支持。 一、管式土壤墒情监测仪的工作原理…

【力扣 - 二叉树的最大深度】

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 提示&#xff1a; 树中节点的数量在 [0, 10^4] 区间内。 -100 < Node.val < 100方法一&#xff1a;深度优先搜索 思路与算法 如…

Redis第一关之常规用法

简介 Redis不用多说&#xff0c;已经火了很多年了&#xff0c;也用了很多年了。现在做一些归纳总结。 这篇文章主要介绍Redis的常规知识及用法&#xff0c;包括数据结构、使用场景、特性、过期机制、持久化机制。 Redis与Mysql Mysql是一款基于磁盘的关系型SQL数据库。 Redi…

软件实际应用实例分享,门诊电子处方模板制作教程,中西医诊所病历开单系统教程

软件实际应用实例分享&#xff0c;门诊电子处方模板制作教程&#xff0c;中西医诊所病历开单系统教程 一、前言 以下软件教程以 佳易王诊所电子处方软件V17.3为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、在开电子处方的时候&#xff0c…

RocketMQ(五):功能特性——消费管理

1 消费者负载均衡 消费者从Apache RocketMQ获取消息消费时&#xff0c;通过消费者负载均衡策略&#xff0c;可以将主题内的消息分配给指定消费者分组中的多个消费者共同分担&#xff0c;提高消费并发能力和消费者的水平扩展能力。 1.1 背景信息 了解消费者负载均衡策略&#x…

文献学习-1-Continuum Robots for Medical Interventions

Chapt 5. 连续体机构分析 5.1 文献学习 5.1.1 Continuum Robots for Medical Interventions Authors: PIERRE E. DUPONT , Fellow IEEE, NABIL SIMAAN , Fellow IEEE, HOWIE CHOSET , Fellow IEEE, AND CALEB RUCKER , Member IEEE 连续体机器人在医学上得到了广泛的应用&a…

“比特币突破5.2万美元”,一枚币可换一斤半黄金?黄金比特币之争再次甚嚣尘上!

自今年1月美国SEC批准比特币现货ETF登陆美股市场之后&#xff0c;只用了短短的30个交易日&#xff0c;比特币ETF就从零膨胀到了近400亿美元的规模&#xff0c;超过白银ETF约100多亿美元的规模&#xff0c;和规模约为900多亿美元的黄金ETF暂时形成了“三七开”的格局。比特币现货…

SpringBoot自动注入源码分析

Spring Boot何时注入Autowired标注的属性&#xff1f; 是在Bean实例化后&#xff0c;填充Bean的时候注入Autowired标注的属性 如果注入类型的Bean存在多个&#xff0c;Spring Boot是如何处理的&#xff1f; 如果存在多个类型的Bean&#xff0c;会根据primary—>javax.ann…

电脑屏幕录制工具 Top10 榜单,免费无水印方法集

随着媒体行业的突飞猛进&#xff0c;不同服务之间对有效屏幕录制的竞争日益激烈。这导致市场上出现了质量参差不齐的屏幕录像机。特别是有些录屏器会自动给你录制的视频加上水印&#xff0c;给需要在公共场合使用的人留下不专业的印象。除此之外&#xff0c;它们甚至不能保护您…

【postgresql】ERROR: relation “data_screen.import_record_id_seq“ does not exist

创建表时候提示下面错误&#xff1a; ERROR: relation "data_screen.import_record_id_seq" does not exist 错误&#xff1a;关系“data_screen.import_record_id_seq”不存在 创建语句 CREATE TABLE "data_screen"."import_record" ("…

[框架系列]-[通用lock框架]

通用lock框架 项目特点一:框架集成1.引入核心依赖2.使用redis厂商lock默认实现Redisson3.使用zookeeper厂商lock 二:api调用示例三:注解支持1.注解介绍2.注解使用示例 四:lock增强五:全局锁降级六:配置1.配置清单2.具体配置介绍3.配置demo 七:CUSTOMER的SPI扩展示例1.SPI扩展点…