Linux驱动开发-字符设备驱动开发
- linux 驱动开发
- 1. 驱动程序的类型
- 2. 驱动开发流程
- 字符设备驱动
- 1. 基本概念
- 2. 字符设备驱动的基本结构
- 架构
- 字符设备驱动开发中常用的 API
- 示例
- 以下代码加入了设备类和设备实例的创建
linux 驱动开发
1. 驱动程序的类型
在 Linux 中,驱动程序主要有以下几种类型:
字符设备驱动:处理字节流的设备,如串口、键盘等。它们通过字符设备接口(如 /dev/tty)与用户空间进行交互。
块设备驱动:处理块存储设备,如硬盘、SSD 等。它们支持随机访问,提供高效的数据传输。
网络设备驱动:用于网络接口卡,处理网络数据包的发送和接收。
USB 驱动:支持 USB 设备的连接和管理。
2. 驱动开发流程
以下是开发 Linux 驱动的一般流程:
2.1 环境准备
确保你有一个支持的 Linux 发行版。
安装开发工具,如 gcc 和 make。
下载和编译 Linux 内核源代码(与你的内核版本一致)。2.2 编写驱动代码
根据你要开发的设备类型,选择合适的接口。
创建相应的初始化(init)和退出(exit)函数。
根据设备实现文件操作结构体 file_operations。2.3 编写 Makefile
创建 Makefile,用于编译你的模块。2.4 编译模块
在终端中通过 make 命令编译模块。2.5 加载和测试模块
使用 insmod 加载模块,使用 rmmod 卸载模块。
通过 dmesg 查看内核日志,调试和验证模块功能。
字符设备驱动
字符设备驱动是Linux内核中的一种设备驱动类型,
主要用于处理字符设备(如键盘、鼠标、串口等)。
字符设备以字节流的形式进行数据传输,与块设备(如硬盘、SSD等)不同,
块设备以固定大小的块进行数据传输。
下面是一个简单的字符设备驱动入门指南:
1. 基本概念
字符设备(Character Device):以字节流的形式进行数据传输的设备。
设备文件:在Linux中,字符设备通过设备文件(通常位于/dev目录下)与用户空间进行交互。
主设备号和次设备号:设备文件由主设备号和次设备号标识。主设备号用于标识设备驱动,次设备号用于标识特定的设备实例。
2. 字符设备驱动的基本结构
字符设备驱动通常包括以下几个部分:
设备注册:向内核注册字符设备。
文件操作接口:定义设备文件的操作接口(如open, read, write, close等)。
设备操作函数:实现具体的设备操作逻辑。
架构
字符设备驱动程序在 Linux 中的架构通常包括以下几个关键组件:设备注册: 使用 register_chrdev 注册设备,并提供操作函数。驱动程序需要处理打开、读取、写入和关闭操作,通常通过定义 file_operations 结构体来实现。打开、读写、关闭接口: 驱动程序需要实现用户空间程序可以调用的接口。读取和写入操作使用 copy_to_user 和 copy_from_user 进行数据传输。内存管理: 使用 kmalloc 和 kfree 进行动态内存分配和释放,以管理驱动所需的数据结构。进程同步: 使用等待队列(基于 wait_queue_head_t)来管理进程的等待与唤醒,实现异步操作。错误处理: 驱动程序需要实现适当的错误处理机制,以确保在发生错误时能够提供适当的反馈。
字符设备驱动开发中常用的 API
/** 1. register_chrdev* 功能:注册字符设备。* 参数:* int nr: 主设备号。如果设置为 0,内核会自动分配一个主设备号。* const char *name: 设备的名字,将显示在 /proc/devices 中。* struct file_operations *fops: 指向文件操作结构体的指针,定义设备的操作函数。* 返回值:* 返回主设备号,如果发生错误,则返回负值。*/
int register_chrdev(unsigned int nr, const char *name, struct file_operations *fops);/** 2. unregister_chrdev* 功能:注销字符设备。* 参数:* int nr: 要注销的主设备号。* const char *name: 设备的名字。* 返回值:* 无。*/
void unregister_chrdev(unsigned int nr, const char *name);/** 3. copy_to_user* 功能:将数据从内核空间复制到用户空间。* 参数:* void __user *to: 用户空间的目标地址。* const void *from: 内核空间的源地址。* unsigned long count: 要复制的字节数。* 返回值:* 返回未成功复制的字节数。如果为 0,表示成功。*/
long copy_to_user(void __user *to, const void *from, unsigned long count);/** 4. copy_from_user* 功能:将数据从用户空间复制到内核空间。* 参数:* void *to: 内核空间的目标地址。* const void __user *from: 用户空间的源地址。* unsigned long count: 要复制的字节数。* 返回值:* 返回未成功复制的字节数。如果为 0,表示成功。*/
long copy_from_user(void *to, const void __user *from, unsigned long count);/** 5. kmalloc* 功能:分配内核内存。* 参数:* size_t size: 要分配的内存字节数。* gfp_t flags: 分配内存的标志,如 GFP_KERNEL。* 返回值:* 返回指向分配内存区域的指针。如果分配失败,返回 NULL。*/
void *kmalloc(size_t size, gfp_t flags);/** 6. kfree* 功能:释放内核内存。* 参数:* void *ptr: 指向要释放内存的指针。* 返回值:* 无。*/
void kfree(void *ptr);/** 7. init_waitqueue_head* 功能:初始化等待队列头。* 参数:* wait_queue_head_t *q: 等待队列头指针。* 返回值:* 无。*/
void init_waitqueue_head(wait_queue_head_t *q);/** 8. wait_event* 功能:将当前进程放入等待队列,直到条件满足为止。* 参数:* wait_queue_head_t *q: 等待队列头指针。* int condition: 条件表达式,当其评估为真时,返回进程。* 返回值:* 无。*/
#define wait_event(q, condition) wait_event_interruptible(q, condition)/** 9. wake_up* 功能:唤醒等待队列中的进程。* 参数:* wait_queue_head_t *q: 等待队列头指针。* 返回值:* 无。*/
void wake_up(wait_queue_head_t *q);/** 10. printk* 功能:在内核中打印日志信息。* 参数:* const char *fmt: 格式化字符串。* 返回值:* 返回打印的字符数。*/
int printk(const char *fmt, ...);
示例
#include <linux/module.h> // 包含模块相关的宏和函数
#include <linux/init.h> // 包含模块初始化和退出相关的宏
#include <linux/fs.h> // 包含文件系统相关的函数和结构体
#include <linux/cdev.h> // 包含字符设备相关的函数和结构体
#include <linux/uaccess.h> // 包含用户空间和内核空间数据传输的函数// 设备号
static dev_t dev_num;// 字符设备结构体
static struct cdev chr_dev;// 设备缓冲区
static char buffer[1024];// 缓冲区大小
static int buffer_size = 0;// 模块许可证
MODULE_LICENSE("GPL");// 模块作者
MODULE_AUTHOR("gopher");// 模块描述
MODULE_DESCRIPTION("A simple character device driver");// 打开设备文件时的回调函数
// 打开设备文件时,内核会创建设备文件结构体和相关资源
// 该函数在内核空间中执行,因此不能有进程上下文的操作
// 该函数的返回值是成功与否的标志
//@param struct inode *inode 设备文件节点结构体
// @param struct file *file 设备文件结构体
static int chr_dev_open(struct inode *inode, struct file *file) {printk(KERN_INFO "chr_dev: Device opened\n");//打印设备号return 0;
}// 关闭设备文件时的回调函数
// 关闭设备文件时,内核会释放设备文件结构体和相关资源
// 该函数在内核空间中执行,因此不能有进程上下文的操作
// 该函数的返回值是成功与否的标志
//@param struct inode *inode 设备文件节点结构体
// @param struct file *file 设备文件结构体
static int chr_dev_release(struct inode *inode, struct file *file) {printk(KERN_INFO "chr_dev: Device closed\n");return 0;
}// 从设备读取数据时的回调函数
// 从设备读取数据时,内核会将数据从内核缓冲区复制到用户空间缓冲区
// 并更新读取位置
// 从设备读取数据时,内核会返回实际读取的字节数
// 如果读取位置超出缓冲区大小,则返回0
// 如果发生其他错误,则返回-EFAULT
// 成功读取数据时,返回实际读取的字节数
// 注意:从设备读取数据时,内核不会阻塞,而是立即返回
//@param struct file *file 设备文件结构体
// @param char __user *user_buf 用户空间缓冲区
// @param size_t count 要读取的字节数
// @param loff_t *ppos 读取位置指针
static ssize_t chr_dev_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) {int ret;// 检查读取位置是否超出缓冲区大小if (*ppos >= buffer_size)return 0;// 将数据从内核缓冲区复制到用户空间缓冲区ret = copy_to_user(user_buf, buffer + *ppos, count);if (ret)return -EFAULT; // 复制失败printk(KERN_INFO "chr_dev: Read %d bytes from device\n", count);// 更新读取位置*ppos += count;return count;
}// 向设备写入数据时的回调函数
// 向设备写入数据时,内核会将数据从用户空间缓冲区复制到内核缓冲区
// 并更新缓冲区大小
// 向设备写入数据时,内核会返回实际写入的字节数
// 如果缓冲区已满,则返回-ENOSPC
// 如果发生其他错误,则返回-EFAULT
// 成功写入数据时,返回实际写入的字节数
// 注意:向设备写入数据时,内核不会阻塞,而是立即返回
//@param struct file *file 设备文件结构体
// @param const char __user *user_buf 用户空间缓冲区
// @param size_t count 要写入的字节数
// @param loff_t *ppos 读取位置指针
static ssize_t chr_dev_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) {int ret;// 检查缓冲区是否有足够的空间if (count > sizeof(buffer) - buffer_size)return -ENOSPC; // 空间不足// 将数据从用户空间缓冲区复制到内核缓冲区//@param void *to 目的地址// @param const void *from 源地址// @param size_t n 字节数ret = copy_from_user(buffer + buffer_size, user_buf, count);if (ret)return -EFAULT; // 复制失败// 打印调试信息printk(KERN_INFO "chr_dev: Wrote %d bytes to device\n", count);// 更新缓冲区大小buffer_size += count;return count;
}// 文件操作结构体,定义了设备文件的操作接口
// 包含了文件操作的回调函数和一些其他属性
// 这些回调函数在设备文件被打开、关闭、读、写时被调用
static struct file_operations chr_dev_fops = {.owner = THIS_MODULE, // 模块所有者.open = chr_dev_open, // 打开设备文件的回调函数.release = chr_dev_release, // 关闭设备文件的回调函数.read = chr_dev_read, // 从设备读取数据的回调函数.write = chr_dev_write, // 向设备写入数据的回调函数
};// 模块初始化函数
static int __init chr_dev_init(void) {int ret;// 分配设备号//@param dev_t dev_num 设备号// @param unsigned int major 主设备号// @param unsigned int minor 次设备号// @param const char *name 设备名ret = alloc_chrdev_region(&dev_num, 0, 1, "chr_dev");if (ret < 0) {printk(KERN_ERR "chr_dev: Failed to allocate device number\n");return ret;}// 初始化字符设备//@param struct cdev *cdev 字符设备结构体// @param struct file_operations *fops 字符设备操作结构体cdev_init(&chr_dev, &chr_dev_fops);chr_dev.owner = THIS_MODULE;// 添加字符设备//@param struct cdev *cdev 字符设备结构体// @param dev_t dev 设备号// @param unsigned int count 设备号计数ret = cdev_add(&chr_dev, dev_num, 1);if (ret < 0) {printk(KERN_ERR "chr_dev: Failed to add character device\n");unregister_chrdev_region(dev_num, 1);return ret;}printk(KERN_INFO "chr_dev: Device initialized\n");//打印设备号printk(KERN_INFO "chr_dev: Major number: %d\n", MAJOR(dev_num));printk(KERN_INFO "chr_dev: Minor number: %d\n", MINOR(dev_num));return 0;
}// 模块退出函数
static void __exit chr_dev_exit(void) {// 删除字符设备//@param dev_t dev 设备号/cdev_del(&chr_dev);// 释放设备号//@param dev_t dev 设备号 // @param unsigned int count 设备号计数unregister_chrdev_region(dev_num, 1);(KERN_INFO "chr_dev: Device removed\n");
}// 注册模块初始化函数
// 内核在加载模块时,调用模块的初始化函数
// 该函数在内核空间中执行,因此不能有进程上下文的操作
// 该函数的返回值是模块初始化成功与否的标志
module_init(chr_dev_init);// 注册模块退出函数
// 内核在卸载模块时,调用模块的退出函数
// 该函数在内核空间中执行,因此不能有进程上下文的操作
module_exit(chr_dev_exit);
以下代码加入了设备类和设备实例的创建
/*以下代码加入了设备类和设备实例的创建*/
#include <linux/module.h> // 包含模块相关的宏和函数
#include <linux/init.h> // 包含模块初始化和退出相关的宏
#include <linux/fs.h> // 包含文件系统相关的函数和结构体
#include <linux/cdev.h> // 包含字符设备相关的函数和结构体
#include <linux/uaccess.h> // 包含用户空间和内核空间数据传输的函数
#include <linux/device.h> // 包含设备类和设备实例相关的函数// 设备号
static dev_t dev_num;// 字符设备结构体
static struct cdev chr_dev;// 设备缓冲区
static char buffer[1024];// 缓冲区大小
static int buffer_size = 0;// 设备类
static struct class *chr_dev_class;// 设备实例
static struct device *chr_dev_device;// 模块许可证
MODULE_LICENSE("GPL");// 模块作者
MODULE_AUTHOR("gopher");// 模块描述
MODULE_DESCRIPTION("A simple character device driver");// 打开设备文件时的回调函数
static int chr_dev_open(struct inode *inode, struct file *file) {printk(KERN_INFO "chr_dev: Device opened\n");return 0;
}// 关闭设备文件时的回调函数
static int chr_dev_release(struct inode *inode, struct file *file) {printk(KERN_INFO "chr_dev: Device closed\n");return 0;
}// 从设备读取数据时的回调函数
static ssize_t chr_dev_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) {int ret;if (*ppos >= buffer_size)return 0;ret = copy_to_user(user_buf, buffer + *ppos, count);if (ret)return -EFAULT;printk(KERN_INFO "chr_dev: Read %zu bytes from device\n", count);*ppos += count;return count;
}// 向设备写入数据时的回调函数
static ssize_t chr_dev_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) {int ret;if (count > sizeof(buffer) - buffer_size)return -ENOSPC;ret = copy_from_user(buffer + buffer_size, user_buf, count);if (ret)return -EFAULT;printk(KERN_INFO "chr_dev: Wrote %zu bytes to device\n", count);buffer_size += count;return count;
}// 文件操作结构体
static struct file_operations chr_dev_fops = {.owner = THIS_MODULE,.open = chr_dev_open,.release = chr_dev_release,.read = chr_dev_read,.write = chr_dev_write,
};// 模块初始化函数
static int __init chr_dev_init(void) {int ret;// 分配设备号ret = alloc_chrdev_region(&dev_num, 0, 1, "chr_dev");if (ret < 0) {printk(KERN_ERR "chr_dev: Failed to allocate device number\n");return ret;}// 初始化字符设备cdev_init(&chr_dev, &chr_dev_fops);chr_dev.owner = THIS_MODULE;// 添加字符设备ret = cdev_add(&chr_dev, dev_num, 1);if (ret < 0) {printk(KERN_ERR "chr_dev: Failed to add character device\n");unregister_chrdev_region(dev_num, 1);return ret;}// 创建设备类// 用于管理设备实例// @param struct module *owner 模块所有者// @param const char *name 设备类名// @return struct class * 设备类结构体chr_dev_class = class_create(THIS_MODULE, "chr_dev_class");if (IS_ERR(chr_dev_class)) {// 出错printk(KERN_ERR "chr_dev: Failed to create device class\n");cdev_del(&chr_dev);// 删除字符设备unregister_chrdev_region(dev_num, 1);// 释放设备号return PTR_ERR(chr_dev_class);// 返回错误码}// 创建设备实例// 用于管理设备文件// @param struct class *class 设备类结构体// @param struct device *parent 父设备实例// @param dev_t dev 设备号// @param void *drvdata 设备数据// @param const char *fmt 设备名格式// @return struct device * 设备实例结构体chr_dev_device = device_create(chr_dev_class, NULL, dev_num, NULL, "chr_dev");if (IS_ERR(chr_dev_device)) {printk(KERN_ERR "chr_dev: Failed to create device\n");class_destroy(chr_dev_class);// 删除设备类cdev_del(&chr_dev);// 删除字符设备unregister_chrdev_region(dev_num, 1);// 释放设备号return PTR_ERR(chr_dev_device);// 返回错误码}printk(KERN_INFO "chr_dev: Device initialized\n");// 打印调试信息printk(KERN_INFO "chr_dev: Major number: %d\n", MAJOR(dev_num));// 打印设备号printk(KERN_INFO "chr_dev: Minor number: %d\n", MINOR(dev_num));// 打印设备号return 0;
}// 模块退出函数
static void __exit chr_dev_exit(void) {// 删除设备实例device_destroy(chr_dev_class, dev_num);// 删除设备类class_destroy(chr_dev_class);// 删除字符设备cdev_del(&chr_dev);// 释放设备号unregister_chrdev_region(dev_num, 1);printk(KERN_INFO "chr_dev: Device removed\n");
}// 注册模块初始化函数
module_init(chr_dev_init);// 注册模块退出函数
module_exit(chr_dev_exit);
相关文章:

