Linux内核netlink机制 - 用户空间和内核空间数据传输
简介:
Netlink socket 是一种Linux特有的socket,用于实现用户空间与内核空间通信的一种特殊的进程间通信方式(IPC) ,也是网络应用程序与内核通信的最常用的接口。
Netlink 是一种在内核和用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就能使用 Netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 Netlink。Netlink 的接口分为应用层接口和内核接口,我们需要在应用程序实现策略,然后在内核实现机制。
用户空间和内核空间的常用通信方式有三种:proc、ioctl、Netlink
(1) /proc-单向:虚拟文件系统,用户获取内核信息,输出数据
(2) ioctl-单向:不能发送异步信息,用户向内核传送命令
(3)netlink-双向:kernel可以启动传输,而不是仅限于响应用户空间请求而返回信息
1、netlink 优点
- 支持全双工、异步通信
- 用户空间使用标准的socket接口即可进行通信
- 支持多播
- 在内核端可用于进程上下文与中断上下文
2、netlink常用场景
- 获取或修改路由信息
- 监听TCP协议数据报文
- 防火墙
- netfilter子系统
- 内核事件向用户态通知
一、netlink常用数据结构及函数
1、netlink应用层数据结构及函数
网络编程对比netlink:网络编程中我们是使用 IP地址 + 端口号 进行寻址的,而 netlink 则是通过 协议类型+进程ID 进行寻址的,其中 协议类型 会在调用 socket接口 的时候指定。
1.1 消息结构
netlink中的message包含消息头和消息体,消息头占16字节,后面跟的是消息体(数据)。
- Message Length:总长度,包括netlink消息头在内的总字节数,占4字节;
- type:消息类型,往往用于协议流程。内核定义了多个标准的消息类型。内核已经使用 netlink实现了多种协议,每个协议都有特定的类型和功能,占2字节;
- Flags:消息标志,占2字节;
- Sequence number:序列号,该项是可选项,类似TCP协议中的报文号。占4字节;
- PID(port ID):端口号,发送端的端口ID号,占4字节;
消息头 nlmsghdr 结构体:
struct nlmsghdr {__u32 nlmsg_len; /* 包括netlink消息头在内,整个消息长度 */__u16 nlmsg_type; /* 消息类型 */__u16 nlmsg_flags; /* 消息标志 */__u32 nlmsg_seq; /* 消息报文的序列号 */__u32 nlmsg_pid; /* 发送端口的ID号,对于内核来说该值就是0,对于用户进程来说就是其socket所绑定的ID号 */
};
1.2 netlink通信地址 struct sockaddr_nl
struct sockaddr_nl 是netlink通信地址跟普通socket struct sockaddr_in类似
struct sockaddr_nl {__kernel_sa_family_t nl_family; /* AF_NETLINK */unsigned short nl_pad; /* 目前未用到,填充为0 */__u32 nl_pid; /* port ID (通信端口号),0表示发送给kernel*/__u32 nl_groups; /* 多播组掩码 */
};
2、netlink内核数据结构及函数
2.1 常用宏
netlink消息类型及常用宏
/******************** netlink消息类型 ********************/
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_UNUSED 1 /* Unused number */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_SELINUX 7 /* SELinux event notifications */
#define NETLINK_ISCSI 8 /* Open-iSCSI */
#define NETLINK_AUDIT 9 /* auditing */
#define NETLINK_FIB_LOOKUP 10
#define NETLINK_CONNECTOR 11
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
#define NETLINK_IP6_FW 13
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16
/* leave room for NETLINK_DM (DM Events) */
#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
#define NETLINK_ECRYPTFS 19
#define NETLINK_RDMA 20
#define NETLINK_CRYPTO 21 /* Crypto layer */#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG#define MAX_LINKS 32/******************** netlink常用宏 ********************/
#define NLMSG_ALIGNTO 4U
/* 宏NLMSG_ALIGN(len)用于得到不小于len且字节对齐的最小数值 */
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )/* Netlink 头部长度 */
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))/* 计算消息数据len的真实消息长度(消息体 + 消息头)*/
#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)/* 宏NLMSG_SPACE(len)返回不小于NLMSG_LENGTH(len)且字节对齐的最小数值 */
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))/* 宏NLMSG_DATA(nlh)用于取得消息的数据部分的首地址,设置和读取消息数据部分时需要使用该宏 */
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))/* 宏NLMSG_NEXT(nlh,len)用于得到下一个消息的首地址, 同时len 变为剩余消息的长度 */
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))/* 判断消息是否 >len */
#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \(nlh)->nlmsg_len <= (len))/* NLMSG_PAYLOAD(nlh,len) 用于返回payload的长度*/
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
2.2 常用函数
1)netlink_kernel_create
static inline struct sock *
netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)
功能:创建内核 socket,以提供和用户态通信
参数:
- net: net指向所在的网络命名空间namespace, 默认情况传入&init_net(不需要定义)这个全局变量;
- unit:netlink协议类型,如NETLINK_TEST、NETLINK_SELINUX等;
- cfg: cfg存放的是netlink内核配置参数(如下)
struct netlink_kernel_cfg {unsigned int groups;unsigned int flags;void (*input)(struct sk_buff *skb); //input 回调函数struct mutex *cb_mutex;int (*bind)(struct net *net, int group);void (*unbind)(struct net *net, int group);bool (*compare)(struct net *net, struct sock *sk);
};
2)单播函数 netlink_unicast()
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock)
功能:发送单播消息
参数:
- ssk: netlink socket(netlink_kernel_create 的返回值);
- skb: skb buff 指针;
- portid: 通信的端口号;
- nonblock:表示该函数是否为非阻塞,如果为1,该函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用 定时睡眠;
3)多播函数 netlink_broadcast()
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid,
__u32 group, gfp_t allocation)
功能:发送多播消息
参数:
- ssk: netlink socket(netlink_kernel_create 的返回值);
- skb: 内核skb buff;
- portid: 端口id;
- group: 是所有目标多播组对应掩码的"OR"操作的合值;
- allocation: 指定内核内存分配方式,通常GFP_ATOMIC用于中断上下文,而GFP_KERNEL用于其他场合。这个参数的存在是因为该API可能需要分配一个或多个缓冲区来对多播消息进行clone;
二、代码实例
代码示例分为用户态和内核态netlink实现。
1、用户态netlink程序
1.1 netlink应用层基本步骤
(1) 使用 socket 声明套接字
int socket(int domain, int type, int protocol)
- domain:表示协议簇,在 netlink 中一般为 AF_NETLINK。
- type:表示套接字类型,在 netlink 中一般为 SOCK_RAW。
- protocol:表示协议类型,在 netlink 中可以是内核支持的协议,也可以是自定义协议。
自定义协议例如:
#define NETLINK_TEST 23 //自定义协议......int skfd = 0;skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
(2) 使用 bind 绑定 本地地址 到套接字
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) //绑定
/* sockaddr_nl 是 netlink 使用的地址数据结构,与网络编程不同 */
struct sockaddr_nl {
__kernel_sa_family_t nl_family; //一般为AF_NETLINK
unsigned short nl_pad; //无需填充
__u32 nl_pid; //与内核通信的进程的PID,0 则代表地址为内核
__u32 nl_groups; //多播组号,netlink支持多播
};
例如:
struct sockaddr_nl nlsrc_addr = {0};/* 设置本地socket地址 */nlsrc_addr.nl_family = AF_NETLINK;nlsrc_addr.nl_pid = getpid();nlsrc_addr.nl_groups = 0;/* 绑定套接字 */if(bind(skfd, (struct sockaddr*)&nlsrc_addr, addr_len) != 0){printf("bind addr error\n"); return -1;}
(3) 构造消息
(4) 接收/发送消息
netlink 有 2 套收发消息的接口,分别是 sendto/recvfrom、sendmsg/recvmsg。
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
1.2 netlink用户空间代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>#define NETLINK_TEST 17
#define RX_BUF_SIZE 100 //接收buf size
#define MAX_PLOAD 100 //发送message内存sizetypedef struct
{struct nlmsghdr hdr;char msg[RX_BUF_SIZE];
}RX_KERNEL_MSG;int main(int argc, char* argv[])
{char *data = "This message is from user's space";//初始化struct sockaddr_nl src_addr, dest_addr; //sockaddr_nl 是 netlink 使用的地址数据结构int skfd, ret, rxlen = sizeof(struct sockaddr_nl);struct nlmsghdr *message;RX_KERNEL_MSG info;char *retval;/* 1.创建NETLINK socket */skfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);if(skfd < 0){printf("can not create a netlink socket\n");return -1;}//初始化 netlink 源地址memset(&src_addr, 0, sizeof(src_addr));src_addr.nl_family = AF_NETLINK;src_addr.nl_pid = getpid();src_addr.nl_groups = 0;if(bind(skfd, (struct sockaddr *)&src_addr, sizeof(src_addr)) != 0){printf("bind() error\n");return -1;}//初始化 netlink 目标地址memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.nl_family = AF_NETLINK;dest_addr.nl_pid = 0; //0表示发送给kerneldest_addr.nl_groups = 0; //多播组/* 2.设置消息 */message = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD));memset(message, '\0', sizeof(struct nlmsghdr));message->nlmsg_len = NLMSG_SPACE(strlen(data)); //包括netlink消息头在内,整个消息长度 message->nlmsg_flags = 0; //消息标志message->nlmsg_type = 0; //消息类型message->nlmsg_seq = 0; //消息报文的序列号message->nlmsg_pid = src_addr.nl_pid; //消息中加入本应用端口pid,内核应答时往此pid写入retval = memcpy(NLMSG_DATA(message), data, strlen(data)); //数据// printf("User Send: %s, len:%d\r\n", (char *)NLMSG_DATA(message), message->nlmsg_len);/* 3.发送消息 */ret = sendto(skfd, message, message->nlmsg_len, 0,(struct sockaddr *)&dest_addr, sizeof(dest_addr)); //将message消息发送给内核if(!ret){perror("send pid:");exit(-1);}/* 4.接收内核发来的信息 */ret = recvfrom(skfd, &info, sizeof(RX_KERNEL_MSG), 0, (struct sockaddr*)&dest_addr, &rxlen);if(!ret){perror("recv form kerner:");exit(-1);}printf("User Receive ACK from kernel:%s\r\n",(char *)info.msg);//内核和用户进行通信close(skfd);free((void *)message);return 0;
}
2、内核空间代码
2.1 netlink内核态编程步骤
内核接口与应用层接口相似,其过程和使用的接口如下:
(1) 创建socket并注册回调
struct netlink_kernel_cfg {unsigned int groups;unsigned int flags;void (*input)(struct sk_buff *skb); /* 接收回调函数 */struct mutex *cb_mutex;int (*bind)(struct net *net, int group);void (*unbind)(struct net *net, int group);bool (*compare)(struct net *net, struct sock *sk);
};/* 创建接口,其中,参数net 一般为 &init_net */
static inline struct sock *netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg)/* 释放接口 */
void netlink_kernel_release(struct sock *sk);
(2) 构造消息
//sk_buff 为内核中 Netlink 使用的数据结构体,下面分别是分配、使用、释放的接口
static inline struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
static inline struct sk_buff *skb_get(struct sk_buff *skb)
void kfree_skb(struct sk_buff *skb);//下面为构建消息内容的接口
static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int payload, int flags)
大概的调用方法为:
//NLMSG_SPACE计算包括消息头在内的消息长度
size_t size = max(NLMSG_SPACE(message_size), (size_t)NLMSG_GOODSIZE);//分配sk_buff内存
sk_buff * log_skb = alloc_skb(size, GFP_ATOMIC);//构造消息结构体
nlmsghdr *nlh = nlmsg_put(log_skb, /*pid*/0, /*seq*/0, type,message_size, 0);//将要发送的数据复制到消息结构体上
if(payload != NULL) {memcpy(nlmsg_data(nlh), payload, size);
}
(3) 接收/发送消息
发送消息有单播、广播两个接口,可以根据实际业务选择使用。
int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock);
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid, __u32 group, gfp_t allocation);
2.2 netlink内核态模块代码
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <linux/netlink.h>#define NETLINK_TEST 17struct {__u32 pid;
}user_process;static struct sock *netlinkfd = NULL;/* 发送到用户空间 */
int send_to_user(int _pid, char *pbuf, uint16_t len)
{struct sk_buff *nl_skb;struct nlmsghdr *nlh;int ret;/* 创建sk_buff 空间 */nl_skb = nlmsg_new(len, GFP_ATOMIC);if(!nl_skb){printk("netlink alloc failure\n");return -1;}/* 设置netlink消息头部 */nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0);if(nlh == NULL){printk("nlmsg_put failaure \n");nlmsg_free(nl_skb);return -1;}/* 拷贝数据发送 */memcpy(nlmsg_data(nlh), pbuf, len);ret = netlink_unicast(netlinkfd, nl_skb, _pid, MSG_DONTWAIT); //发送数据return ret;
}/* 接收回调函数 */
static void netlink_rcv_msg(struct sk_buff *skb)
{struct nlmsghdr *nlh = NULL;char *data = NULL;char *kmsg = "hello users!!!";nlh = nlmsg_hdr(skb);if(skb->len >= NLMSG_SPACE(0)){data = NLMSG_DATA(nlh); //数据if (data){user_process.pid = nlh->nlmsg_pid; //数据从用户端口ID获取printk("kernel recv from user pid %d: %s\n", user_process.pid, data);send_to_user(user_process.pid, kmsg, strlen(kmsg)); //发送数据给用户pid}} else {printk("%s: error skb, length:%d\n", __func__, skb->len);}
}struct netlink_kernel_cfg cfg = { .input = netlink_rcv_msg, /* 设置接收回调函数 */.groups = 0,.flags = 0,.cb_mutex = NULL,.bind = NULL,.compare = NULL,
};int __init test_netlink_init(void)
{/* 创建netlink socket */netlinkfd = (struct sock *)netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);if(netlinkfd == NULL){printk(KERN_ERR "can not create a netlink socket\n");return -1;}return 0;
}void __exit test_netlink_exit(void)
{if (netlinkfd){netlink_kernel_release(netlinkfd); /* release ..*/netlinkfd = NULL;}printk(KERN_DEBUG "test_netlink_exit!!\n");
}module_init(test_netlink_init);
module_exit(test_netlink_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("donga");
3、测试结果
测试代码下载链接:https://download.csdn.net/download/hinewcc/89590914
将内核态代码编译成ko模块,用户态代码编译成app。insmod加载ko模块,并运行app代码:
$ insmod netlink_test.ko #加载驱动
$ ./netlink_app #运行APP
内核态收到用户态发送的数据,并发送"hello users!!!"给用户空间。
相关文章:

Linux内核netlink机制 - 用户空间和内核空间数据传输
简介: Netlink socket 是一种Linux特有的socket,用于实现用户空间与内核空间通信的一种特殊的进程间通信方式(IPC) ,也是网络应用程序与内核通信的最常用的接口。 Netlink 是一种在内核和用户应用间进行双向数据传输的非常好的方式&a…...

Node.js自动化处理TOML文件
在软件开发过程中,自动化处理配置文件是一种常见的需求。TOML(Tom’s Obvious, Minimal Language)是一种用于配置文件的简单易读的格式。本文将展示如何使用Node.js和一些流行的库来自动化读取、修改并写入TOML文件。 1. 准备工作 在开始之前…...

Spring boot 后端向前端发送日期时间发现少了8小时
问题 数据库 后端的控制台输出 前端控制台输出 可以发现少了8小时 问题 springboot 向前端响应数据是默认 Json 格式,所以会有类型转换,springboot 就通过 Jackson 来对 data 类型数据进行转换,但是Jackson 类型的时区是 GMT,与…...

MySQL数据库(基础篇)
🌏个人博客主页:心.c 前言:今天讲解的是MySQL的详细知识点的,希望大家可以收货满满,话不多说,直接开始搞! 🔥🔥🔥文章专题:MySQL 😽感…...

ffmpeg ffplay.c 源码分析二:数据读取线程
本章主要是分析 数据读取线程read_thread 中的工作。如上图红色框框的部分 从ffplay框架分析我们可以看到,ffplay有专⻔的线程read_thread()读取数据, 且在调⽤av_read_frame 读取数据包之前需要做: 1.例如打开⽂件, 2.查找配置解…...

国科大作业考试资料《人工智能原理与算法》2024新编-第十三次作业整理
1、假设我们从决策树生成了一个训练集,然后将决策树学习应用于该训练集。当训练集的大小趋于无穷时,学习算法将最终返回正确的决策树吗?为什么是或不是? 本次有两个参考: 参考一: 当训练集的大小趋于无穷…...

Netdevops入门之Telnetlib语法案例
1、Telnetlib模块: 支持telnet/ssh远程访问的模块很多,常见的有telnetlib、ciscolib、paramiko、netmiko、pexpect,其中telnetlib和ciscolib对应telnet协议,后面3个对应SSH协议。 ①-通过ENSP环境搭建实验环境 ②-基础语法-telnetlib案例1&…...

永辉“爆改”续命
2024年,在线下零售一片哀嚎之下,胖东来似乎活成了国内零售业的密码,同时也变身成为各大零售企业的咨询公司,四处帮助“友商”救火,就连一直名声在外的永辉超市,也成了救火对象。 作为曾经国内生鲜超市的“…...

IEEE双一区Top“饱受诟病”!曾上医院黑名单,国人占比高达82.405%,目测即将拉下神坛?
本周投稿推荐 SCI&EI • 1区计算机类,3.5-4.0(1个月录用) • CCF推荐,1区-Top(3天初审) EI • 各领域沾边均可(2天录用) 知网(CNKI)、谷歌学术 •…...

Hive环境搭建(Mysql数据库)
【实验目的】 1) 了解hive的作用 2) 熟练hive的配置过程(Mysql数据库) 【实验原理】 Hive工具中默认使用的是derby数据库,该数据库使用简单,操作灵活,但是存在一定的局限性,hive支持使用第三方数据库&…...

