Linux驱动编程 - seq_open、single_open使用方法

news2025/3/25 12:07:24

目录

 前言:

一、seq_xxx

1、seq_xxx 函数介绍

1.1 seq_open

1.2 seq_read

1.3 seq_lseek

1.4 seq_release

1.5 格式化输出函数

2、seq_open 实例

二、single_xxx 函数

1、single_xxx 函数介绍

1.1 single_open

1.2 single_start

1.3 single_next

1.4 single_stop

1.5 single_release

2、single_open 实例

三、更精简的方法 DEFINE_SHOW_ATTRIBUTE


 前言:


        内核态和用户态数据交互有很多方法,比如驱动中的 copy_to_user、copy_from_user。再比如驱动中添加属性文件,cat、echo调用节点属性文件的xx_show函数或xx_store函数。

        本文介绍 seq_file 的用法,为了更简单和方便,内核提供了single_xxx系列接口,它是对seq_file的进一步封装。

        相比较于之前的方法其优势可以向应用层导出比较多的数据,例如大于1个PAGE_SIZE,同时驱动文件中我们不用关注复杂的缓冲区管理,这些内核自己处理,属于比较成熟的内核接口。

        seq_file机制提供了一种标准化的例程,使得顺序文件的处理变得简单高效。顺序文件通常用于遍历一些数据项并创建文件内容,其访问模式是逐个访问读取数据项。seq_file机制通过struct seq_operations结构定义了一系列操作函数,包括开始、停止、显示和获取下一个操作,从而简化了文件处理过程‌

测试示例依赖debugfs,内核配置打开debugfs:

CONFIG_DEBUG_FS=y

如果/sys/kernel/debug是空的,执行以下命令挂载debugfs文件系统:

$ mount -t debugfs none /sys/kernel/debug

一、seq_xxx


seq_file只是在普通的文件read中加入了内核缓冲的功能,从而实现顺序多次遍历,读取大数据量的简单接口。

/* 路径:include/linux/seq_file.h */
struct seq_file {
	char *buf;			//在seq_open中分配,大小为4KB
	size_t size;		//4096
	size_t from;		//struct file从seq_file中向用户态缓冲区拷贝时相对于buf的偏移地址
	size_t count;		//可以拷贝到用户态的字符数目
	size_t pad_until;
	loff_t index;		//从内核态向seq_file的内核态缓冲区buf中拷贝时start、next的处理的下标pos数值,即用户自定义遍历iter
	loff_t read_pos;	//当前已拷贝到用户态的数据量大小,即struct file中拷贝到用户态的数据量
	u64 version;
	struct mutex lock;
	const struct seq_operations *op;	//操作集,包含seq_start,seq_next,set_show,seq_stop函数
	int poll_event;
	const struct file *file;
	void *private;
};

struct seq_operations {
	void * (*start) (struct seq_file *m, loff_t *pos);
	void (*stop) (struct seq_file *m, void *v);
	void * (*next) (struct seq_file *m, void *v, loff_t *pos);
	int (*show) (struct seq_file *m, void *v);
};
  • start:用于指定seq_file文件的读开始位置,返回实际读开始位置,如果指定的位置超过文件末尾,应当返回NULL;
  • stop:用于在读完seq_file文件后调用,它类似于文件操作close,用于做一些必要的清理,如释放内存等;
  • next:用于把seq_file文件的当前读位置移动到下一个读位置,返回实际的下一个读位置,如果已经到达文件末尾,返回NULL;
  • show:用于格式化输出,如果成功返回0,否则返回出错码;

1、seq_xxx 函数介绍


内核自带函数 seq_open、seq_read、seq_lseek、seq_release等函数

1.1 seq_open

功能:用于把struct seq_operations结构与seq_file文件关联起来

