使用内核线程的Linux内核的Netlink服务器
- 代码仓库
./client下是客户目录- 根目录下执行
make可以编译模块,执行./remake.sh可以一键编译安装 - 此服务器运行在Ubuntu系统,内核版本为
6.5.0-27-generic,基于NETLINK协议 - 主要实现了基于netlink的通信响应,每次响应的时候都创建一个内核线程(kthread)来执行操作,执行完之后线程自动结束
- 内核创建netlink服务端
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
- 上面注意
NETLINK_USER协议号必须跟用户态的程序设置的相同,否则无法通信 - 发送数据使用
nlmsg_new,nlmsg_put两个函数构造信息,使用nlmsg_unicast发送数据(不区分多播组) - 接收数据使用回调函数实现
// 创建netlink socket
struct netlink_kernel_cfg cfg = {
.input = <call back function>,
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg); - 回调函数会自动传入此时接收到的数据,使用内核提供的宏
NLMSG_DATA和NLMSG_PAYLOAD等可以提取到信息和长度用户端的相关操作
- 创建sock
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER); - 绑定后可以通信
bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr)) - 发送
sendmsg(sock_fd, &msg, 0) - 接收
recvmsg(sock_fd, &msg_recv, 0)/proc下的文件
- 在
/proc下创建一个文件用于读取内核模块的信息proc_entry = proc_create("netlink_stats", 0666, NULL, &proc_file_fops);
- 处理用户的读取操作
// proc文件的读取操作
static ssize_t proc_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) {
char buffer[128];
int len;
len = sprintf(buffer, "Messages received: %d\nTotal bytes: %d\n", message_count, total_bytes);
return simple_read_from_buffer(user_buf, count, ppos, buffer, len);
}内核线程
kthread_run(threadfn, data, namefmt, ...)- 第一个函数是一个
int(*)(void*)的函数,接收一个void*的参数,返回一个返回码 - 第二个是传入的参数
- 第三个是名称
执行结果