【ESP32 IDF SPI硬件驱动W25Q64】
目录 SPISPI介绍idf配置初始化配置通信 驱动代码 SPI SPI介绍 详细SPI介绍内容参考我之前写的内容【ESP32 IDF 软件模拟SPI驱动 W25Q64存储与读取数组】 idf配置 初始化配置 spi_bus_initialize() 参数1 :spi几,例如spi2,spi3 参数2:…...

太原高校大学智能制造实验室数字孪生可视化系统平台建设项目验收
随着科技的不断进步,智能制造已经成为推动制造业转型升级的重要力量。太原高校大学智能制造实验室紧跟时代步伐,积极推进数字孪生可视化系统平台的建设,并于近日圆满完成了项目的验收工作。这一里程碑式的成果,不仅标志着实验室在…...

Kafka消息队列
目录 什么是消息队列 高可用性 高扩展性 高可用性 持久化和过期策略 consumer group 分组消费 ZooKeeper 什么是消息队列 普通版消息队列 说白了就是一个队列,生产者生产多少,放在消息队列中存储,而消费者想要多少拿多少,按序列号消费 缓存信息 生产者与消费者解耦…...

@Transactional注解及其事务管理
1. 事务问题概述 事务问题主要来源于数据库,与数据库事务紧密相关。事务的四大特性(ACID): 原子性(Atomicity):事务要么完全执行,要么完全不执行。一致性(Consistency&a…...

ROS2入门到精通—— 3-1 ROS2实战:CasADi —— 优化计算的利器
0 前言 CasADi是一个强大的开源软件库,它提供了一种灵活且高效的方式来构建和解决复杂的非线性模型。通过其直观的API,开发者可以轻松地定义数学表达式并自动求解微分方程、优化问题以及符号计算等任务。 CasADi基于Python编写,但提供了C++和MATLAB接口,使得不同背景的开发…...

日拱一卒 | JVM
文章目录 什么是JVM?JVM的组成JVM的大致工作流程JVM的内存模型 什么是JVM? 我们知道Java面试,只要你的简历上写了了解JVM,那么你就必然会被问到以下问题: 什么是JVM?简单说一下JVM的内存模型?…...

乐尚代驾六订单执行一
加载当前订单 需求 无论是司机端,还是乘客端,遇到页面切换,重新登录小程序等,只要回到首页面,查看当前是否有正在执行订单,如果有跳转到当前订单执行页面 之前这个接口已经开发,为了测试&…...

SciPy 与 MATLAB 数组
SciPy 与 MATLAB 数组 SciPy 是一个开源的 Python 库,广泛用于科学和工程计算。它构建在 NumPy 数组的基础之上,提供了许多高级科学计算功能。MATLAB 是一个高性能的数值计算环境,它也使用数组作为其基础数据结构。在这篇文章中,我们将探讨 SciPy 和 MATLAB 在数组操作上的…...

基于vue-grid-layout插件(vue版本)实现增删改查/拖拽自动排序等功能(已验证、可正常运行)
前端时间有个需求,需要对33(不一定,也可能多行)的卡片布局,进行拖拽,拖拽过程中自动排序,以下代码是基于vue2,可直接运行,报错可评论滴我 部分代码优化来自于GPT4o和Clau…...

DBoW3相关优化脉络
1 DBow3 GitHub - rmsalinas/DBow3: Improved version of DBow2 2 优化后得到fbow GitHub - rmsalinas/fbow: FBOW (Fast Bag of Words) is an extremmely optimized version of the DBow2/DBow3 libraries. 其中fbow是ucoslam的一部分; ucoslam GitHub - la…...

qt 如何制作动态库插件
首先 首先第一点要确定我们的接口是固定的,也就是要确定 #ifndef RTSPPLUGIN_H #define RTSPPLUGIN_H #include "rtspplugin_global.h" typedef void (*func_callback)(uint8_t* data,int len,uint32_t ssrc,uint32_t ts,const char* ipfrom,uint16_t f…...

一种docker start放回Error response from daemon: task xxx错误的解决方式
1. 问题描述 执行systemctl daemon-reload与systemctl restart docker命令后,发现docker中有的应用无法启动,并显示出Exit(255)的错误提示。 重新执行docker start 容器id后发现返回,Error response from daemon: task xxx的错误。 2. 问题…...

规控面试常见问题
一、项目中遇到的困难或者挑战是什么? 二、A*算法原理(伪代码) 输入:代价地图、start 、 goal(Node结构,包含x、y、g、h、id、pid信息) 首先初始化:创建一个优先级队列openlist,它是一个最小堆,根据节点的f值排序 ( priority_queue<Node, std::vector<Node…...

代码随想录算法训练营Day 63| 图论 part03 | 417.太平洋大西洋水流问题、827.最大人工岛、127. 单词接龙
代码随想录算法训练营Day 63| 图论 part03 | 417.太平洋大西洋水流问题、827.最大人工岛、127. 单词接龙 文章目录 代码随想录算法训练营Day 63| 图论 part03 | 417.太平洋大西洋水流问题、827.最大人工岛、127. 单词接龙17.太平洋大西洋水流问题一、DFS二、BFS三、本题总结 82…...

【全网最全】CSDN博客的文字颜色、字体和字号设置
文章目录 一、字体颜色二、字体大小三、字体类型四、字体背景色 在这篇博客中,我们将深入探讨如何在Markdown编辑器中设置文字颜色、大小、字体与背景色。Markdown本身并不直接支持这些功能,但通过结合HTML标签和CSS样式,我们可以实现这些视觉…...

C#实现数据采集系统-Mqtt实现采集数据转发
在数据采集系统中,通过ModbusTcp采集到数据之后,再通过MQTT转发到其他应用 MQTT操作 安装MQTT mqtt介绍和环境安装 使用MQTT 在C#/Net中使用Mqtt MQTT类封装 MQTT配置类 public class MqttConfig{public string Ip {get; set;...

common-intellisense:助力TinyVue 组件书写体验更丝滑
本文由体验技术团队Kagol原创~ 前两天,common-intellisense 开源项目的作者 Simon-He95 在 VueConf 2024 群里发了一个重磅消息: common-intellisense 支持 TinyVue 组件库啦! common-intellisense 插件能够提供超级强大的智能提示功能&…...

图片在线压缩有效方法详解,分享7款最佳图片压缩工具免费(全新)
当您的系统中图片数量不断增加,却无法删除时,那么就需要通过图片压缩来解决您的问题。随着图片文件的增大,高分辨率图片占据了大量存储空间。而此时系统中的存储空间也开始变得不够用,无法跟上高质量图片的增长。因此,…...

electron安装及快速创建
electron安装及快速创建 electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 详细内容见官网:https://www.electronjs.org/zh/docs/latest/。 今天来记录下练习中的安装过程和hello world的创建。 创建项目文件夹,并执行npm 初始化命…...

需要消化的知识点
需要消化 消灭清单 如何自定义一个Interceptor拦截器? 后端开发可以用上的前端技巧 10个堪称神器的 Java 学习网站. 【前端胖头鱼】11 chrome高级调试技巧,学会效率直接提升666% 【前端胖头鱼】10个我经常逛的“小网站” 【前端劝退师lv-6】Chrome D…...