/*
参数:
    *file:指向要操作的文件指针
    *op:指向一个seq_operations结构体,包含start、show等
返回值:0:成功, 非0:失败
*/
int seq_open(struct file *file, const struct seq_operations *op)
{
	struct seq_file *p;

	WARN_ON(file->private_data);

	p = kmem_cache_zalloc(seq_file_cache, GFP_KERNEL);
	if (!p)
		return -ENOMEM;

	file->private_data = p;

	mutex_init(&p->lock);
	p->op = op;

	// No refcounting: the lifetime of 'p' is constrained
	// to the lifetime of the file.
	p->file = file;

	/*
	 * Wrappers around seq_open(e.g. swaps_open) need to be
	 * aware of this. If they set f_version themselves, they
	 * should call seq_open first and then set f_version.
	 */
	file->f_version = 0;

	/*
	 * seq_files support lseek() and pread().  They do not implement
	 * write() at all, but we clear FMODE_PWRITE here for historical
	 * reasons.
	 *
	 * If a client of seq_files a) implements file.write() and b) wishes to
	 * support pwrite() then that client will need to implement its own
	 * file.open() which calls seq_open() and then sets FMODE_PWRITE.
	 */
	file->f_mode &= ~FMODE_PWRITE;
	return 0;
}

1.2 seq_read

功能:用于从内核缓冲区中读取数据并将其输出到用户空间

/*
参数:
    *file:指向要操作的文件指针
    *buf:用户空间的缓冲区地址,用于存放读取的数据
    size:用户请求读取的字节数
    *ppos:文件描述符的当前位置,指示读取的起始位置
返回值:读取的字节数,失败返回负数错误码
*/
ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	struct seq_file *m = file->private_data;
	size_t copied = 0;
	size_t n;
	void *p;
	int err = 0;

	mutex_lock(&m->lock);

	/*
	 * seq_file->op->..m_start/m_stop/m_next may do special actions
	 * or optimisations based on the file->f_version, so we want to
	 * pass the file->f_version to those methods.
	 *
	 * seq_file->version is just copy of f_version, and seq_file
	 * methods can treat it simply as file version.
	 * It is copied in first and copied out after all operations.
	 * It is convenient to have it as  part of structure to avoid the
	 * need of passing another argument to all the seq_file methods.
	 */
	m->version = file->f_version;

	/*
	 * if request is to read from zero offset, reset iterator to first
	 * record as it might have been already advanced by previous requests
	 */
	if (*ppos == 0) {
		m->index = 0;
		m->version = 0;
		m->count = 0;
	}

	/* Don't assume *ppos is where we left it */
	if (unlikely(*ppos != m->read_pos)) {
		while ((err = traverse(m, *ppos)) == -EAGAIN)
			;
		if (err) {
			/* With prejudice... */
			m->read_pos = 0;
			m->version = 0;
			m->index = 0;
			m->count = 0;
			goto Done;
		} else {
			m->read_pos = *ppos;
		}
	}

	/* grab buffer if we didn't have one */
	if (!m->buf) {
		m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
		if (!m->buf)
			goto Enomem;
	}
	/* if not empty - flush it first */
	if (m->count) {
		n = min(m->count, size);
		err = copy_to_user(buf, m->buf + m->from, n);
		if (err)
			goto Efault;
		m->count -= n;
		m->from += n;
		size -= n;
		buf += n;
		copied += n;
		if (!size)
			goto Done;
	}
	/* we need at least one record in buffer */
	m->from = 0;
	p = m->op->start(m, &m->index);
	while (1) {
		err = PTR_ERR(p);
		if (!p || IS_ERR(p))
			break;
		err = m->op->show(m, p);
		if (err < 0)
			break;
		if (unlikely(err))
			m->count = 0;
		if (unlikely(!m->count)) {
			p = m->op->next(m, p, &m->index);
			continue;
		}
		if (m->count < m->size)
			goto Fill;
		m->op->stop(m, p);
		kvfree(m->buf);
		m->count = 0;
		m->buf = seq_buf_alloc(m->size <<= 1);
		if (!m->buf)
			goto Enomem;
		m->version = 0;
		p = m->op->start(m, &m->index);
	}
	m->op->stop(m, p);
	m->count = 0;
	goto Done;
Fill:
	/* they want more? let's try to get some more */
	while (1) {
		size_t offs = m->count;
		loff_t pos = m->index;

		p = m->op->next(m, p, &m->index);
		if (pos == m->index)
			/* Buggy ->next function */
			m->index++;
		if (!p || IS_ERR(p)) {
			err = PTR_ERR(p);
			break;
		}
		if (m->count >= size)
			break;
		err = m->op->show(m, p);
		if (seq_has_overflowed(m) || err) {
			m->count = offs;
			if (likely(err <= 0))
				break;
		}
	}
	m->op->stop(m, p);
	n = min(m->count, size);
	err = copy_to_user(buf, m->buf, n);
	if (err)
		goto Efault;
	copied += n;
	m->count -= n;
	m->from = n;