Linux驱动开发-字符设备驱动开发
linux 驱动开发1. 驱动程序的类型2. 驱动开发流程字符设备驱动 1. 基本概念2. 字符设备驱动的基本结构 架构字符设备驱动开发中常用的 API示例以下代码加入了设备类和设备实例的创建 linux 驱动开发 1. 驱动程序的类型 在 Linux 中,驱动程序主要有以下几种类型&am…...

好用的电脑录屏软件有哪些?推荐4款专业工具。
不同系统的电脑上面带有的录屏功能不一样,比如win10上面有Xbox game bar,Mac系统则用的是QuickTime Player,或者是使用快捷键“CommandShift5”。但更方便的,我自己认为是使用一些专业的录屏软件,他门的录制模式多,兼容…...

web基础之XSS
一、搭建XSS平台 安装 1、我这里安装在本地的Phpstudy上,安装过程就是一路下一步(可以改安装路径),附上下载链接: # 官网:https://www.xp.cn/download.html# 蓝莲花 - github下载 https://github.com/fi…...

目标检测-小目标检测方法
小目标检测是计算机视觉中的一个挑战性问题,因为小目标往往在图像中占据的像素较少,容易被背景或其他物体干扰。为了有效地进行小目标检测,研究人员和工程师提出了多种方法和算法来提高检测精度。以下是一些针对小目标检测的有效方式和算法&a…...

