Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

 提到 sysfs 文件系统 ,必须先需要了解的是Linux设备模型,什么是Linux设备模型呢?

一、Linux 设备模型

1、设备模型概述

     从2.6版本开始,Linux开发团队便为内核建立起一个统一的设备模型。在以前的内核中没有独立的数据结构用来让内核获得系统整体配合的信息。尽管缺乏这些信息,在多数情况下内核还是能正常工作的。然而,随着拓扑结构越来越复杂,以及要支持诸如电源管理等新特性的需求,向新版本的内核明确提出了这样的要求:需要有一个对系统结构的一般性抽象描述,即设备模型。

目的

    设备、驱动、总线等彼此之间关系错综复杂。如果想让内核运行流畅,那就必须为每个模块编码实现这些功能。如此一来,内核将变得非常臃肿、冗余。而设备模型的理念即是将这些代码抽象成各模块共用的框架,这样不但代码简洁了,也可让设备驱动开发者摆脱这本让人头痛但又必不可少的一劫,将有限的精力放于设备差异性的实现。

II    设备模型用类的思想将具有相似功能的设备放到一起管理,并将相似部分萃取出来,使用一份代码实现。从而使结构更加清晰,简洁。

III   动态分配主从设备号,有效解决设备号的不足。设备模型实现了只有设备在位时才为其分配主从设备号,这与之前版本为每个设备分配一个主从设备号不同,使得有限的资源得到合理利用。

IV   设备模型提供sysfs文件系统,以文件的方式让本是抽象复杂而又无法捉摸的结构清晰可视起来。同时也给用户空间程序配置处于内核空间的设备驱动提供了一个友善的通道。

V   程序具有随意性,同一个功能,不同的人实现的方法和风格各不相同,设备驱动亦是如此。大量的设备亦若实现方法流程均不相同,对以后的管理、重构将是难以想象的工作量。设备模型恰是提供了一个模板,一个被证明过的最优的思路和流程,这减少了开发者设计过程中不必要的错误,也给以后的维护扫除了障碍。


2、设备模型结构

       如表,Linux设备模型包含以下四个基本结构:

类型

所包含的内容

内核数据结构

对应/sys

设备(Devices)

设备是此模型中最基本的类型,以设备本身的连接按层次组织

struct device

/sys/devices/*/*/.../

驱动

(Drivers)

在一个系统中安装多个相同设备,只需要一份驱动程序的支持

struct device_driver

/sys/bus/pci/drivers/*/

总线

(Bus)

在整个总线级别对此总线上连接的所有设备进行管理

struct bus_type

/sys/bus/*/

类别(Classes)

这是按照功能进行分类组织的设备层次树;如 USB 接口和 PS/2 接口的鼠标都是输入设备,都会出现在/sys/class/input/下

struct class

