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

linux驱动(二):led补

        本文主要探讨s5pv210的led驱动相关知识,包括驱动主次设备注册和取消,udev(mdev)机制,静态和动态映射操作寄存器。

字符设备驱动注册
        
老接口(register_chrdev)

static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
{return __register_chrdev(major, 0, 256, name, fops);
}

        新接口(register_chrdev_region/alloc_chrdev_region)

int register_chrdev_region(dev_t from, unsigned count, const char *name)
{struct char_device_struct *cd;dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;cd = __register_chrdev_region(MAJOR(n), MINOR(n),next - n, name);if (IS_ERR(cd))goto fail;}return 0;
fail:to = n;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}return PTR_ERR(cd);
}

        指定主次设备号(/proc/devices查看未使用驱动号)
        form:起始设备号(static dev_t dev;)
        count:次设备号数量
        name:驱动名字

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
{struct char_device_struct *cd;cd = __register_chrdev_region(0, baseminor, count, name);if (IS_ERR(cd))return PTR_ERR(cd);*dev = MKDEV(cd->major, cd->baseminor);return 0;
}

        内核分配主次设备号(从254开始查找未使用驱动号)
        dev:内核分配的主次设备号(static dev_t dev;)
        baseminor:次设备号起始号
        count:次设备号个数
        name:驱动名字

static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,int minorct, const char *name)
{struct char_device_struct *cd, **cp;int ret = 0;int i;cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);if (cd == NULL)return ERR_PTR(-ENOMEM);mutex_lock(&chrdevs_lock);/* temporary */if (major == 0) {for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {if (chrdevs[i] == NULL)break;}if (i == 0) {ret = -EBUSY;goto out;}major = i;ret = major;}cd->major = major;cd->baseminor = baseminor;cd->minorct = minorct;strlcpy(cd->name, name, sizeof(cd->name));i = major_to_index(major);for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)if ((*cp)->major > major ||((*cp)->major == major &&(((*cp)->baseminor >= baseminor) ||((*cp)->baseminor + (*cp)->minorct > baseminor))))break;/* Check for overlapping minor ranges.  */if (*cp && (*cp)->major == major) {int old_min = (*cp)->baseminor;int old_max = (*cp)->baseminor + (*cp)->minorct - 1;int new_min = baseminor;int new_max = baseminor + minorct - 1;/* New driver overlaps from the left.  */if (new_max >= old_min && new_max <= old_max) {ret = -EBUSY;goto out;}/* New driver overlaps from the right.  */if (new_min <= old_max && new_min >= old_min) {ret = -EBUSY;goto out;}}cd->next = *cp;*cp = cd;mutex_unlock(&chrdevs_lock);return cd;
out:mutex_unlock(&chrdevs_lock);kfree(cd);return ERR_PTR(ret);
}

        注册都是用该函数,判断major为0则自动分配设备号,且从254依次递减查找未使用的号码

void unregister_chrdev_region(dev_t from, unsigned count)
{dev_t to = from + count;dev_t n, next;for (n = from; n < to; n = next) {next = MKDEV(MAJOR(n)+1, 0);if (next > to)next = to;kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));}
}

        注销驱动
        form:驱动号
        count:驱动个数

cdev结构体(字符设备描述,cdev.h)

struct cdev {struct kobject kobj; /* 内嵌的 kobject 对象 */struct module *owner; /*所属模块*/  const struct file_operations *ops; /*文件操作结构体*/struct list_head list; /*内核链表*/dev_t dev;/*设备号*/unsigned int count;/*设备个数*/
};

        主设备号MAJOR(dev_t dev) 
        次设备号MINOR(dev_t dev) 
        生成设备号MKDEV(int major, int minor)
        cdev中dev_t dev定义设备号(高12位为主设备号,低20 位为次设备号)
        MAJOR和MINOR根据已实例化的cdev中的dev_t dev获得主次设备号
        MKDEV实例化cdev中的dev_t dev设备号

cdev结构体操作函数
 

