当前位置: 首页 > news >正文

实现Linux平台自定义协议族

一 简介

我们常常在Linux系统中编写socket接收TCP/UDP协议数据,大家有没有想过它怎么实现的,如果我们要实现socket接收自定义的协议数据又该怎么做呢?带着这个疑问,我们一起往下看吧~~

二 Linux内核函数简介

在Linux系统中要想实现通过socket接收网络协议栈送过来的数据,首先要对这两个内核函数实现注册, 先来看看这两个函数原型:

//ops: 指向一个描述套接字协议族的 net_proto_family 结构体。这个结构体定义了:
//协议族编号(family),比如 AF_INET(IPv4)或 AF_INET6(IPv6)。
//与此协议族关联的 create 函数,用于创建套接字。
int sock_register(const struct net_proto_family *ops);//prot: 指向一个描述传输层协议的 proto 结构体,该结构体定义了协议的具体实现,包括各种操作和资源管理逻辑,例如发送、接收、内存分配等。
//alloc_slab: 一个布尔值,指定是否为该协议分配内存缓存(slab 缓存),通常用于控制协议的缓冲区管理。
int proto_register(struct proto *prot, int alloc_slab);

1.sock_register 将用户自定义的协议族挂载到内核的协议族表(net_families),注册成功后,用户态程序可以通过指定协议族(如 socket(AF_INET, ..))来创建对应的套接字。

2.proto_register 函数将传输层协议的实现注册到内核的协议栈中,使其可以在对应的套接字类型下运行(如 SOCK_STREAM 对应 TCP),注册的协议通常与 sock_register 中的协议族关联,用于实现更高层次的功能。

两者的关系

  1. sock_register: 是更高层的接口,用于注册协议族(如 AF_INET)。

  2. proto_register: 是传输层的具体实现,用于注册实际的协议逻辑(如 TCP、UDP、或自定义协议)。

通常,一个协议族可能对应多种协议,比如AF_INET(IPv4)对的具体协议又TCP/UDP等,proto_register 是为了支持某个协议族的实际功能,而 sock_register 提供的是更外层的入口。二者可以配合使用,以实现从协议族到协议具体实现的完整功能。

自定义协议族:内核模块实现

下面这个代码是实现自定义一个协议族AF_MYPROTO(28)的内核模块。