/sys/class/*/



       device、driver、bus、class是组成设备模型的基本数据结构。kobject是构成这些基本结构的核心,kset又是相同类型结构kobject的集合。kobject和kset共同组成了sysfs的底层数据体系。本节采用从最小数据结构到最终组成一个大的模型的思路来介绍。当然,阅读时也可先从Device、Driver、Bus、Class的介绍开始,先总体了解设备模型的构成,然后再回到kobject和kset,弄清它们是如何将Device、Driver、Bus、Class穿插链接在一起的,以及如何将这些映像成文件并最终形成一个sysfs文件系统。


二、sys 文件系统

        sysfs是一个基于内存的文件系统,它的作用是将内核信息以文件的方式提供给用户程序使用

        sysfs可以看成与proc,devfs和devpty同类别的文件系统,该文件系统是虚拟的文件系统,可以更方便对系统设备进行管理。它可以产生一个包含所有系统硬件层次视图,与提供进程和状态信息的proc文件系统十分类似。

       sysfs把连接在系统上的设备和总线组织成为一个分级的文件,它们可以由用户空间存取,向用户空间导出内核的数据结构以及它们的属性。sysfs的一个目的就是展示设备驱动模型中各组件的层次关系,其顶级目录包括block,bus,drivers,class,power和firmware等.

      sysfs提供一种机制,使得可以显式的描述内核对象、对象属性及对象间关系。sysfs有两组接口,一组针对内核,用于将设备映射到文件系统中,另一组针对用户程序,用于读取或操作这些设备。表2描述了内核中的sysfs要素及其在用户空间的表现:

          sysfs在内核中的组成要素              

               在用户空间的显示         

内核对象(kobject)

目录

对象属性(attribute)

文件

对象关系(relationship)

   链接(Symbolic Link)


     sysfs目录结构:

/sys 下的子目录                   

所包含的内容

/sys/devices

这是内核对系统中所有设备的分层次表达模型,也是/sys文件系统管理设备的最重要的目录结构;

/sys/dev

这个目录下维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件;

/sys/bus

这是内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接,它也是构成 Linux 统一设备模型的一部分;

/sys/class

这是按照设备功能分类的设备模型,如系统所有输入设备都会出现在/sys/class/input 之下,而不论它们是以何种总线连接到系统。它也是构成 Linux 统一设备模型的一部分;

/sys/kernel

这里是内核所有可调整参数的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的slab 分配器等几项较新的设计在使用它,其它内核可调整参数仍然位于sysctl(/proc/sys/kernel) 接口中;

/sys/module

这里有系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在/sys/module 中:

  • 编译为外部模块(ko文件)在加载后会出现对应的/sys/module/<module_name>/,并且在这个目录下会出现一些属性文件和属性目录来表示此外部模块的一些信息,如版本号、加载状态、所提供的驱动程序等;
  • 编译为内联方式的模块则只在当它有非0属性的模块参数时会出现对应的/sys/module/<module_name>,这些模块的可用参数会出现在/sys/modules/<modname>/parameters/<param_name> 中,
    • 如/sys/module/printk/parameters/time这个可读写参数控制着内联模块printk在打印内核消息时是否加上时间前缀;
    • 所有内联模块的参数也可以由"<module_name>.<param_name>=<value>"的形式写在内核启动参数上,如启动内核时加上参数"printk.time=1"与向"/sys/module/printk/parameters/time"写入1的效果相同;
  • 没有非0属性参数的内联模块不会出现于此。

/sys/power

这里是系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等。

表3:sysfs目录结构

 

三、深入理解 sysfs 文件系统

        sysfs是一个特殊文件系统,并没有一个实际存放文件的介质。

1、kobject结构

        sysfs的信息来源是kobject层次结构,读一个sysfs文件,就是动态的从kobject结构提取信息,生成文件。重启后里面的信息当然就没了

        sysfs文件系统与kobject结构紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。

        Kobject 是Linux 2.6引入的新的设备管理机制,在内核中由struct kobject表示。通过这个数据结构使所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,Kobject是组成设备模型的基本结构。类似于C++中的基类,它嵌入于更大的对象的对象中,用来描述设备模型的组件。如bus,devices, drivers 等。都是通过kobject连接起来了,形成了一个树状结构。这个树状结构就与/sys向对应


2、sysfs 如何读写kobject 结构

      sysfs就是利用VFS的接口去读写kobject的层次结构,建立起来的文件系统。 kobject的层次结构的注册与注销XX_register()形成的。文件系统是个很模糊广泛的概念, linux把所有的资源都看成是文件,让用户通过一个统一的文件系统操作界面,也就是同一组系统调用,对属于不同文件系统的文件进行操作。这样,就可以对用户程序隐藏各种不同文件系统的实现细节,为用户程序提供了一个统一的,抽象的,虚拟的文件系统界面,这就是所谓"VFS(Virtual Filesystem Switch)"。这个抽象出来的接口就是一组函数操作。
     我们要实现一种文件系统就是要实现VFS所定义的一系列接口,file_operations, dentry_operations, inode_operations等,供上层调用。

file_operations是描述对每个具体文件的操作方法(如:读,写);

dentry_operations结构体指明了VFS所有目录的操作方法;

inode_operations提供所有结点的操作方法


举个例子,我们写C程序,open(“hello.c”, O_RDONLY),它通过系统调用的流程是这样的

open() -> 系统调用->  sys_open() -> filp_open()-> dentry_open() -> file_operations->open()          

      不同的文件系统,调用不同的file_operations->open(),在sysfs下就是sysfs_open_file()。我们使用不同的文件系统,就是将它们各自的文件信息都抽象到dentry和inode中去。这样对于高层来说,我们就可以不关心底层的实现,我们使用的都是一系列标准的函数调用。这就是VFS的精髓,实际上就是面向对象。

     注意sysfs是典型的特殊文件。它存储的信息都是由系统动态的生成的,它动态的包含了整个机器的硬件资源情况。从sysfs读写就相当于向 kobject层次结构提取数据


下面是详细分析:

a -- sysfs_dirent是组成sysfs单元的基本数据结构,它是sysfs文件夹或文件在内存中的代表。sysfs_dirent只表示文件类型(文件夹/普通文件/二进制文件/链接文件)及层级关系,其它信息都保存在对应的inode中。我们创建或删除一个sysfs文件或文件夹事实上只是对以sysfs_dirent为节点的树的节点的添加或删除。sysfs_dirent数据结构如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. struct sysfs_dirent {  
  2.        atomic_t                s_count;  
  3.        atomic_t                s_active;  
  4.        struct sysfs_dirent  *s_parent;  /* 指向父节点 */  
  5.        struct sysfs_dirent  *s_sibling;  /* 指向兄弟节点,兄弟节点是按照inode索引s_ino的大小顺序链接在一起的。*/  
  6.        const char             *s_name;    /* 节点名称 */  
  7.    
  8.        union {  
  9.               struct sysfs_elem_dir            s_dir;      /* 文件夹,s_dir->kobj指向sysfs对象 */  
  10.               struct sysfs_elem_symlink    s_symlink;  /* 链接 */  
  11.               struct sysfs_elem_attr           s_attr;     /* 普通文件 */  
  12.               struct sysfs_elem_bin_attr     s_bin_attr;  /* 二进制文件 */  
  13.        };  
  14.    
  15.        unsigned int           s_flags;  
  16. ino_t          s_ino;     /* inode索引,创建节点时被动态申请,通过此值和sysfs_dirent地址可以到inode散列表中获取inode结构 */  
  17.        umode_t                s_mode;  
  18.        struct iattr             *s_iattr;  
  19. };  


