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

在这里插入图片描述

文章:用户空间与内核通信(一)介绍了系统调用(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 1024struct 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 1024int 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 numberbind(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 kerneldest_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 1024static 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.hqwc.cn/news/479265.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详解-领航家政策/双2.0模式

#领航家代理政策怎么代理# ∨&#xff1a;ok1234vip 简单点说&#xff01;费率/分润和返现先不说了&#xff0c;领航家是双2.0平台&#xff0c;用户也可以参与其中拼团&#xff0c;费率随之降低能一直降至0费率&#xff0c;甚至可以赚钱&#xff0c;&#xff08;这就是拼团两人…

关于tcp与UDP基本对比

建立连接的差异 TCP 建立连接需要经过三次握手&#xff0c;同时 TCP 断开连接需要经过四次挥手&#xff0c;这也表示 TCP 是一种面向连接的协议&#xff0c;这个连接不是用一条网线或者一个管道把两个通信双方绑在一起&#xff0c;而是建立一条虚拟通信管道。 TCP 的三次握手…

亚马逊鲲鹏系统一键注册亚马逊买家号的软件

在如今的电商世界中&#xff0c;自动注册亚马逊买家号已经成为了一种必要的操作需求。为了规避关联性问题&#xff0c;许多用户选择借助专门设计的软件工具&#xff0c;其中最为流行的就是亚马逊鲲鹏系统。这款软件以其自带防指纹浏览器和全自动化操作功能而闻名。 亚马逊鲲鹏系…

计算机是否还要读研?就看这一点

不知道大家有没有了解最近新出现的chatGPT4&#xff0c;反正我是十分认真的研究了一把 而且&#xff0c;Github刚推出了Github Copilot X&#xff0c;基于chatGPT4&#xff0c;可以直接在IDE里对GPT4提问&#xff0c;帮助重构&#xff0c;调试&#xff0c;debug代码&#xff0…

CG-FS-M2 风速传感器 金属 轻便小巧 量程宽 稳定性好

产品概述 采用电路模块技术开发变送器&#xff0c;操作简单&#xff0c;使用方便&#xff0c;用于实现对环境风速的测量&#xff0c;根据需求可输出脉冲信号&#xff0c;0.4-2V电压或4-20mA电流信号,RS485信号。 功能特点 ◆体积小&#xff0c;携带方便、安装简捷 ◆测量精…

leetcode hot100 分割等和子集

在本题中&#xff0c;我们是要把一个数组&#xff0c;分割成两个子集&#xff0c;并且两个子集的元素和相等。那么也就是说&#xff0c;两个子集的和是相等的&#xff0c;并且都是整个数组的一半。那我们考虑这是一个01背包问题&#xff0c;物品的价值和物品的质量一样&#xf…

C++11---(3)

目录 一、可变参数模板 1.1、可变参数模板的概念 1.2、可变参数模板的定义方式 1.3、如何获取可变参数 二、lambda表达式 2.1、Lamabda表达式定义 2.2、为什么有Lambda 2.3、Lambda表达式的用法 2.4、函数对象与lambda表达式 三、包装器 3.1、function 3.2、bind …

Elasticsearch:什么是 kNN?

kNN - K-nearest neighbor 定义 kNN&#xff08;即 k 最近邻算法&#xff09;是一种机器学习算法&#xff0c;它使用邻近度将一个数据点与其训练并记忆的一组数据进行比较以进行预测。 这种基于实例的学习为 kNN 提供了 “惰性学习&#xff08;lazy learning&#xff09;” 名…

做人力RPO项目需要注意哪些问题?

在当今激烈的商业环境中&#xff0c;企业对人才的需求愈发迫切&#xff0c;人力RPO(招聘流程外包)应运而生。作为一种创新的招聘模式&#xff0c;人力RPO被认为是蓝海项目&#xff0c;拥有广阔的市场前景和巨大潜力。本文将为您揭示做人力RPO市场的关键策略。 一、专业团队&…

用记事本写Java

本篇文章将会用hello word的例子来教大家如何使用记事本写java 1.创建一个txt文件 2.输入代码 public class HelloWorld{public static void main(String[] args){System.out.println("Hello World");} } 3.将文件名后缀由txt改为java 如果不能直接改后缀 打开…

力扣题目训练(17)

2024年2月10日力扣题目训练 2024年2月10日力扣题目训练551. 学生出勤记录 I557. 反转字符串中的单词 III559. N 叉树的最大深度241. 为运算表达式设计优先级260. 只出现一次的数字 III126. 单词接龙 II 2024年2月10日力扣题目训练 2024年2月10日第十七天编程训练&#xff0c;今…

ffmpeg for android编译全过程与遇到的问题

编译前准备 编译环境&#xff1a;Ubuntu16&#xff0c;可自行下载VMWare最新版并百度永久许可证或在服务器上安装Ubuntu ffmpeg源码&#xff1a;ffmpeg4.2.2 NDK下载&#xff1a;Android NDK r21e 有条件的最好还是在Liunx平台下编译吧&#xff0c;Windows平台下编译坑更多…