Done:
	if (!copied)
		copied = err;
	else {
		*ppos += copied;
		m->read_pos += copied;
	}
	file->f_version = m->version;
	mutex_unlock(&m->lock);
	return copied;
Enomem:
	err = -ENOMEM;
	goto Done;
Efault:
	err = -EFAULT;
	goto Done;
}

1.3 seq_lseek

功能:重新定位文件内的读/写文件偏移量

/*
参数:
    *file:指向要操作的文件指针
    offset:偏移量,表示从文件开头向后移动的字节数
    whence:起始位置,可以是SEEK_SET(文件开头)、SEEK_CUR(当前位置)或SEEK_END(文件末尾)
返回值:文件位置,失败返回-1
*/
loff_t seq_lseek(struct file *file, loff_t offset, int whence)
{
	struct seq_file *m = file->private_data;
	loff_t retval = -EINVAL;

	mutex_lock(&m->lock);
	m->version = file->f_version;
	switch (whence) {
	case SEEK_CUR:
		offset += file->f_pos;
		/* fall through */
	case SEEK_SET:
		if (offset < 0)
			break;
		retval = offset;
		if (offset != m->read_pos) {
			while ((retval = traverse(m, offset)) == -EAGAIN)
				;
			if (retval) {
				/* with extreme prejudice... */
				file->f_pos = 0;
				m->read_pos = 0;
				m->version = 0;
				m->index = 0;
				m->count = 0;
			} else {
				m->read_pos = offset;
				retval = file->f_pos = offset;
			}
		} else {
			file->f_pos = offset;
		}
	}
	file->f_version = m->version;
	mutex_unlock(&m->lock);
	return retval;
}

1.4 seq_release

功能:释放seq_file结构体资源

int seq_release(struct inode *inode, struct file *file)
{
	struct seq_file *m = file->private_data;
	kvfree(m->buf);
	kmem_cache_free(seq_file_cache, m);
	return 0;
}

1.5 格式化输出函数

/*函数seq_putc用于把一个字符输出到seq_file文件*/
int seq_putc(struct seq_file *m, char c);
/*函数seq_puts则用于把一个字符串输出到seq_file文件*/
int seq_puts(struct seq_file *m, const char *s);
/*函数seq_escape类似于seq_puts,只是,它将把第一个字符串参数中出现的包含在第二个字符串参数中的字符按照八进制形式输出,也即对这些字符进行转义处理*/
int seq_escape(struct seq_file *, const char *, const char *);
/*函数seq_printf是最常用的输出函数,它用于把给定参数按照给定的格式输出到seq_file文件*/
int seq_printf(struct seq_file *, const char *, ...)__attribute__ ((format(printf,2,3)));
/*函数seq_path则用于输出文件名,字符串参数提供需要转义的文件名字符,它主要供文件系统使用*/
int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *);

2、seq_open 实例


#include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>

static void *my_seq_start(struct seq_file *p, loff_t *pos)
{
    if (*pos >= 1)
        return NULL;
    return 1;
}

static void *my_seq_next(struct seq_file *p, void *v, loff_t *pos)
{
    ++(*pos);
    return NULL;
}

static void my_seq_stop(struct seq_file *p, void *v)
{
    return;
}

static int my_seq_show(struct seq_file *p, void *v)
{
    seq_printf(p, "hello word\n");
    return 0;
}

static const struct seq_operations my_seq_ops= {
    .start = my_seq_start,
    .next  = my_seq_next,
    .stop  = my_seq_stop,
    .show  = my_seq_show,
};

static int my_seq_open(struct inode *inode, struct file *file)
{
    return seq_open(file, &my_seq_ops);	//内核自带的 seq_open 设置 seq_operations
}

static const struct file_operations my_debug_fops = {
    .owner = THIS_MODULE,
    .open = my_seq_open,
    .read = seq_read,		//内核自带的 seq_read
    .llseek = seq_lseek,	//内核自带的 seq_lseek
    .release = seq_release,	//内核自带的 seq_release
};

static struct dentry *seq_file_demo_dir = NULL;
int demo_seq_init(void)
{
    /* 生成 /sys/kernel/debug/demo_seq 文件 */
    seq_file_demo_dir = debugfs_create_file("demo_seq", 0444, NULL,
                NULL, &my_debug_fops);
    return 0;
}