连接数据库(以MySQL为例)
文章目录 前言一、数据库是什么?二、连接步骤 1.手动导入驱动包2.连接数据库总结 前言 面对应用程序的开发,普遍需要保存用户的海量数据。保存粮的库叫粮库,保存水的库叫水库,那么保存数据的库自然叫数据库。有了数据库࿰…...

Mysql高级教程
1.安装部署 安装依赖性: [rootmysql-node10 ~]# dnf install cmake gcc-c openssl-devel ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el7_4.x86_64.rpm rpcgen.x86_64 下载并解压源码包 [rootmysql-node10 ~]# tar zxf mysql-boost-5.7.44.tar.gz [rootmysql-no…...

基于Ubuntu2404搭建mysql8配置远程访问
使用系统为Ubuntu2404,mysql8版本为8.0.36 安装mysql apt install -y mysql-server设置开机自启动 systemctl enable --now mysql修改密码,似乎是bug,修改密码第一次不成功,第二次可以 mysql use mysql; update user set Host…...

前端工程师职业发展路线图
在前端开发领域,从一个新手成长为一名资深工程师需要经过一系列的学习和实践。以下是一份详细的前端工程师职业发展路线图,包括了从基础到高级的各个阶段。 入门阶段 1. 学习基础技术 HTML/HTML5:掌握网页结构和语义化标签的使用。CSS/CSS…...