struct cdev *cdev_alloc(void)
{struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);if (p) {INIT_LIST_HEAD(&p->list);kobject_init(&p->kobj, &ktype_cdev_dynamic);}return p;
}


        动态申请cdev内存
 

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{memset(cdev, 0, sizeof *cdev);INIT_LIST_HEAD(&cdev->list);kobject_init(&cdev->kobj, &ktype_cdev_default);cdev->ops = fops;
}   


        初始化cdev中的file_operation

 int cdev_add(struct cdev *p, dev_t dev, unsigned count)  

         注册设备,通常发生在驱动模块的加载函数中

void cdev_put(struct cdev *p);

          释放动态申请cdev内存

void cdev_del(struct cdev *p);

        注销设备

        驱动注册和取消流程:register_chrdev_region/alloc_chrdev_region + cdev_alloc + cdev_init + cdev_add + cdev_put + cdev_del + unregister_chrdev_region

udev(mdev)
        
udev是应用程序,驱动注册和注销信息传给udev,udev在应用层进行设备文件创建和删除
        自动创建/sys/class/设备类/设备目录
        /etc/init.d/rcS有关于udev的配置

echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

        mdev -s:系统启动时扫描/sys/class和/sys/block查找dev文件
        ex:/sys/class/tty/tty0/dev内容为4:0,即主设备号是4,次设备号是0,dev上级目录为设备名(tty0),/sys/class/下每个文件夹代表一个子系统
echo /sbin/mdev > /proc/sys/kernel/hotplug:有热插拔时内核调用/proc/sys/kernel/hotplug文件里指定应用程序来处理        

        创建驱动类

#define class_create(owner, name)        \
({                        \static struct lock_class_key __key;    \__class_create(owner, name, &__key);    \
})struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key)
{struct class *cls;int retval;cls = kzalloc(sizeof(*cls), GFP_KERNEL);if (!cls) {retval = -ENOMEM;goto error;}cls->name = name;cls->owner = owner;cls->class_release = class_create_release;retval = __class_register(cls, key);if (retval)goto error;return cls;error:kfree(cls);return ERR_PTR(retval);
}

        owner:THIS_MODULE(通常)
        name:类名
        返回值class类指针        

        驱动类注销

void class_destroy(struct class *cls)
{if ((cls == NULL) || (IS_ERR(cls)))return;class_unregister(cls);
}

        cls:创建的驱动类

        

        创建设备

struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
{va_list vargs;struct device *dev;va_start(vargs, fmt);dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);va_end(vargs);return dev;
}

        class:类设备
        parent:父设备,一般为NULL
        devt:设备号
        drvdata:设备数据
        fmt:设备名字


        注销设备

void device_destroy(struct class *class, dev_t devt)
{struct device *dev;dev = class_find_device(class, NULL, &devt, __match_devt);if (dev) {put_device(dev);device_unregister(dev);}
}

        class:类设备
        devt:设备号

       
        udev机制流程:kernel(class_create,class_destroy,device_create,device_destroy)-->udev(mdev,应用层)-->/sys/class/设备类/设备 

         函数嵌套:class_create -->__class_create-->__class_register-->kset_register-->kobject_uevent
        函数嵌套:device_create-->device_create_vargs-->kobject_set_name_vargs-->device_register-->device_add-->kobject_add-->kobject_uevent                   

静态映射表建立