static void __exit demo_seq_exit(void)
{
	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    if (seq_file_demo_dir)
            debugfs_remove(seq_file_demo_dir);
}

module_init(demo_seq_init);
module_exit(demo_seq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dongao");

运行结果:

$ insmod ./demo_seq_driver.ko 
$ cat /sys/kernel/debug/demo_seq 
hello word

也可以应用程序 open 打开 /sys/kernel/debug/demo_seq ,然后read,如下:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
 
int main(int argc, char *argv[])
{
	int fd = -1;
	int ret = -1;
	char buf[1024] = {0};
	
	fd = open("/sys/kernel/debug/demo_seq", O_RDONLY);
	if(fd < 0){
		printf("open failed!\r\n");
		return -1;
	}
	
	lseek(fd, 0, SEEK_SET);
	ret = read(fd, buf, sizeof(buf) - 1);
	if(ret < 0){
		printf("read Failed!\r\n");
		close(fd);
		return -1;
	}

	printf("%s", buf);		//打印输出 "hello word"
	
	ret = close(fd); /* 关闭文件 */
	if(ret < 0){
		printf("file %s close failed!\r\n", argv[1]);
		return -1;
	}
	
	return 0;
}

二、single_xxx 函数


相比于seq_open()函数,内核还提供了一个更加精简的single_open()函数,只需要实现xx_show函数就行。

1、single_xxx 函数介绍

1.1 single_open

single_start、single_next、single_stop是内核提供的函数。single_open中实现了设置struct seq_operations,并调用了 seq_open。

/* fs/seq_file.c */
int single_open(struct file *file, int (*show)(struct seq_file *, void *),
        void *data)
{
    struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL_ACCOUNT);
    int res = -ENOMEM;

    if (op) {
        op->start = single_start;
        op->next = single_next;
        op->stop = single_stop;
        op->show = show;
        res = seq_open(file, op);
        if (!res)
            ((struct seq_file *)file->private_data)->private = data;
        else
            kfree(op);
    }
    return res;
}

1.2 single_start

static void *single_start(struct seq_file *p, loff_t *pos)
{
	return NULL + (*pos == 0);
}

1.3 single_next

static void *single_next(struct seq_file *p, void *v, loff_t *pos)
{
	++*pos;
	return NULL;
}

1.4 single_stop

static void single_stop(struct seq_file *p, void *v)
{
}

1.5 single_release

int single_release(struct inode *inode, struct file *file)
{
	const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
	int res = seq_release(inode, file);
	kfree(op);
	return res;
}

2、single_open 实例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>

static int my_seq_show(struct seq_file *m, void *v)
{
    seq_printf(m, "test single_open\n");
    return 0;
}

static int my_seq_open(struct inode *inode, struct file *file)
{
    return single_open(file, &my_seq_show, NULL);		//设置 xxx_show
}

static const struct file_operations my_debug_fops = {
    .owner = THIS_MODULE,
    .open = my_seq_open,
    .read = seq_read,		//内核自带的 seq_read
    .llseek = seq_lseek,	//内核自带的 seq_lseek
    .release = seq_release,	//内核自带的 seq_release
};

static struct dentry *seq_file_demo_dir = NULL;
int demo_seq_init(void)
{
    /* 生成 /sys/kernel/debug/demo_seq 文件 */
    seq_file_demo_dir = debugfs_create_file("demo_seq", 0444, NULL,
                NULL, &my_debug_fops);
    return 0;
}

static void __exit demo_seq_exit(void)
{
	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    if (seq_file_demo_dir)
            debugfs_remove(seq_file_demo_dir);
}