人工智能(AI)正在以前所未有的速度融入我们生活的方方面面
人工智能将融入我们生活的方方面面 人工智能(AI)正在以前所未有的速度融入我们生活的方方面面,这种趋势在未来几年乃至几十年内将会持续加速。以下是一些人工智能已经或即将在各个领域产生深远影响的例子: 智能家居:…...

OpenCV-模板匹配多个目标
文章目录 一、基本概念二、基本步骤1.图像准备2.图像预处理3.执行模板匹配4.定位匹配区域5.处理多个匹配6.优化和验证 三、代码实现1.图片读取2.图像预处理3.模板匹配4.绘制矩形框 三、总结 模型匹配(Model Matching)是一个广泛应用的概念,其…...

uniapp 原生插件开发 UI
前言: 在集成某些特定 原生SDK的时候,它本身是带UI控件的。当我们使用 uniapp 开发app的时候实是 可以使使用 nvue 页面,以 weex 的方式嵌入原生的UI控件。 我这边的场景是 接入连连app的支付,它有个自己的密码键盘 控件是原生的页…...

性能测试-性能分析与调优原理总结
性能分析与调优如何下手,先从硬件开始,还是先从代码或数据库。 从操作系统(CPU调度,内存管理,进程调度,磁盘I/O)、网络、协议(HTTP, TCP/IP ),还是…...

