Linux内核态和用户态的socket编程

article/2025/9/24 5:07:33

文章目录

  • 前言
  • 一、内核态socket API
  • 二、server内核态编程
    • 1.源代码:server.c
    • 2.Makefile
  • 三、用户态编程
    • 1.源代码 client.c
    • 2.Makefile
  • 总结


前言

在实际中,有些时候我们底层驱动有数据发生时,需要立即通知应用层获取数据。当然网上的方法有很多种,比如select、poll、sysctl、sysfs、procfs、netlink等,这篇文章是介绍内核态的socket和用户态的socket通信。


一、内核态socket API

内核态socket编程和用户态的socket编程流程一样,但接口API不同,但和用户态的API是对应关系,在net/socket.c中可以看到内核导出符号:

EXPORT_SYMBOL(sock_create_kern);
EXPORT_SYMBOL(sock_release);
EXPORT_SYMBOL(kernel_bind);    
EXPORT_SYMBOL(kernel_listen);    
EXPORT_SYMBOL(kernel_accept);    
EXPORT_SYMBOL(kernel_connect); 
EXPORT_SYMBOL(kernel_sendmsg);    
EXPORT_SYMBOL(kernel_recvmsg);

这里还实现了linux的系统调用,后续讲解Linux如何实现系统调用。这里直接来一个内核态的server和用户态的client例程便于理解。为了方便学习理解,我直接把内核态的server编译为.ko文件,并在ko中开辟一个内核线程。

二、server内核态编程

模块功能:建立套接字, 绑定端口,监听端口,等待连接,接收数据。

1.源代码:server.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <net/sock.h>static struct task_struct *task;	//内核线程任务头//内核线程服务函数,重点!!!!
static int socket_threadfn(void *data)
{struct socket *sock, *nsock;struct sockaddr_in addr;int err;//建立套接字err = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);if(err < 0){printk("sock_create_kern failed.\n");return -1;}//绑定端口memset(&addr, '\0', sizeof(addr));    addr.sin_family      = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port        = htons(8888);err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));if (err < 0){printk("kernel_bind failed.\n");sock_release(sock);return -1;}//监听端口err = kernel_listen(sock, 1024);if (err < 0){printk("kernel_listen failed.\n");sock_release(sock);return -1;}//等待连接err = kernel_accept(sock, &nsock, 0);if (err < 0){printk("kernel_accept failed.\n");sock_release(sock);return -1;}//任务主循环while (!kthread_should_stop()) {struct msghdr       msg = {NULL,};struct kvec     	iov;char buffer[1024];int len, buflen = sizeof(buffer);iov.iov_base     = buffer;iov.iov_len      = (size_t)buflen;//等待sk_bufer中数据可读		wait_event_interruptible(*sk_sleep(nsock->sk),!skb_queue_empty(&nsock->sk->sk_receive_queue) || kthread_should_stop());if(!skb_queue_empty(&nsock->sk->sk_receive_queue)){len = kernel_recvmsg(nsock, &msg, &iov, 1, buflen, MSG_DONTWAIT);if(len<0)printk("receiving message error\n");elseprintk("receiving: %s\n", buffer);}}sock_release(nsock);sock_release(sock);return 0;
}int __init test_server_init(void)
{task = kthread_run(socket_threadfn, NULL, "listen thread");return 0;
}void __exit test_server_exit(void)
{
}
module_init(test_server_init);
module_exit(test_server_exit);
MODULE_LICENSE("GPL");

2.Makefile

server-driver-objs := server.oobj-m:=server-driver.o
PWD:=$(shell pwd)
#这里是你自己已经编译好的内核源码路径
KDIR:=/home/vinda/work/RockLivetQ/linux-3.6
all:$(MAKE) -C $(KDIR) M=$(PWD)
clean:$(RM) -r *.ko *.order *.symvers *.cmd *.o *.mod.c *.tmp_versions .*.cmd .tmp_versions

在设备终端安装驱动,insmod server-derver.ko,启动内核态的服务。


三、用户态编程

模块功能:建立套接字,连接端口,发送数据。