b -- inode(index node)中保存了设备的主从设备号、一组文件操作函数和一组inode操作函数。

     文件操作比较常见:open、read、write等。inode操作在sysfs文件系统中只针对文件夹实现了两个函数一个是目录下查找inode函数(.lookup=sysfs_lookup),该函数在找不到inode时会创建一个,并用sysfs_init_inode为其赋值;另一个是设置inode属性函数(.setattr=sysfs_setattr),该函数用于修改用户的权限等。inode结构如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. struct inode {  
  2.        struct hlist_node     i_hash;    /* 散列表链节 */  
  3.        struct list_head       i_list;  
  4.        struct list_head       i_sb_list;  
  5.        struct list_head       i_dentry;  /* dentry链节 */  
  6.        unsigned long         i_ino;   /* inode索引 */  
  7.        atomic_t             i_count;  
  8.        unsigned int           i_nlink;  
  9.        uid_t                     i_uid;  
  10.        gid_t                     i_gid;  
  11.        dev_t                    i_rdev; /* 主从设备号 */  
  12. const struct inode_operations *i_op; /* 一组inode操作函数,可用其中lookup查找目录下的inode,对应sysfs为sysfs_lookup函数 */  
  13. const struct file_operations  *i_fop;    /* 一组文件操作函数,对于sysfs为sysfs的open/read/write等函数 */  
  14.        struct super_block  *i_sb;  
  15.        struct list_head       i_devices;  
  16.        union {  
  17.               struct pipe_inode_info    *i_pipe;  
  18.               struct block_device       *i_bdev;  
  19.               struct cdev            *i_cdev;  
  20.        };  
  21. };  

c -- dentry(directory entry) 的中文名称是目录项,是Linux文件系统中某个索引节点(inode)的链接。

      这个索引节点可以是文件,也可以是目录。引入dentry的目的是加快文件的访问。dentry数据结构如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. struct dentry {  
  2.        atomic_t d_count;         /* 目录项对象使用的计数器 */  
  3.        unsigned int d_flags;             /* 目录项标志 */  
  4.        spinlock_t d_lock;              /* 目录项自旋锁 */  
  5.        int d_mounted;                     /* 对于安装点而言,表示被安装文件系统根项 */  
  6.        struct inode *d_inode;           /* 文件索引节点(inode) */  
  7.        /* 
  8.         * The next three fields are touched by __d_lookup.  Place them here 
  9.         * so they all fit in a cache line. 
  10.         */  
  11.        struct hlist_node d_hash;       /* lookup hash list */  
  12.        struct dentry *d_parent; /* parent directory */  
  13.        struct qstr d_name;              /* 文件名 */  
  14.    
  15.        /* 
  16.         * d_child and d_rcu can share memory 
  17.         */  
  18.        union {  
  19.               struct list_head d_child; /* child of parent list */  
  20.              struct rcu_head d_rcu;  
  21.        } d_u;  
  22.         
  23.        void *d_fsdata;                    /* 与文件系统相关的数据,在sysfs中指向sysfs_dirent */  
  24.        unsigned char d_iname[DNAME_INLINE_LEN_MIN];      /* 存放短文件名 */  
  25. };  