【机器学习】4 ——熵
机器学习4 ——熵 文章目录 机器学习4 ——熵前言 前言 熵衡量随机变量不确定性,由克劳德香农(Claude Shannon)在1948年提出,称为香农熵。反映了一个系统中信息的混乱程度或信息量。 其定义为: H ( P ) − ∑ x P …...

linux命令用于删除文本文件中的重复行的命令uniq详解
目录 一、概述 二、基本用法 1、uniq 命令的基本语法 2、常用选项 3、获取帮助 三、主要功能 1. 识别并删除相邻重复行 2. 保留重复行的第一个实例 3. 统计重复次数 4. 忽略指定列的比较 四、示例 1. 删除相邻重复行 2. 显示每一行及其重复次数 3. 只显示重复行 4. …...

PHP智驭未来悦享生活智慧小区物业管理小程序系统源码
智驭未来,悦享生活 —— 探索智慧小区物业管理小程序 一、引言:智慧生活的新篇章 在这个日新月异的时代,科技正以前所未有的速度改变着我们的生活。从智能家居到智慧城市,每一处都闪耀着智慧的光芒。而今天,我要带大家…...

深度学习:怎么看pth文件的参数
.pth 文件是 PyTorch 模型的权重文件,它通常包含了训练好的模型的参数。要查看或使用这个文件,你可以按照以下步骤操作: 1. 确保你有模型的定义 你需要有创建这个 .pth 文件时所用的模型的代码。这意味着你需要有模型的类定义和架构。 2. …...