测试平台:CentOS7, Linux内核版本: 3.10.0,编译工具:gcc 4.8.5

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/socket.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/init.h>/* 自定义协议族号 (通常选择未使用的值,sock.h有定义) */
#define AF_MYPROTO 28 /* 定义 proto_ops,用于实现 socket 操作 */
static int myproto_sock_create(struct net *net, struct socket *sock, int protocol, int kern);/* 应用层调用close会调用sock_my_release */
static int sock_my_release (struct socket *sock)
{pr_info("sock_my_release............\n");return 0;
}/* 应用层调用recv函数会触发调用下面这个sock_my_recvmsg函数 */
static int sock_my_recvmsg (struct kiocb *iocb, struct socket *sock,struct msghdr *msg, size_t total_len,int flags)
{char buf[32];int i=0;for(i=0; i<32; ++i) buf[i] = (total_len+i)&0xFF;memcpy_toiovec(msg->msg_iov, buf, 32); /* 拷贝数据到应用层buffer */pr_info("total_len=%ld flags=%d\n", total_len, flags);return 0;
}/* 应用层调用send函数会触发调用该sock_my_sendmsg函数 */
static int sock_my_sendmsg (struct kiocb *iocb, struct socket *sock,struct msghdr *m, size_t total_len)
{pr_info("sock_my_sendmsg............\n");return 0;
}static const struct proto_ops myproto_ops = {.family     = AF_MYPROTO,.owner      = THIS_MODULE,.release    = sock_my_release, .bind       = sock_no_bind, /* 默认空函数 xxx_no_xxx(),下同 */.connect    = sock_no_connect,.socketpair = sock_no_socketpair,.accept     = sock_no_accept,.getname    = sock_no_getname,.poll       = sock_no_poll,.ioctl      = sock_no_ioctl,.listen     = sock_no_listen,.shutdown   = sock_no_shutdown,.setsockopt = sock_no_setsockopt,.getsockopt = sock_no_getsockopt,.sendmsg    = sock_my_sendmsg, /* 指定上面实现的函数 */.recvmsg    = sock_my_recvmsg, /* 指定上面实现的函数 */.mmap       = sock_no_mmap,.sendpage   = sock_no_sendpage,
};/* 定义传输协议 proto 结构体 */
static struct proto myproto_proto = {.name = "MYPROTO",.owner = THIS_MODULE,.obj_size = sizeof(struct sock),
};// 定义协议族 net_proto_family
static const struct net_proto_family myproto_family = {.family = AF_MYPROTO,.create = myproto_sock_create,.owner = THIS_MODULE,
};/* 创建 socket 函数 */
static int myproto_sock_create(struct net *net, struct socket *sock, int protocol, int kern) {struct sock *sk;pr_info("MYPROTO: Creating socket\n");if (!protocol)protocol = IPPROTO_IP;/* 分配 socket 的底层数据结构:PF_INET: Internet IP Protocol */sk = sk_alloc(net, PF_INET, GFP_KERNEL, &myproto_proto);if (!sk) return -ENOMEM;sock->ops = &myproto_ops;sock_init_data(sock, sk);return 0;
}/* 模块加载和卸载,模块入口 */
static int __init myproto_init(void) {int ret;pr_info("MYPROTO: Initializing module\n");/* 注册传输层协议,具体协议 */ret = proto_register(&myproto_proto, 1);if (ret) {pr_err("MYPROTO: Failed to register proto\n");return ret;}ret = sock_register(&myproto_family); /* 注册协议族 */if (ret) {pr_err("MYPROTO: Failed to register protocol family\n");proto_unregister(&myproto_proto);return ret;}pr_info("MYPROTO: Module loaded\n");return 0;
}/* 模块卸载时候调用 */
static void __exit myproto_exit(void) {pr_info("MYPROTO: Cleaning up module\n");// 注销协议族和传输层协议sock_unregister(AF_MYPROTO);proto_unregister(&myproto_proto);pr_info("MYPROTO: Module unloaded\n");
}module_init(myproto_init);
module_exit(myproto_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux编程用C@Young");

编译内核模块的Makefile如下:注意内核代码名称为net_prot.c才能编译,

obj-m:=net_prot.o #名称对应起来,也可自己修改KERNELDIR:=/lib/modules/$(shell uname -r)/buildPWD:=$(shell pwd)default:       $(MAKE) -C $(KERNELDIR)  M=$(PWD) modules
clean:        rm -rf *.o *.mod.c *.mod.o *.koendif

编译完成后,使用insmod向内核插入模块:insmod net_prot.ko

使用dmesg查看模块加载信息:

三 自定义协议族:应用程序实现

这个应用程序创建AF_MYPROTO自定义协议的socket,读取数据,示例如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>#define AF_MYPROTO 28 // 和内核协议族号保持一致int main() {int sockfd, i=100;char buf[2048];// 创建套接字sockfd = socket(AF_MYPROTO, SOCK_RAW, 0);if (sockfd < 0) {perror("socket");return EXIT_FAILURE;}printf("Socket created successfully with AF_MYPROTO\n");while(--i){read(sockfd, buf, 32+i);for(int i=0; i<32; ++i){printf("0x%x ", buf[i]);}printf("\n");}// 关闭套接字close(sockfd);return EXIT_SUCCESS;
}

使用dmesgch

四 测试结果

收到来自内核返回数据:该数据是固定填充,做示例演示。

五 总结

通过这个例子,我们了解到了内核协议族的注册与使用流程,加深对Linux协议栈的了解。

我是小C,欢迎大家一起交流学习~

相关文章:

实现Linux平台自定义协议族

一 简介 我们常常在Linux系统中编写socket接收TCP/UDP协议数据&#xff0c;大家有没有想过它怎么实现的&#xff0c;如果我们要实现socket接收自定义的协议数据又该怎么做呢&#xff1f;带着这个疑问&#xff0c;我们一起往下看吧~~ 二 Linux内核函数简介 在Linux系统中要想…...

RL78/G15 Fast Prototyping Board Arduino IDE 平台开发过程

这是一篇基于RL78/G15 Fast Prototyping Board的Arduino IDE开发记录 RL78/G15 Fast Prototyping Board硬件简介&#xff08;背景&#xff09;基础测试&#xff08;方法说明/操作说明&#xff09;开发环境搭建&#xff08;方法说明/操作说明代码结果&#xff09;Arduino IDE RL…...

YOLOv11 NCNN安卓部署