/* minimal IO mapping */static struct map_desc s5p_iodesc[] __initdata = {{.virtual    = (unsigned long)S5P_VA_CHIPID,.pfn        = __phys_to_pfn(S5P_PA_CHIPID),.length        = SZ_4K,.type        = MT_DEVICE,}, {.virtual    = (unsigned long)S3C_VA_SYS,.pfn        = __phys_to_pfn(S5P_PA_SYSCON),.length        = SZ_64K,.type        = MT_DEVICE,}, {.virtual    = (unsigned long)S3C_VA_UART,.pfn        = __phys_to_pfn(S3C_PA_UART),.length        = SZ_4K,.type        = MT_DEVICE,}, {.virtual    = (unsigned long)VA_VIC0,.pfn        = __phys_to_pfn(S5P_PA_VIC0),.length        = SZ_16K,.type        = MT_DEVICE,}, {.virtual    = (unsigned long)VA_VIC1,.pfn        = __phys_to_pfn(S5P_PA_VIC1),.length        = SZ_16K,.type        = MT_DEVICE,}, {.virtual    = (unsigned long)S3C_VA_TIMER,.pfn        = __phys_to_pfn(S5P_PA_TIMER),.length        = SZ_16K,.type        = MT_DEVICE,}, {.virtual    = (unsigned long)S5P_VA_GPIO,.pfn        = __phys_to_pfn(S5P_PA_GPIO),.length        = SZ_4K,.type        = MT_DEVICE,},
};

        建立映射表的三个关键:物理地址和虚拟地址相关宏定义,映射表建立函数
        映射表建立函数:smdkc110_map_io(mach-smdkc110.c)-->s5p_init_io-->iotable_init
        s5p_iodesc(cpu.c)是结构体数组数组中每个元素为一段段物理地址到虚拟地址映射,iotable_init函数将结构体数组格式表建立成MMU页表映射关系
        开机-->start_kernel-->setup_arch-->paging_init-->devicemaps_init:mdesc->map_io();
            

内核寄存器读写接口

include/asm/io.h
#define writeb(v,c)        ({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c)        ({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c)        ({ __iowmb(); writel_relaxed(v,c); })
#define writesb(p,d,l)        __raw_writesb(__mem_pci(p),d,l)
#define writesw(p,d,l)        __raw_writesw(__mem_pci(p),d,l)
#define writesl(p,d,l)        __raw_writesl(__mem_pci(p),d,l)#define readb(c)        ({ u8  __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c)        ({ u16 __v = readw_relaxed(c); __iormb(); __v; })
#define readl(c)        ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
#define readsb(p,d,l)        __raw_readsb(__mem_pci(p),d,l)
#define readsw(p,d,l)        __raw_readsw(__mem_pci(p),d,l)
#define readsl(p,d,l)        __raw_readsl(__mem_pci(p),d,l)v为值,c为地址,b为位,w为字节,l为4字节操

    demo:

        动态(静态)注册驱动

        mdev机制

        动态映射结构体方式操作寄存器

       内核寄存器读写接口   

led.c  

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>#define FILE    "/dev/led"char buf[16];
char led_cmd[3][4];void div_cmd(char *str)
{unsigned int m = 0;unsigned int n = 0;memset(led_cmd,'\0',sizeof(led_cmd));while(*str != '\0'){if(*str != ' '){led_cmd[m][n] = *str;n++;}else{led_cmd[m][n] = '\0';n = 0;m++;}str++;}
}void write_buf()
{int i;memset(buf,'\0',sizeof(buf));if(!strcmp(led_cmd[1],"on"))buf[0] = '0';if(!strcmp(led_cmd[1],"off"))buf[0] = '1';buf[1] = *(led_cmd[2]);
} int main()
{int fd = -1;char cmd[16];fd = open(FILE, O_RDWR);if (fd < 0){printf("open %s error.\n", FILE);return -1;}printf("input led cmd :led on|off 1|2|3\n");while(1){memset(cmd,'\0',sizeof(cmd));printf(">>>>");fgets(cmd,16,stdin);if(cmd[0] == '.' && cmd[1] == 'q'){break;}div_cmd(cmd);write_buf();write(fd,buf,strlen(buf));}close(fd);return 0;
}