MMLU-Pro 基准测试数据集上线,含 12k 个跨学科复杂问题,难度提升,更具挑战性!DeepSeek 数学模型一键部署
在大语言模型 (LLM) 蓬勃发展的时代,诸如大规模多任务语言理解 (MMLU) 之类的基准测试,在推动 AI 于不同领域的语言理解与推理能力迈向极限方面,发挥着至关重要的关键作用。 然而,伴随模型的持续改进与优化,LLM 在这些…...

Vue | Vue深入浅出——Vue中的render函数详解
1.render函数 在编写vue单文件的大多数情况下,我们都是使用template模板来创建HTML。然而在一些条件判断比较复杂的场景下,使用JavaScript去描绘HTML的生成逻辑会显得更加的简洁直观。 使用Vue官网的例子来简单说明: 如果自己在开发的时候…...

数学基础 -- 线性代数之奇异值
奇异值与其应用 1. 奇异值定义 对于任意的矩阵 A A A(可以是方阵或非方阵),存在三个矩阵 U U U、 Σ \Sigma Σ 和 V V V,使得: A U Σ V T A U \Sigma V^T AUΣVT 其中: U U U 是一个 m m m \ti…...

Python爬虫使用实例-wallpaper
1/ 排雷避坑 🥝 中文乱码问题 print(requests.get(urlurl,headersheaders).text)出现中文乱码 原因分析: <meta charset"gbk" />解决方法: 法一: response requests.get(urlurl,headersheaders) response.en…...