1.源代码 client.c

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>int main(int argc, char* argv[])
{struct sockaddr_in serverAddr;char buffer[1024];int sock, retl;sock = socket(PF_INET,SOCK_STREAM , 0);assert(sock >= 0);bzero(&serverAddr,sizeof(serverAddr));serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);serverAddr.sin_port = htons(8888);serverAddr.sin_family = AF_INET;retl = connect(sock, (const struct sockaddr *)&serverAddr, (socklen_t)sizeof(struct sockaddr));assert(retl >= 0);retl=0;while(1){retl++;sprintf(buffer, "This is frame number %d", retl);send(sock, buffer, strlen(buffer), 0);sleep(1);}return 0;
}

2.Makefile

.PHONY: clean AllCC				= arm-linux-gccAll: client
client:client.o$(CC)  -o $@  $^	
clean:@$(RM) *.o client

在终端启动client程序,这是内核打印输出如下:
在这里插入图片描述

总结

内核态的socket编程还是很好理解的。希望对你们有帮助,谢谢!


http://chatgpt.dhexx.cn/article/w9Ikxas1.shtml

相关文章

CentOS7.6升级内核

CentOS7.6升级内核 方法一 1、更新系统和安装包 yum -y update 安装yum插件&#xff0c;以在安装和更新软件包时更快 yum -y install yum-plugin-fastestmirror 2、查看内核版本 uname -r 3、添加ELrepo存储库&#xff08; 在安装新的内核版本之前&#xff0c;我们需要添加…

寒江独钓-Windows内核安全编程(完整版).pdf

寒江独钓-Windows内核安全编程(完整版).pdf 编写Windows内核程序,就意味着这个程序可以执行任意指令,可以访问计算机所有的软件、硬件资源。因此,稍有不慎就有可能将系统变得不稳定。Windows的设计者设计了各种驱动模型或者框架,如NT式内核驱动模型、WDM框架和新推出的WDF框…

linux kernel内核编程基础总结

Linux_kernel编程基础总结 时间:2015/10/9 背景:学习linux内核编程,总结学习中的经验,方便之后查看; 通常我们想弄清楚linux内核是怎么样工作的,如何使用内核接口来编写linux内核代码的第一步都是搭建一个实验环境来做试验的;这里总结一下实验环境的搭建步骤,和我的一…

内核模块编程之入门(二)—必备知识

模块编程属于内核编程&#xff0c;因此&#xff0c;除了对内核相关知识有所了解外&#xff0c;还需要了解与模块相关的知识。 1&#xff0e;应用程序与内核模块的比较 为了加深对内核模块的了解&#xff0c;表一给出应用程序与内核模块程序的比较。 表一 应用程序与内核模块程…

操作系统实验:Linux内核模块编程

实验内容 &#xff08;1&#xff09;设计一个模块&#xff0c;要求列出系统中所有内核线程的程序名、PID、进程状态、进程优先级、父进程的PID。 &#xff08;2&#xff09;设计一个带参数的模块&#xff0c;其参数为某个进程的PID号&#xff0c;模块的功能是列出该进程的家族…

HC12微控制器上的闪存内核编程

HC12微控制器上的闪存内核编程 作者 Sven Deckardt 限制 草案文件 摘要 本应用笔记的目的是解释如何为HC12实现CCP闪存内核以及如何为闪存编程配置CANape Graph。 目录 1.0概述... 1 闪存内核的一般用法... 1 2.0 Flash内核... 3 2.1结构... 3 2.2 …

Linux内核模块编程入门( 最简单的内核模块编程)

第1章简介 什么是内核模块&#xff1f; 所以&#xff0c;你想编写一个内核模块。 你知道C&#xff0c;你已经编写了一些正常的程序作为进程运行&#xff0c;现在你想要到达实际操作的位置&#xff0c;一个狂野指针可以消灭你的文件系统&#xff0c;核心转储意味着重启。 什么…

Linux内核模块编程