YOLOv11 NCNN安卓部署 前言 yolov11 NCNN安卓部署 目前的帧率可以稳定在20帧左右&#xff0c;下面是这个项目的github地址&#xff1a;https://github.com/gaoxumustwin/ncnn-android-yolov11 上面的检测精度很低时因为这个模型只训练了5个epoch&#xff0c;使用3090训练一个…...

对载入的3dtiles进行旋转、平移和缩放变换。

使用 params: {tx: 129.75845, //模型中心X轴坐标&#xff08;经度&#xff0c;单位&#xff1a;十进制度&#xff09;//小左ty: 46.6839, //模型中心Y轴坐标&#xff08;纬度&#xff0c;单位&#xff1a;十进制度&#xff09;//小下tz: 28, //模型中心Z轴坐标&#xff08;高…...

Rust个人认为将抢占C和C++市场,逐渐成为主流的开发语言

本人使用C开发8年、C#开发15年、中间使用JAVA开发过项目、后期在学习过程中发现了Rust语言说它是最安全的语言&#xff0c;能够解决C、C的痛点、于是抽出一部分时间网上买书&#xff0c;看网上资料进行学习&#xff0c;这一学习起来发现和其它语言比较起来&#xff0c;在编码的…...

在openEuler中使用top命令

在openEuler中使用top命令 概述 top 命令是Linux系统中最常用的实时性能监控工具之一,允许用户查看系统的整体状态,包括CPU使用率、内存使用情况、运行中的进程等。本文档将详细介绍如何在openEuler操作系统中有效利用top命令进行系统监控。 启动top命令 打开终端并输入t…...

探索文件系统,Python os库是你的瑞士军刀

文章目录 探索文件系统&#xff0c;Python os库是你的瑞士军刀第一部分&#xff1a;背景介绍第二部分&#xff1a;os库是什么&#xff1f;第三部分&#xff1a;如何安装os库&#xff1f;第四部分&#xff1a;简单库函数使用方法1. 获取当前工作目录2. 改变当前工作目录3. 列出目…...

【小白学机器学习41】如何从正态分布的总体中去抽样? 获得指定正态分布的样本的2种方法

目录 1 目标&#xff1a;使用2种方法&#xff0c;去从正态分布的总体中去抽样&#xff0c;获得样本 1.1 step1: 首先&#xff0c;逻辑上需要先有符合正态分布的总体population 1.2 从总体中取得样本&#xff0c;模拟抽样的过程 2 从正态分布抽样的方法1 3 从正态分布抽样…...

将VSCode设置成中文语言环境

目录 VSCode默认是英文语言环境&#xff0c;这对于像我这种英语比较菜的人来说不是那么友好 另外也习惯了用中文&#xff0c;所以接下来介绍下如何将VSCode设置成中文语言环境。 1、打开VSCode软件&#xff0c;按快捷键【CtrlShiftP】 2、在弹出的搜索框中输入【configure l…...

Applied Intelligence投稿

一、关于手稿格式&#xff1a; 1、该期刊是一个二区的&#xff0c;模板使用Springer nature格式&#xff0c; 期刊投稿要求&#xff0c;详细期刊投稿指南&#xff0c;大部分按Soringernature模板即可&#xff0c;图片表格声明参考文献命名要求需注意。 2、参考文献&#xff…...

AI-agent矩阵营销:让品牌传播无处不在

矩阵营销是一种通过多平台联动构建品牌影响力的策略&#xff0c;而 AI-agent 技术让这一策略变得更加智能化。AI社媒引流王凭借其矩阵管理功能&#xff0c;帮助品牌在多个平台上实现深度覆盖与精准传播。 1. 矩阵营销的优势 品牌触达更广&#xff1a;多平台联动可以覆盖不同用…...

【0346】Postgres内核 Startup Process 通过 signal 与 postmaster 交互实现 (5)

1. Startup Process 进程 postmaster 初始化过程中, 在进入 ServerLoop() 函数之前,会先通过调用 StartChildProcess() 函数来开启辅助进程,这些进程的目的主要用来完成数据库的 XLOG 相关处理。 如: 核实 pg_wal 和 pg_wal/archive_status 文件是否存在Postgres先前是否发…...

NSSCTF-做题笔记

[羊城杯 2020]easyre 查壳&#xff0c;无壳&#xff0c;64位&#xff0c;ida打开 encode_one encode_tow encode_three 那么我们开始一步一步解密&#xff0c;从最外层开始 def decode_three(encrypted_str):decrypted_str ""for char in encrypted_str:char_code …...

【小白学机器学习35】数据表:整洁数据表,交叉表/列联表,以及两者转化pd.pivot_table()

目录 1 虽然这是个很基础的知识&#xff0c;但是我觉得有必要记录下 2 整洁数据表 3 交叉数据表的2种形式 3.0 交叉表的名字 3.1 2维的交叉表 3.2 用2维表现3维的 3.3 上述内容&#xff0c;具体的markdown文本 4 交叉数据表 4.1 交叉数据表并不整洁 4.2 但是交叉表也…...

springboot旅游管理系统的设计与实现

springboot旅游管理系统的设计与实现 如需源码pc端&#x1f449;&#x1f449;&#x1f449;资源 手机端&#x1f449;&#x1f449;&#x1f449;资源 摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于…...

k8s 1.28 聚合层部署信息记录

–requestheader-client-ca-file –requestheader-allowed-namesfront-proxy-client –requestheader-extra-headers-prefixX-Remote-Extra- –requestheader-group-headersX-Remote-Group –requestheader-username-headersX-Remote-User –proxy-client-cert-file –proxy-cl…...

自由学习记录(25)

只要有修改&#xff0c;子表就不用元表的参数了&#xff0c;用自己的参数&#xff08;只不过和元表里的那个同名&#xff09; 子表用__index“继承”了父表的值&#xff0c;此时子表仍然是空表 一定是创建这样一个同名的变量在原本空空的子表里&#xff0c; 传参要传具体的变…...

关于函数式接口和编程的解析和案例实战

文章目录 匿名内部类“匿名”在哪里 函数式编程lambda表达式的条件Supplier使用示例 ConsumeracceptandThen使用场景 FunctionalBiFunctionalTriFunctional 匿名内部类 匿名内部类的学习和使用是实现lambda表达式和函数式编程的基础。是想一下&#xff0c;我们在使用接口中的方…...

Linux 僵尸进程和孤儿进程, 进程优先级

僵尸进程 之间在进程状态中了解到了 "僵尸状态". 那么处于僵尸状态的进程就是僵尸进程. 僵尸状态是一种特殊的进程状态, 它表示一个进程已经完成执行, 但其父进程尚未回收其终止状态. "僵尸状态" 的本质就是死亡状态. 如何理解僵尸进程: 举个例子: 一个正…...

爬虫笔记24——纷玩岛自动抢票脚本笔记

纷玩岛自动抢票&#xff0c;协议抢票思路实现 一、获取Authorization凭证二、几个关键的参数三、几个关键的接口获取参数v&#xff0c;这个参数其实可以写死&#xff0c;可忽略通过价位获取演出的参数信息获取观演人信息&#xff0c;账号提前录入即可提交订单接口 先看实现图&a…...

《白帽子讲Web安全》15-16章

《白帽子讲Web安全》15-16章 《白帽子讲Web安全》15章15、Web Server配置安全15.1、Apache安全15.2、Nginx安全15.3、jBoss远程命令执行15.4、Tomcat远程命令执行15.5、HTTP Parameter Pollution15.6、小结 第四篇 互联网公司运营安全《白帽子讲Web安全》16章16、互联网业务安全…...

计算机毕业设计Python+LSTM天气预测系统 AI大模型问答 vue.js 可视化大屏 机器学习 深度学习 Hadoop Spark

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

大语言模型压缩技术;推理优化技术;SparseGPT算法;GPTQ算法

目录 大语言模型落地的成本、效率与效果 模型压缩技术 推理优化技术 SparseGPT算法 GPTQ算法 大语言模型落地的成本、效率与效果 模型压缩技术 模型压缩技术是大语言模型轻量化的关键。介绍了多种模型压缩方法,其中权重量化和模型稀疏化是两种主要的技术。 权重量化:权重…...

Facebook的开源项目解析:推动开发者社区的技术进步

Facebook&#xff0c;作为全球领先的社交平台之一&#xff0c;其在技术领域的创新不仅体现在产品功能的实现上&#xff0c;也积极推动开源社区的发展。开源项目已经成为Facebook技术战略的重要组成部分&#xff0c;通过开源&#xff0c;Facebook不仅加速了技术进步&#xff0c;…...

力扣--LCR 149.彩灯装饰记录I

题目 代码 /** Definition for a binary tree node. public class TreeNode { int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val val;this.left left;this.right ri…...

Rust SQLx CLI 同步迁移数据库

上文我们介绍了SQLx及SQLite&#xff0c;并介绍了如何使用代码同步迁移数据库。本文介绍Sqlx cli 命令行工具&#xff0c;介绍如何安装、使用&#xff0c;利用其提供的命令实现数据表同步迁移。Java生态中有flyway, sqlx cli 功能类似&#xff0c;利用命令行工具可以和其他语言…...

批量生成不同用户的pdf 文件(html样式)

技术 selenium thymeleaf itextpdf chromedriver 使用thymeleaf 将动态数据替换 使用selenium chromedriver 进行js &#xff0c;css等逻辑运算后渲染视图 使用itextpdf 将html 转为pdf 文件 html模板 <!DOCTYPE html> <html xmlns:th"http://www.thymeleaf…...

混淆零碎知识点

minifyEnabled true //混淆开关 zipAlignEnabled true // Zipalign优化 shrinkResources true // 移除无用的resource文件 &#xff08;必须要混淆开了之后才才可以设置为true&#xff09; proguard-rules.pro 为混淆文件 //整个文件保留 不被混淆 -keep class com.cn…...

排序算法2

排序算法1-CSDN博客 排序算法1中提及的是较为基础(暴力实现&#xff0c;复杂度较高)的排序算法&#xff0c;不适合于数据量较大的场景&#xff0c;比如序列长度达到1e5 接下来以蓝桥另一道题目来理解其它的排序算法 蓝桥3226 蓝桥账户中心 样例 5 1 5 9 3 7 4、快速排序 快速排…...

【Web开发基础学习——corsheaders 应用的理解】

Web开发基础学习系列文章目录 第一章 基础知识学习之corsheaders 应用的理解 文章目录 Web开发基础学习系列文章目录前言一、使用1.1 安装1.2 配置 二、功能总结 前言 corsheaders 是一个 Django 第三方应用&#xff0c;用于处理跨域资源共享 (CORS)。CORS 是一种机制&#x…...

做网站的策划书/百度网站登录

标题 / 关键词 / 描述title / keywords / description{dede:field.title/} - {dede:global.cfg_webname/}获取顶级栏目相关信息gettoptype(me,typename){dede:field.typeid functiongettoptype(me,typename)/}获取上级栏目相关信息getredtype(me,typename){dede:field.typeid f…...

一键网站提交/seo 优化是什么

题目.用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead 分别完成在对尾插入节点和在队头删除节点。 该队列类模板如下: 1 template <typename T>2 class CQueue3 {4 public:5 void appendTail(const T& node);6 T deleteHead…...

视频解析网站如何做搜索/网站怎样才能在百度被搜索到

alibaba/p3c github地址 : https://github.com/alibaba/p3c可以直接clone到本地(含阿里巴巴Java开发手册(终极版).pdf)主要说说eclipse安装1.在线安装方法Help >> Install New Software 然后输入下面的地址 https://p3c.alibaba.com/plugi...等下面的列表加载出来,直接下…...

济宁网站建设 果壳科技/seo优化工具

在说优化之前需要先GET到以下知识点&#xff0c;这样便于后续的分析。看完这篇文章不仅要会如何优化&#xff0c;还要搞懂为什么这样优化。半双工通信&#xff1a;MySQL的数据传输采用的是半双工通信&#xff0c;同一时间要么是客户端向服务端发送数据&#xff0c;要么是服务端…...

自己做h5网站/全国疫情高峰感染高峰

与Non-mutating Algorithms相比&#xff0c;变易算法能修改容器元素数据&#xff0c;可进行序列数据的复制、交换、替换、填充、移除、旋转、随机抖动、分割。还是参考叶至军的那本书以及网站Cplusplus.com copy 元素复制。该函数用于容器间元素拷贝&#xff0c;将迭代器区间[…...

北京网站建设 标准型 新翼/建设网页

分布式编程模型的背景 编程模型是指编程的方法而不是特指某一种编程语言&#xff0c;如面向对象的编程就是一种编程模型。编程模型大致分为两类&#xff1a;命令式编程和声明式编程。前者最典型的是面向过程的编程语言&#xff0c;如C语言&#xff1b;后者与前者差异较大&#…...