sysfs_dirent、inode、dentry三者关系:


       如上图sysfs超级块sysfs_sb、dentry根目录root、sysfs_direct根目录sysfs_root都是在sysfs初始化时创建。

      sysfs_root下的子节点是添加设备对象或对象属性时调用sysfs_create_dir/ sysfs_create_file创建的,同时会申请对应的inode的索引号s_ino。注意此时并未创建inode。

       inode是在用到的时候调用sysfs_get_inode函数创建并依据sysfs_sb地址和申请到的s_ino索引计算散列表位置放入其中。

      dentry的子节点也是需要用的时候才会创建。比如open文件时,会调用path_walk根据路径一层层的查找指定dentry,如果找不到,则创建一个,并调用父dentry的inodelookup函数(sysfs文件系统的为sysfs_lookup)查找对应的子inode填充指定的dentry。


       这里有必要介绍一下sysfs_lookup的实现,以保证我们更加清晰地了解这个过程,函数主体如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)  
  2. {  
  3.        struct dentry *ret = NULL;  
  4.        struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; //获取父sysfs_direct  
  5.        struct sysfs_dirent *sd;  
  6.        struct inode *inode;  
  7.    
  8.        mutex_lock(&sysfs_mutex);  
  9.         
  10.        /* 在父sysfs_direct查找名为dentry->d_name.name的节点 */  
  11.        sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);  
  12.    
  13.        /* no such entry */  
  14.        if (!sd) {  
  15.               ret = ERR_PTR(-ENOENT);  
  16.               goto out_unlock;  
  17.        }  
  18.         
  19.        /* 这儿就是通过sysfs_direct获取对应的inode,sysfs_get_inode实现原理上面已经介绍过了 */  
  20.        /* attach dentry and inode */  
  21.        inode = sysfs_get_inode(sd);  
  22.        if (!inode) {  
  23.               ret = ERR_PTR(-ENOMEM);  
  24.               goto out_unlock;  
  25.        }  
  26.         
  27.        /* 填充目录项,至此一个目录项创建完毕 */  
  28.        /* instantiate and hash dentry */  
  29. dentry->d_op = &sysfs_dentry_ops;   /* 填充目录项的操作方法,该方法只提供一释放inode函数sysfs_d_iput */  
  30.        dentry->d_fsdata = sysfs_get(sd);        //填充sysfs_direct  
  31.        d_instantiate(dentry, inode);                 //填充inode  
  32.        d_rehash(dentry);                               //将dentry加入hash表  
  33.    
  34.  out_unlock:  
  35.        mutex_unlock(&sysfs_mutex);  
  36.        return ret;  
  37. }  


四、实例分析

a -- sysfs文件open流程

        open的主要过程是通过指定的路径找到对应的dentry,并从中获取inode,然后获取一个空的file结构,将inode中相关内容赋值给file,这其中包括将inode的fop赋给file的fop。因此接下来调用的filp->fop->open其实就是inode里的fop->open。新的file结构对应一个文件句柄fd,这会作为整个open函数的返回值。之后的read/write操作就靠这个fd找到对应的file结构了。

图3-2是从网上找到的,清晰地描述了file和dentry以及inode之间的关系


                                                  图3-2:file、dentry、inode关系


        进程每打开一个文件,就会有一个file结构与之对应。同一个进程可以多次打开同一个文件而得到多个不同的file结构,file结构描述了被打开文件的属性,读写的偏移指针等等当前信息。

        两个不同的file结构可以对应同一个dentry结构。进程多次打开同一个文件时,对应的只有一个dentry结构。dentry结构存储目录项和对应文件(inode)的信息。

       在存储介质中,每个文件对应唯一的inode结点,但是,每个文件又可以有多个文件名。即可以通过不同的文件名访问同一个文件。这里多个文件名对应一个文件的关系在数据结构中表示就是dentry和inode的关系。

      inode中不存储文件的名字,它只存储节点号;而dentry则保存有名字和与其对应的节点号,所以就可以通过不同的dentry访问同一个inode。