Linux内核模块编程 (作者&#xff1a;Baron_wu 禁止转载) 首先&#xff0c;创建一个内核模块并插入Linux内核中。这是实验第一部分 首先查看当前内核模块使用情概况&#xff1a;lsmod Module&#xff1a;模块名 Size&#xff1a;模块大小 Used by&#xff1a;这些模块在哪被使…

Linux内核网络编程

netfilter 内核网络编程 网络协议数据结构inet_protosw 在Linux-2.6.26.3/net/ipv4/af_inet.c文件中有一个名为inet_init()的函数对协议进行了初始化。inet_init()函数使用proto_register()函数来注册每个内嵌协议。 软中断CPU报文队列及其处理 Linux内核网络协议层的层间…

Linux学习之内核模块编程

前言 之前成功编译了内核&#xff0c;这次学习如何修改增加删除内核模块&#xff0c;为了保证内核的纯净&#xff0c;我特意重新编译安装了一个新的5.11.8的内核&#xff0c;其他内核同理。 本文原创&#xff0c;创作不易&#xff0c;转载请注明&#xff01;&#xff01;&…

MATLAB脚本调用simulink仿真文件及simulink模块参数修改-load_system函数-sim函数-set_param函数

文章目录 1. load_system2. sim3. set_param4. get_param5. 应用 1. load_system 加载系统&#xff0c;添加所需要加载的simulink仿真模型所在的路径和名称。 load_system(pathname\filename);必须加载系统之后才可以完成后续的运行simulink仿真模型和获取仿真模型参数和设置…

Matlab学习笔记3——str2num

Matlab学习笔记3——str2num Convert character array or string to numeric array 将字符数组或字符串转换为数字数组 语法 X str2num(chr) [X,tf] str2num(chr) 输出 X — 输出数组 数字矩阵 输出数组&#xff0c;以数字矩阵形式返回。 tf — 真或假 1 |0 真或假结果…

strlen,strcpy,strcat,strcmp函数

1.strlen函数 strlen函数的作用是计算给定字符串的长度&#xff0c;从内存的某个位置开始&#xff0c;遇到第一个\0结束。 使用样例&#xff1a; int main() {const char *ar "abcdef";printf("%d\n", strlen(ar)); } 返回字符串"abcdef"的…

MATLAB str char cell num格式互相转换

简介 关于如何str char cell num格式互相转换的例子很多&#xff0c;但是都很单一&#xff0c;有时候使用的时候需要查找很久才可以解决问题。这里就对这几种方法进行一个汇总。 之所以会涉及使用cell&#xff0c;是因为涉及字符串、数字在同一个“矩阵”中&#xff0c;这时候…

C++ std::string::substr()

substr()函数返回一个新建的 初始化为string对象的子串的拷贝string对象。 子串是&#xff0c;在字符位置_Off开始&#xff0c;跨越_Count个字符&#xff08;或直到字符串的结尾&#xff09;对象的部分 void main() {//std::string::substr(_Off 0, _Count 4294967295U)&am…

matlab中 str2num 函数与 str2double 函数的区别

str2num 函数与 str2double 函数的相同点与不同点 1. 相同点&#xff1a; 当str为一个含数字的字符串时&#xff0c; str2num 函数与 str2double 函数一样。 如&#xff1a; 2. 不同点&#xff1a;当str为多个字符串构成的数组时&#xff0c; str2num 函数与 str2double 函数有…

可逆计算:下一代软件构造理论

可逆计算&#xff1a;下一代软件构造理论 众所周知&#xff0c;计算机科学得以存在的基石是两个基本理论&#xff1a;图灵于1936年提出的图灵机理论和丘奇同年早期发表的Lambda演算理论。这两个理论奠定了所谓通用计算&#xff08;Universal Computation&#xff09;的概念基础…

android 微积分计算器,不到1M的良心之作 连微积分都能算的计算器APP

计算器可谓是被手机取代的一大电子产品了&#xff0c;不过手机上的APP是否真的有传统的计算器好用&#xff1f;也并不一定。 一来&#xff0c;手机上的计算器APP功能普遍偏弱&#xff0c;特别是手机ROM自带的计算器&#xff1b;二来&#xff0c;计算器APP也算得上是流氓软件的重…

matlab对信号积分,对信号求积分 - Simulink - MathWorks 中国

说明 Integrator 模块输出其输入信号相对于时间的积分值。 Simulink 将 Integrator 模块作为具有一种状态的动态系统进行处理。模块动态由以下方程指定: {x˙(t)=u(t)y(t)=x(t)x(t0)=x0 ,其中: u 是模块输入。 y 是模块输出。 x 是模块状态。 x0 是 x 的初始条件。 虽然这些…