module_init(demo_seq_init);
module_exit(demo_seq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dongao");

生成 /sys/kernel/debug/demo_seq 文件,测试方法同上。

三、更精简的方法 DEFINE_SHOW_ATTRIBUTE


#define DEFINE_SHOW_ATTRIBUTE(__name)                   \
static int __name ## _open(struct inode *inode, struct file *file)  \
{                                   \
    return single_open(file, __name ## _show, inode->i_private);    \
}                                   \
                                    \
static const struct file_operations __name ## _fops = {         \
    .owner      = THIS_MODULE,                  \
    .open       = __name ## _open,              \
    .read       = seq_read,                 \
    .llseek     = seq_lseek,                    \
    .release    = single_release,               \
}

实例如下

#include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>

static struct dentry *seq_file_demo_dir;

static int my_seq_show(struct seq_file *seq, void *v)
{
        seq_printf(seq, "Hello World\n");
        return 0;
}
DEFINE_SHOW_ATTRIBUTE(my_seq);

static int __init demo_seq_init(void)
{
        /* 生成 /sys/kernel/debug/demo_seq 文件 */
        seq_file_demo_dir = debugfs_create_file("demo_seq", 0444, NULL,
                NULL, &my_seq_fops);
        return 0;
}

static void __exit demo_seq_exit(void)
{
        if (seq_file_demo_dir)
                debugfs_remove(seq_file_demo_dir);
}

module_init(demo_seq_init);
module_exit(demo_seq_exit);
MODULE_LICENSE("GPL");

测试方法同上,不再赘述。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2320670.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

N列股票收盘价为起点的马科维茨(Markowitz)均值—方差理论

1. 数据准备与收益率计算 输入数据&#xff1a; 假设你有一个矩阵&#xff0c;每一列代表一只股票的历史收盘价序列。每一行对应一个时间点的收盘价。 计算收益率&#xff1a; 马科维茨理论要求使用资产的收益率而非价格。常用的收益率计算方法有对数收益率或简单收益率。 2.…

mac brew 安装的php@7.4 打开redis扩展

1. 找到php7.4的pecl目录 一般在这个位置 cd /usr/local/Cellar/php7.4/7.4.33_8/pecl/20190902 ls 一下 有个 redis.so 于是 直接去php.ini编辑了 php.ini的路径 vim /usr/local/etc/php/7.4/php.ini 把938行添加进去 然后重启一下 php7.4 brew services restart ph…

OSPF多区域通信

作业要求: 1、多区域0SPF area 0、area10、are20 2、AR5、AR6作为stub区&#xff0c;使用环回接口与Pc1进行通信 第一步&#xff1a;为各端口配置IP地址 AR1: <Huawei>sys [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 5.5.5.1 24 [Huawei-GigabitEther…

三、重学C++—C语言内存管理

上一章节&#xff1a; 二、重学C—C语言核心-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146191640?spm1001.2014.3001.5502 本章节代码&#xff1a; cPart2 CuiQingCheng/cppstudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/cppstudy/tree/…

算法题(105):小猫爬山

审题&#xff1a; 本题需要我们找出将n个小猫放在有限重的缆车上运下山所需的最小缆车数 时间复杂度分析&#xff1a;本题的数据量小于等于18&#xff0c;所以我们在做好剪枝的前提下可以使用深度优先搜索解题 思路&#xff1a; 方法一&#xff1a;dfs 搜索策略&#xff1a;将小…

线程的pthread_create、pthread_join、pthread_exit、pthread_detach函数

线程的创建&#xff08;pthread_create&#xff09; pthread_t tid;//本质是unsigned long类型&#xff0c;打印时得到的是该线程的虚拟地址int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void*), void *arg ); pthread_t *thre…

测试专项4:AI算法测试在测试行业中,该如何定位自己自述

这岗位到底干啥的&#xff1f; 打个比方&#xff1a; 你就像AI模型的“质检员产品经理风险顾问”三合一。 质检员&#xff1a; 别人造了个AI模型&#xff08;比如人脸识别系统&#xff09;&#xff0c;你不能光看它实验室成绩好&#xff0c;得把它丢到现实里折腾&#xff1a;…

【C语言系列】数据在内存中存储

数据在内存中存储 一、整数在内存中的存储二、大小端字节序和字节序判断2.1什么是大小端&#xff1f;2.2练习2.2.1练习12.2.2练习22.2.3练习32.2.4练习42.2.5练习52.2.6练习6 三、浮点数在内存中的存储3.1练习3.2浮点数的存储3.2.1 浮点数存的过程3.2.2 浮点数取的过程 3.3题目…

【中文翻译】第12章-The Algorithmic Foundations of Differential Privacy

由于GitHub项目仅翻译到前5章&#xff0c;我们从第6章开始通过大语言模型翻译&#xff0c;并导出markdown格式。 大模型难免存在错漏&#xff0c;请读者指正。 教材原文地址&#xff1a;https://www.cis.upenn.edu/~aaroth/Papers/privacybook.pdf 12 其他模型 到目前为止&…

图解模糊推理过程(超详细步骤)

我们前面已经讨论了三角形、梯形、高斯型、S型、Z型、Π型6种隶属函数&#xff0c;下一步进入模糊推理阶段。 有关六种隶属函数的特点在“Pi型隶属函数&#xff08;Π-shaped Membership Function&#xff09;的详细介绍及python示例”都有详细讲解&#xff1a;https://lzm07.b…

datawhale组队学习-大语言模型-task5:主流模型架构及新型架构

目录 5.3 主流架构 5.3.1 编码器-解码器架构 5.3.2 因果解码器架构 5.3.3 前缀解码器架构 5.4 长上下文模型 5.4.1 扩展位置编码 5.4.2 调整上下文窗口 5.4.3 长文本数据 5.5 新型模型架构 5.5.1 参数化状态空间模型 5.5.2 状态空间模型变种 5.3 主流架构 在预训…

RAG 架构地基工程-Retrieval 模块的系统设计分享

目录 一、知识注入的关键前奏——RAG 系统中的检索综述 &#xff08;一&#xff09;模块定位&#xff1a;连接语言模型与知识世界的桥梁 &#xff08;二&#xff09;核心任务&#xff1a;四大关键问题的协调解法 &#xff08;三&#xff09;系统特征&#xff1a;性能、精度…

(C语言)习题练习 sizeof 和 strlen

sizeof 上习题&#xff0c;不知道大家发现与上一张的习题在哪里不一样嘛&#xff1f; int main() {char arr[] "abcdef";printf("%zd\n", sizeof(arr));printf("%zd\n", sizeof(arr 0));printf("%zd\n", sizeof(*arr));printf(&…

Unity Animation的其中一种运用方式

Animation是Unity的旧的动画系统&#xff0c;先说目的&#xff0c;其使用是为了在UI中播放动效&#xff0c;并且在动效播放结束后接自定义事件而设计的 设计的关键点在于&#xff0c;这个脚本不是通过Animation直接播放动画片段&#xff0c;而是通过修改AnimationState的nor…

框架的CVE漏洞利用 php类 java类 手工操作和自动化操作蓝队分析漏洞利用的流量特征

前言 php重要框架和基本的识别特征 php的主要是 tp框架 和 laravel 当然还有 yii等 tp的主要特征 1\报错信息&#xff1a; 2、图标 3、请求头 Laravel特征 1、报错信息 2、请求头 php框架CVE利用 lavarvel 工具 https://github.com/zhzyker/CVE-2021-3129 https://git…

【算法day19】括号生成——数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

括号生成 https://leetcode.cn/problems/generate-parentheses/description/ 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 左括号数必须大于右括号数&#xff0c;且小于等于n class Solution { publ…

Qt5.15.2实现Qt for WebAssembly与示例

目录 1.什么是Qt for WebAssembly&#xff1f; 1.1 什么是 WebAssembly&#xff1f; 1.2 WebAssembly 的优势 1.3 什么是 Qt for WebAssembly&#xff1f; 1.4 Qt for WebAssembly 的特点 1.5 编译过程 1.6 运行时环境 注意&#xff01;&#xff01;&#xff01;注意&am…

好吧好吧,看一下达梦的模式与用户的关系

单凭个人感觉&#xff0c;模式在达梦中属于逻辑对象合集&#xff0c;回头再看资料 应该是一个用户可以对应多个模式 问题来了&#xff0c;模式的ID和用户的ID一样吗&#xff1f; 不一样 SELECT USER_ID,USERNAME FROM DBA_USERS WHERE USERNAMETEST1; SELECT ID AS SCHID, NA…

HOW - DP 动态规划系列(三)(含01背包问题)

目录 一、01背包问题最直接的暴力解法动态规划解法 二、完全背包 通过几个算法的学习&#xff0c;理解和掌握动态规划来解决背包问题。 一、01背包问题 对于面试的话&#xff0c;掌握01背包和完全背包就够用了&#xff0c;最多可以再来一个多重背包。 如果这几种背包分不清&…

在linux服务器部署Heygem

前言&#xff1a; Heygem官方文档上提供了基于windwos系统的安装方案。在实际使用过程中个人电脑的配置可能不够。这个时候如果服务器配置够的话&#xff0c;可以尝试在服务器上装一下。但是服务器一般都是linux系统的&#xff0c;于是这篇教程就出现了… 可行性分析 通读安装…