b -- sysfs文件read/write流程

      sysfs与普通文件系统的最大差异是,sysfs不会申请任何内存空间来保存文件的内容。事实上再不对文件操作时,文件是不存在的。只有用户读或写文件时,sysfs才会申请一页内存(只有一页),用于保存将要读取的文件信息。如果作读操作,sysfs就会调用文件的父对象(文件夹kobject)的属性处理函数kobject->ktype->sysfs_ops->show,然后通过show函数来调用包含该对象的外层设备(或驱动、总线等)的属性的show函数来获取硬件设备的对应属性值,然后将该值拷贝到用户空间的buff,这样就完成了读操作。写操作也类似,都要进行内核空间ßà用户空间内存的拷贝,以保护内核代码的安全运行。

图为用户空间程序读sysfs文件的处理流程,其他操作类似:





 

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

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

相关文章

Python爬虫入门七正则表达式

已经搞定了怎样获取页面的内容&#xff0c;不过还差一步&#xff0c;这么多杂乱的代码夹杂文字我们怎样把它提取出来整理呢&#xff1f;下面就开始介绍一个十分强大的工具&#xff0c;正则表达式 1.了解正则表达式 正则表达式是用来匹配字符串非常强大的工具&#xff0c;在其…

Linux 文件系统与设备文件系统 (一)—— udev 设备文件系统

一、什么是Linux设备文件系统 首先我们不看定义&#xff0c;定义总是太抽象很难理解&#xff0c;我们先看现象。当我们往开发板上移植了一个新的文件系统之后&#xff08;假如各种设备驱动也移植好了&#xff09;&#xff0c;启动开发板&#xff0c;我们用串口工具进入开发板&a…

情人节,教大家使用css画出一朵玫瑰花。

情人节到了&#xff0c;给大家来一朵高端的玫瑰花。 在网上看到的一个canvas实现的玫瑰花&#xff0c;效果很好&#xff0c;但是代码被压缩过&#xff0c;也没有注释&#xff0c;看的云里雾里的。 今天我教大脚用CSS来实现一朵玫瑰花。 先看效果 首先我们画出一个花瓣 1、画出一…

Linux 字符设备驱动开发基础(六)—— VFS 虚拟文件系统解析

一、VFS 虚拟文件系统基础概念 Linux 允许众多不同的文件系统共存&#xff0c;并支持跨文件系统的文件操作&#xff0c;这是因为有虚拟文件系统的存在。虚拟文件系统&#xff0c;即VFS&#xff08;Virtual File System&#xff09;是 Linux 内核中的一个软件抽象层。它通过一些…

vim使用—实现程序的自动补齐(C语言)

使用过Source Insight的人一定对它的自动补全功能印象深刻&#xff0c;在很多的集成开发环境中&#xff0c;也都支持自动补全。vim做为一个出色的编辑器&#xff0c;这样的功能当然少不了。至于如何实现程序自动补全&#xff0c;网上教程很多。这里&#xff0c;我将自己配置过程…