led_dynamic_module.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
#include <linux/device.h>dev_t led_dev;
static struct cdev *led_cdev;
static struct class *led_class;
static struct device *led_device;//#define MAJOR 227 /*定义主设备号*/
#define BAEMINOR 0
#define DEV_COUNT 1
#define NAME    "led"#define GPJ0_BASE_PA 0xe0200240/*
*动态映射结构体方式操作寄存器
typedef struct GPJ0REG
{volatile unsigned int gpj0con;volatile unsigned int gpj0dat;
} gpj0_reg_t;gpj0_reg_t *pGPJ0_BASE;
*///内核io接口读写寄存器
unsigned int led_tmp;
#define S5P_GPJ0REG(x)          (x)
#define S5P_GPJ0CON                     S5P_GPJ0REG(0)
#define S5P_GPJ0DAT                     S5P_GPJ0REG(4)
static void __iomem *baseaddr;char kbuf[16];static ssize_t led_open(struct inode *inode, struct file *file)
{printk(KERN_INFO,"open led module\n");return 0;
}ssize_t led_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{int ret = -1;copy_to_user(buf,kbuf,size);if(ret){printk(KERN_ERR,"copy to user error\n");return ret;}printk(KERN_INFO,"copy to user success\n");return 0;
}static ssize_t led_write(struct file *file, const char __user *ubuf,size_t count, loff_t *ppos)
{int ret = -1;int led;memset(kbuf, 0, sizeof(kbuf));ret = copy_from_user(kbuf,ubuf,count);if(ret){printk(KERN_ERR,"copy from user fail\n");return ret;}led = kbuf[1] - '0' + 2;if (kbuf[0] == '0'){//pGPJ0_BASE->gpj0con = 0x1111111;//pGPJ0_BASE->gpj0dat &= ~(1<<led);led_tmp &= ~(1<<led);writel(led_tmp,baseaddr + S5P_GPJ0DAT);}else if (kbuf[0] == '1'){//pGPJ0_BASE->gpj0con = 0x1111111;//pGPJ0_BASE->gpj0dat |= (1<<led);led_tmp |= (1<<led);writel(led_tmp,baseaddr + S5P_GPJ0DAT);}printk(KERN_INFO,"copy from user success\n");return 0;
}static int led_close(struct inode *inode, struct file *file)
{//pGPJ0_BASE->gpj0dat = (1<<3)|(1<<4)|(1<<5);led_tmp = (1<<3)|(1<<4)|(1<<5);writel(led_tmp,baseaddr + S5P_GPJ0DAT);printk(KERN_INFO,"close led module\n");return 0;
}static const struct file_operations led_fops = {.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_close
};static int __init led_char_dev_init()
{int ret = -1;//MKDEV(MAJOR, 0);      /*定义主次设备号(dev_t led_dev)*///ret = register_chrdev_region(led_dev,DEV_COUNT,NAME);         /*指定设备号注册方式*/ret = alloc_chrdev_region(&led_dev,BAEMINOR,DEV_COUNT,NAME);if(ret < 0){printk(KERN_ERR,"register led device fail\n");goto flag_1;}led_cdev = cdev_alloc();if(led_cdev == NULL){printk(KERN_ERR,"apply cdev memory fail\n");goto flag_2;}cdev_init(led_cdev,&led_fops);//类同cdev_init//led_cdev->owner = THIS_MODULE;//led_cdev->ops = &led_fops;ret = cdev_add(led_cdev,led_dev,DEV_COUNT);if(ret){printk(KERN_ERR,"device num bind fail\n");goto flag_3;}printk(KERN_INFO,"device num bind sucess\n");led_class = class_create(THIS_MODULE,"led_class");if(IS_ERR(led_class)){printk(KERN_ERR,"led class create fail\n");goto flag_4;}printk(KERN_INFO,"led class create success\n");led_device = device_create(led_class,NULL,led_dev,NULL,"led");if(led_device == NULL){printk(KERN_ERR,"device num bind fail\n");goto flag_5;}printk(KERN_INFO,"device num bind sucess\n");if(!request_mem_region(GPJ0_BASE_PA,8,"GPJ0_BASE"))goto flag_6;//pGPJ0_BASE = ioremap(GPJ0_BASE_PA,sizeof(gpj0_reg_t));//pGPJ0_BASE->gpj0con = 0x1111111;baseaddr = ioremap(GPJ0_BASE_PA, 8);writel(0x11111111,baseaddr + S5P_GPJ0CON);led_tmp = (1<<3)|(1<<4)|(1<<5);writel(led_tmp,baseaddr + S5P_GPJ0DAT);return 0;flag_6:device_destroy(led_class,led_dev);flag_5:class_destroy(led_class);flag_4://cdev_put(led_cdev);flag_3:cdev_del(led_cdev);flag_2:unregister_chrdev_region(led_dev,DEV_COUNT);flag_1:return -EINVAL;
}static void __exit led_char_dev_exit()
{//pGPJ0_BASE->gpj0dat = (1<<3)|(1<<4)|(1<<5);//iounmap(pGPJ0_BASE);//release_mem_region(GPJ0_BASE_PA,sizeof(gpj0_reg_t));led_tmp = (1<<3)|(1<<4)|(1<<5);writel(led_tmp,baseaddr + S5P_GPJ0DAT);iounmap(baseaddr);release_mem_region(GPJ0_BASE_PA,8);device_destroy(led_class,led_dev);class_destroy(led_class);//cdev_put(led_cdev);cdev_del(led_cdev);unregister_chrdev_region(led_dev,DEV_COUNT);
}module_init(led_char_dev_init);
module_exit(led_char_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cxb");
MODULE_DESCRIPTION("led dynamic moudle");
MODULE_ALIAS("led");

Makefile

KERN_DIR = /root/kernelobj-m   += led_dynamic_module.oall:make -C $(KERN_DIR) M=`pwd` modules arm-linux-gcc led.c -o ledcp:cp *.ko /root/rootfs/drivercp led /root/rootfs/driver.PHONY: clean
clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf ./led

结果示例:

相关文章:

linux驱动(二):led补

本文主要探讨s5pv210的led驱动相关知识&#xff0c;包括驱动主次设备注册和取消&#xff0c;udev(mdev)机制&#xff0c;静态和动态映射操作寄存器。 字符设备驱动注册 老接口(register_chrdev) static inline int register_chrdev(unsigned int major, const char *n…...

性能测试-jmeter:安装 / 基础使用

一、理解jmeter 官网-Apache JMeter-Apache JMeter™ JMeter是一款开源的性能测试工具&#xff0c;主要用于模拟大量用户并发访问目标服务器&#xff0c;以评估服务器的性能和稳定性。 JMeter可以执行以下任务序号用途描述1性能测试通过模拟多个用户在同一时间对服务器进行请…...

数据仓库-数仓优化小厂实践

一、背景 由于公司规模较小&#xff0c;大数据相关没有实现平台化&#xff0c;相关的架构都是原生的Apache组件&#xff0c;所以集群的维护和优化都需要人工的参与。根据自己的实践整理一些数仓相关的优化。 二、优化 1、简易架构图 2、ODS层优化 2.1 分段式解析 随着业务增长…...

uniapp中uview组件丰富的Code 验证码输入框的使用方法

目录 基本使用 #自定义提示语 #保持倒计时 API #Props #Methods #Event 基本使用 通过ref获取组件对象&#xff0c;再执行后面的操作&#xff0c;见下方示例。 通过seconds设置需要倒计的秒数(默认60)通过ref调用组件内部的start方法&#xff0c;开始倒计时通过监听cha…...

md文件图片上传方案:Github+PicGo 搭建图床

文章目录 1. PicGo 下载2. 配置Github3. 配置PicGo4. PicGo集成Typora4.1 picGo监听端口设置 5. 测试 1. PicGo 下载 下载地址&#xff1a;https://molunerfinn.com/PicGo/ 尽量下载稳定版本 2. 配置Github 1. 创建一个新仓库&#xff0c;用于存放图片 2. 生成一个token&a…...

从零开始 - 在Python中构建和训练生成对抗网络(GAN)模型

生成对抗网络&#xff08;GANs&#xff09;是一种强大的生成模型&#xff0c;可以合成新的逼真图像。通过完整的实现过程&#xff0c;读者将对GANs在幕后的工作原理有深刻的理解。本教程首先导入必要的库并加载将用于训练GAN的Fashion-MNIST数据集。然后&#xff0c;提供了构建…...

OfficeWeb365 Indexs 任意文件读取漏洞复现

0x01 产品简介 OfficeWeb365 是专注于 Office 文档在线预览及PDF文档在线预览云服务,包括 Microsoft Word 文档在线预览、Excel 表格在线预览、Powerpoint 演示文档在线预览,WPS 文字处理、WPS 表格、WPS 演示及 Adobe PDF 文档在线预览。 0x02 漏洞概述 OfficeWeb365 /Pi…...

Crypto的简单应用-前后端加密传输

最近遇到一个数据脱敏处理的需求&#xff0c;想要用一种轻量级的技术实现&#xff0c;必须足够简单并且适用于所有场合如前后端加密传输、路由加密、数据脱敏等。抽时间研究了一下Crypto加密库的一些API&#xff0c;发现完全符合上述需求&#xff0c;扩展也比较容易。 1、前端加…...

Vue3-32-路由-重定向路由

什么是重定向 路由的重定向 &#xff1a;将匹配到的路由 【替换】 为另一个路由。 redirect : 重定向的关键字。 重定向的特点 1、重定向是路由的直接替换,路由的地址是直接改变的&#xff1b; 2、在没有子路由配置的情况下&#xff0c;重定向的路由可以省略 component 属性的配…...

如何用js动态修改字体大小

在项目中&#xff0c;我们常常会遇到使用v-html渲染文本的情况。 如果需要点击大中小三个字号按钮&#xff0c;需要修改字体的大小。那我们应该怎么做呢 function fontSize(element, type) {let size {big: 22,middle: 16,small: 12};var result element.innerHTML.replac…...

【BIG_FG_CSDN】C++ 数组与指针 (个人向——学习笔记)

一维数组 在内存占用连续存储单元的相同类型数据序列的存储。 数组是静态存储器的块&#xff1b;在编译时确定大小后才能使用&#xff1b; 其声明格式如下&#xff1a; 元素类型 数组名[常量]&#xff1b;元素类型&#xff1a;数组中元素的数据类型&#xff1b; 常量&#…...

桌面天气预报软件 Weather Widget free mac特点介绍

Weather Widget free for Mac多种吸引人的小部件设计可供选择&#xff0c;可以随时了解天气&#xff01;还可以在Dock和菜单栏中为您提供简短的天气预报或当前状况的概述。 Weather Widget free for Mac软件介绍 始终在桌面上使用时尚的天气小部件来随时了解天气&#xff01;多…...

HarmonyOS应用开发-搭建开发环境

本文介绍如何搭建 HarmonyOS 应用的开发环境&#xff0c;介绍下载安装 DevEco Studio 开发工具和 SDK 的详细流程。华为鸿蒙 DevEco Studio 是面向全场景的一站式集成开发环境&#xff0c;面向全场景多设备&#xff0c;提供一站式的分布式应用开发平台&#xff0c;支持分布式多…...

<JavaEE> TCP 的通信机制(五) -- 延时应答、捎带应答、面向字节流

目录 TCP的通信机制的核心特性 七、延时应答 1&#xff09;什么是延时应答&#xff1f; 2&#xff09;延时应答的作用 八、捎带应答 1&#xff09;什么是捎带应答&#xff1f; 2&#xff09;捎带应答的作用 九、面向字节流 1&#xff09;沾包问题 2&#xff09;“沾包…...

电脑怎么设置代理IP上网?如何隐藏自己电脑的真实IP?

在现代互联网中&#xff0c;代理IP已成为许多用户保护隐私和上网安全的重要手段。通过设置代理IP&#xff0c;用户可以隐藏自己的真实IP地址&#xff0c;提高上网的安全性&#xff0c;同时保护个人信息不被泄露。本文将详细介绍如何设置代理IP上网以及如何隐藏电脑的真实IP地址…...

Django信号机制源码分析(观察者模式)

Django信号的实现原理本质是设计模式中的观察者模式&#xff0c;浅谈Python设计模式 -- 观察者模式&#xff0c;也可以叫做发布-订阅模式&#xff0c;信号对象维护一个订阅者列表&#xff0c;当信号被触发时&#xff0c;它会遍历订阅者&#xff0c;依次通知它们。 先来回顾一下…...

MyBatis-config.xml配置文件

1、基本介绍&#xff1a; mybatis的核心配置文件(mybatis-config.xml)&#xff0c;比如配置jdbc连接信息&#xff0c;注册mapper等等&#xff0c;我们需要对这个配置文件有详细的了解。 官网地址有详细介绍 mybatis – MyBatis 3 | 配置 2、properties属性 在通常的情况下&am…...

【Spring实战】17 REST服务介绍

文章目录 1. 为什么出现2. 拥有哪些优势3. Spring中的应用4. spring-boot-starter-data-rest总结 REST&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;通常用于设计网络应用程序的服务接口。RESTful 服务是基于 REST 原则构建的网络服…...

java struts2教务管理系统Myeclipse开发mysql数据库struts2结构java编程计算机网页项目

一、源码特点 java struts2 教务管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助 struts2 框架开发&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库…...

跟着cherno手搓游戏引擎【3】事件系统和预编译头文件

不多说了直接上代码&#xff0c;课程中的架构讲的比较宽泛&#xff0c;而且有些方法写完之后并未测试。所以先把代码写完。理解其原理&#xff0c;未来使用时候会再此完善此博客。 文件架构&#xff1a; Event.h:核心基类 #pragma once #include"../Core.h" #inclu…...

排序算法之快速排序

快速排序是一种高效的排序算法&#xff0c;它的基本思想是采用分治策略&#xff0c;将一个无序数组分割成两个子数组&#xff0c;分别对子数组进行排序&#xff0c;然后将两个排序好的子数组合并成一个有序数组。快速排序的性能优于归并排序&#xff0c;尤其在处理大规模数据时…...

Docker 从入门到实践:Docker介绍

前言 在当今的软件开发和部署领域&#xff0c;Docker已经成为了一个不可或缺的工具。Docker以其轻量级、可移植性和标准化等特点&#xff0c;使得应用程序的部署和管理变得前所未有的简单。无论您是一名开发者、系统管理员&#xff0c;还是IT架构师&#xff0c;理解并掌握Dock…...

用IDEA创建/同步到gitee(码云)远程仓库(保姆级详细)

前言&#xff1a; 笔者最近在学习java&#xff0c;最开始在用很笨的方法&#xff1a;先克隆远程仓库到本地&#xff0c;再把自己练习的代码从本地仓库上传到远程仓库&#xff0c;很是繁琐。后发现可以IDEA只需要做些操作可以直接把代码上传到远程仓库&#xff0c;也在网上搜了些…...

【Linux】进程控制深度了解

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握Linux下的进程控制 > 毒鸡汤&#xff…...

kbdnso.dll文件缺失,软件或游戏报错的快速修复方法

很多小伙伴遇到电脑报错&#xff0c;提示“kbdnso.dll文件缺失&#xff0c;程序无法启动执行”时&#xff0c;不知道应该怎样处理&#xff0c;还以为是程序出现了问题&#xff0c;想卸载重装。 首先&#xff0c;先要了解“kbdnso.dll文件”是什么&#xff1f; kbdnso.dll是Win…...

Spring技术内幕笔记之IOC的实现

IOC容器的实现 依赖反转&#xff1a; 依赖对象的获得被反转了&#xff0c;于是依赖反转更名为&#xff1a;依赖注入。许多应用都是由两个或者多个类通过彼此的合作来实现业务逻辑的&#xff0c;这使得每个对象都需要与其合作的对象的引用&#xff0c;如果这个获取过程需要自身…...

kotlin foreach 循环

java中的foreach循环也使用于kotlin &#xff0c;先回顾下java里面的foreach循环 java foreach循环格式 for(元素类型t 元素变量x : 遍历对象obj){引用了x的语句;} 例如&#xff1a; int[] intary {1,2,3,4};for (int a: intary) {Log.d("intary", String.value…...

分享相关知识

直接使用海龟图进行创作移动动态的游戏 这段代码是一个简单的turtle模块实现的小游戏&#xff0c;主要功能包括&#xff1a; 窗口和无人机初始化&#xff1a; 创建了一个turtle窗口&#xff0c;设置了窗口的背景颜色和标题。创建了一个表示无人机的turtle&#xff0c;形状为正…...

RabbitMQ(七)ACK 消息确认机制

目录 一、简介1.1 背景1.2 定义1.3 如何查看确认/未确认的消息数&#xff1f; 二、消息确认机制的分类2.1 消息发送确认1&#xff09;ConfirmCallback方法2&#xff09;ReturnCallback方法3&#xff09;代码实现方式一&#xff1a;统一配置a.配置类a.生产者c.消费者d.测试结果 …...

ubuntu 编译内核报错

Ubuntu 编译 Linux 内核经常会遇到如下错误&#xff1a; 如果报错 canonical-certs.pem&#xff1a; 如下&#xff1a; make[1]: *** No rule to make target ‘debian/canonical-certs.pem’, needed by ‘certs/x509_certificate_list’. Stop. make: *** [Makefile:1868: …...

个人网站开发需求分析/简述企业网站如何推广

今天接着上次说的远程线程注入来说下利用远程线程进行dll注入。 远程线程注入需要目标进程地址空间的某个函数作为线程的thread_func, 这样我们只能用目标进程中自定义的函数&#xff0c;那我们怎么样使用自定义的函数呢&#xff0c;这就需要使用DLL注入技术。 DLL注入原理很简…...

创建网页用什么软件/深圳网站设计专业乐云seo

在这个例子中&#xff0c;主要会用到python内置的和OS模块的几个函数&#xff1a;os.walk() &#xff1a; 该方法用来遍历指定的文件目录&#xff0c;返回一个三元tuple(dirpath, dirnames, filenames) &#xff0c;其中dirpath为当前目录路径&#xff0c;dirnames为当前路径下…...

服装网站建设进度及实施过程/产品seo怎么优化

浮点数的表示和精度如果a>0&#xff0c;那么1a一定大于1吗&#xff1f;在数学上&#xff0c;答案是肯定的。但在计算机上&#xff0c;答案就与a的大小和浮点数的精度有关了。在matalb上&#xff0c;可以作以下计算&#xff1a;>> a1/2^52a 2.220446049250313e-016>…...

黄浦网站建设/线上职业技能培训平台

百度 谷歌&#xff0c;基本没啥结果。 这个对于vim 或 gvim很容易&#xff0c;eclipse也容易&#xff0c;vs 没有提供许多功能&#xff0c;很烦人。 找到一个 文章&#xff1a;visual studio 2008 头文件和CPP文件之间切换 顺带着&#xff0c;找到了 http://www.alteridem.net…...

杭州微网站开发公司电话/免费查权重工具

环境描述&#xff1a;搭建了一个4台机器的hadoop集群环境&#xff0c;分别创建了用户hadoop1。 1&#xff09;首先解决了的问问题是实现master与其余三个slave的ssh无密码通信问题。 2&#xff09;安装hadoop的环境遇见下列问题&#xff1a; 首先&#xff1a;在master上用sc…...

郑州 (网站建设/中国十大seo公司

变量和赋值Name’千寻’Name’小寻’Print(name)运行之后&#xff0c;我们可以发现计算机打印出了我们所输入的第二个name&#xff0c;而没有显示我们第一个name。这里面的Name就是变量&#xff0c;变量就相当于我们独一无二的标签&#xff0c;一次print只能输出显示我们最后定…...