探索Go语言中的随机数生成、矩阵运算与数独验证
1. Go中的随机数生成 在许多编程任务中,随机数的生成是不可或缺的。Go语言通过 math/rand 包提供了伪随机数生成方式。伪随机数由种子(seed)决定,如果种子相同,生成的数列也会相同。为了确保每次程序运行时产生不同的随机数,我们…...

无线安全(WiFi)
免责声明:本文仅做分享!!! 目录 WEP简介 WPA简介 安全类型 密钥交换 PMK PTK 4次握手 WPA攻击原理 网卡选购 攻击姿态 1-暴力破解 脚本工具 字典 2-Airgeddon 破解 3-KRACK漏洞 4-Rough AP 攻击 5-wifi钓鱼 6-wifite 其他 WEP简介 WEP是WiredEquivalentPri…...

牛客练习赛128:Cidoai的平均数对(背包dp)
题目描述 给定 nnn 对数 (ai,bi)(a_i,b_i)(ai,bi) 和参数 kkk,你需要选出一些对使得在满足 bib_ibi 的平均值不超过 kkk 的同时,aia_iai 的和最大,求出这个最大值。 输入描述: 第一行两个整数分别表示 n,kn,kn,k。 接下来 nnn 行&…...

Python世界:简易地址簿增删查改算法实践
Python世界:简易地址簿增删查改算法实践 任务背景编码思路代码实现本文小结 任务背景 该任务来自简明Python教程中迈出下一步一章的问题: 编写一款你自己的命令行地址簿程序, 你可以用它浏览、 添加、 编辑、 删除或搜索你的联系人ÿ…...

网络安全-intigriti-0422-XSS-Challenge Write-up
目录 一、环境 二、解题 2.1看源码 一、环境 Intigriti April Challenge 二、解题 要求:弹出域名就算成功 2.1看源码 我们看到marge方法,肯定是原型链污染题目 接的是传参,我们可控的点在于qs.config和qs.settings,这两个可…...

Debian Linux 11 使用crash
文章目录 前言一、环境安装1.1 安装debug package1.2 安装crash 二、使用crash 前言 # cat /etc/os-release PRETTY_NAME"Debian GNU/Linux 11 (bullseye)" NAME"Debian GNU/Linux" VERSION_ID"11" VERSION"11 (bullseye)" VERSION_C…...

python列表 — 按顺序找出b表中比a表多出的元素
目录 一、功能描述 二、适用场景 三、代码实现 一、功能描述 有a、b两个列表,a列表有3个元素;b列表有7个元素。b列表多出的一个元素可能在随机的位置,在不影响其他元素的情况下,找到b列表多出的那四个元素,并按照在…...

如何使用Python创建目录或文件路径列表
在 Python 中,创建目录或生成文件路径列表通常涉及使用 os、os.path 或 pathlib 模块。下面是一些常见的任务和方法,用于在 Python 中创建目录或获取文件路径列表。 问题背景 在初始阶段的 Python 学习过程中,可能遇到这样的问题:…...

领夹麦克风哪个品牌好,哪种领夹麦性价比高,无线麦克风推荐
在音频录制需求日益多样化的今天,无线领夹麦克风作为提升音质的关键设备,其重要性不言而喻。市场上鱼龙混杂,假冒伪劣、以次充好的现象屡见不鲜。这些产品往往以低价吸引消费者,却在音质、稳定性、耐用性等方面大打折扣࿰…...

苍穹外卖学习笔记(五)
文章目录 二.新增菜品1.图片上传2.具体新增菜品 二.新增菜品 1.图片上传 这里采用了阿里云oss对象存储服务 application.yml alioss:endpoint: ${sky.alioss.endpoint}access-key-id: ${sky.alioss.access-key-id}access-key-secret: ${sky.alioss.access-key-secret}bucket…...