[C#]Attribute特性(3)——AttributeUsage特性和特性标识符

相关文章 [C#]Attribute特性 [C#]Attribute特性(2)——方法的特性及特性参数 AttributeUsage特性 除了可以定制自己的特性来注释常用的C#类型外&#xff0c;您可以用AttributeUsage特性来定义您想怎样使用这些特性。AttributeUsage特性采用如下的调用惯例&#xff1a; 1 [Attri…

Linux 命令 ——less命令

less 工具也是对文件或其它输出进行分页显示的工具&#xff0c;应该说是linux正统查看文件内容的工具&#xff0c;功能极其强大。less 的用法比起 more 更加的有弹性。在 more 的时候&#xff0c;我们并没有办法向前面翻&#xff0c; 只能往后面看&#xff0c;但若使用了 less …

android闹钟实现原理

闹钟的原理可用下面我自己画的一幅图来概括&#xff1a;&#xff08;不对的地方&#xff0c;尽管吐槽&#xff09; 我们来看看新建闹钟到闹钟响铃的步骤&#xff1a; 1、新建一个闹钟&#xff1a; ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22…

将openstack的Token认证信息存储在memcache中

公司线上的openstack环境运行了5个多月的时间&#xff0c;keystone库的token表已经增长到了31GB&#xff0c;这个数据量还是很大的&#xff0c;对于以后的数据库备份很不方便。每次管理openstack的时候&#xff0c;都会产生一个新的token验证&#xff0c;而历史token信息其实都…

Linux 下shell编程

什么是shell?Shell是一个命令解析器&#xff0c;是介于Linux操作系统的内核(kernel)与用户之间的一个绝缘层。shell脚本就是讲各类命令预先放入其中&#xff0c;方便一次性执行的一个程序文件&#xff0c;主要用于方便管理员进行设置或者管理。 序员的角度来看&#xff0c; Sh…

linux 目录/sys 解析

今天学习Linux目录时&#xff0c;遇到/sys这个目录&#xff0c;老师怎么讲的&#xff0c;不太清楚&#xff0c;先对/sys目录知识进行一个整理 首先&#xff0c;对 /sys目录下的各个子目录进行具体说明&#xff1a; /sys下的子目录 内容 /sys/devices 该目录下…

南下事业篇——深圳 深圳(回顾)

2019独角兽企业重金招聘Python工程师标准>>> 二0一二年三月二十三号记录了下面的一篇日志&#xff0c;现在回味一下觉得自己有点惭愧&#xff0c;但不后悔&#xff0c;知道的越多就越了解自己的无知&#xff0c;工作之后渐渐磨灭了许多锐气&#xff0c;变得平滑低调…

php中花括号的使用

一、界定变量名 注&#xff1a;花括号内若左侧出现空格&#xff0c;则会当做普通花括号来解析。 二、界定表达式 1.获取字符串中某个字符 如&#xff1a;$strabcdefg; echo $str{0};//a 效果等同于$str[0]; 2.作为表示下标的方法定义数组 如&#xff1a;$arr []; $arr{10}4;…

游戏开发--开源软件8--cyclone2D(手机引擎+设计工具)

2019独角兽企业重金招聘Python工程师标准>>> Cyclone2D (飓风软件)是集成的手机游戏设计工具以及开源的引擎&#xff0c;工具提供了强大的动画、地图、数值、脚本等设计功能&#xff0c;开源引擎提供了一体化的模块加载与管理&#xff0c;并提供了详细的API文档以及…

python编码

https://www.cnblogs.com/xiao-xue-di/p/11283496.html 《Python中的Unicode编码和UTF-8编码》 《字符串和编码》 《python编码转换(unicode / utf8 / gbk / 内部编码)》 字符编码 最早127个字母被编码到计算机里&#xff0c;也就是大小写英文字母、数字和一些符号&#xff0…

Linux中vi显示中文乱码的问题

linux 下编程&#xff0c;用到的编程工具是VI&#xff0c;编辑编译都方便&#xff0c;但经常出现中文乱码问题&#xff0c;下面可完美解决这个问题 由于在windows下默认是gb编码&#xff0c;而我的vim默认是utf-8&#xff08;gedit默认也是utf-8&#xff09;&#xff0c;所以打…

WIFI vs 无线网

大家好多人都在使用无线设备上网&#xff0c;好多人对一些名词充满了好奇&#xff0c;比如WLAN和WIFI的区别是什么? WIFI无线上网和WLAN无线上网是什么意思? 这篇文章中我们为大家介绍什么是WIFI无线上网?大家可能会有这样的疑问&#xff0c;听说最多的应该是WLAN无线上网&a…

[转]jQuery Validate使用说明

本文转自&#xff1a;http://www.cnblogs.com/gimin/p/4757064.html jQuery Validate 导入 js 库 <script src"./jquery-validation/lib/jquery-1.8.3.js" type"text/javascript"></script> <script src"./jquery-validation/dist/jqu…

Linux 设备驱动开发 —— Tasklets 机制浅析

一 、Tasklets 机制基础知识点 1、Taklets 机制概念 Tasklets 机制是linux中断处理机制中的软中断延迟机制。通常用于减少中断处理的时间&#xff0c;将本应该是在中断服务程序中完成的任务转化成软中断完成。 为了最大程度的避免中断处理时间过长而导致中断丢失&#xff0c;有…

验证码(一)

需要验证码的地方还真不少&#xff0c;这主要是为了确保用户信息的安全。这里我做了一个纯字母的验证码。Random rnew Random ();string all "";private void btnCreatAuthCode_Click(object sender, EventArgs e){GetAuthCodes();}private void GetAuthCodes(){//定…