【Linux开发】linux设备驱动归纳总结(二):模块的相关基础概念

linux设备驱动归纳总结(二):模块的相关基础概念


系统平台:Ubuntu 10.04

开发平台:S3C2440开发板

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


一。初探linux内核模块


内核模块:内核本身是很庞大的一个结构,需要的组件很多。编译内核时,用户 可以把所有的代码编译进内核,但是这样会引起两个问题:一是内核过大;二是 当需要添加或者删除内核时,需要重新再编译内核。所以有了内核模块的概念。 模块并不编译到内核中,编译后存放在指定的目录,当需要使用时动态加载。

1.1下面是一个非常经典的hello world代码: 目录:1st

/*2nd_module/1st*/

1 #include //包含了很多装载模块需要的符号和函数的定义

2 #include //用于指定初始化函数和清除函数

3

4 static int __init test_init(void) //内核初始化函数

5 {

6         printk("hello world!\n"); //打印函数,和prinft类似

7         return 0;

8 }

9

10 static void __exit test_exit(void)//内核清除函数

11 {

12         printk("good bye!\n");

13 }

14

15 module_init(test_init); //指定初始化函数

16 module_exit(test_exit); //指定清除函数

17

18 MODULE_LICENSE("GPL"); //指定代码使用的许可证

19 MODULE_AUTHOR("xiao bai"); //指定作者

20 MODULE_VERSION("1.0"); //指定代码修订号


1.2再来一个Makefile

(注:如果不知道“make -C $(KDIR) M=`pwd` modules ”语句的意思,可以查看linux内核驱动归纳总结(一):内核的相关基础概念的第六小节)

obj-m += test.o


KDIR:=/root/Desktop/drives/nfsroot-29/linux-2.6.29

all:

        make -C $(KDIR) M=`pwd` modules

clean:

        make -C $(KDIR) M=`pwd` modules clean

        rm -f modules.order


1.3编写完毕后在代码目录下执行“make”命令,就会产生test.ko文件,在开发板 上通过命令“insmod test.ko”,插入模块,通过命令“lsmod”查看当前的所有 装载上的模块,通过命令“rmmod test”卸载该模块。并且,加载时会输出 “hello world!”,卸载时会输出“good bye!”

[root: 1st]# rmmod test

good bye!

[root: 1st]# insmod test.ko

hello world!

[root: 1st]# lsmod

test 1060 0 - Live 0xbf00c000

[root: 1st]# rmmod test

good bye!

[root: 1st]#


1.4上面的程序包含了三个知识点:

1.4.1内核初始化函数:

static int __init test_init(void) //内核初始化函数

{

}

module_init(test_init); //指定初始化函数

1)初始化函数是在模块加载时自动被调用,执行相关的初始化工作。

2)static__init都是可以不加的,因为初始化函数除了加载时执行外没有别的 用处,加上static只是声明一下,该函数只能在模块内部使用。而加上__init后,它暗 示内核该函数仅在初始化时使用,所以在模块被装载后,模块装载器就会把该函 数扔掉,释放占用的内存空间。

3)但是moudle_init()是必须要的,因为这样才能让模块加载器知道这是个初始化 函数,没有这一步,函数就不会得到调用。

4)初始化函数成功返回0,失败返回对应的错误码。


1.4.2内核清除函数:

static void __exit test_exit(void)//内核清除函数

{

}

module_exit(test_exit); //指定清除函数

1)内核清除函数是在模块卸载是自动被调用,执行相关的清除工作。

2)同上,static__exit都是可以不加的,但如果加上__exit,模块直接编 译进内核或者不允许卸载,被标志为__exit的函数会被自动丢弃掉。

3)module_exit是必须的,因为这样内核才能找到清除函数。

4)清除函数的没有返回值。

5)一个没有定义清除函数的模块,是不允许被加载的。


1.4.3模块的描述性定义:

MODULE_LICENSE("GPL"); //指定代码使用的许可证

MODULE_AUTHOR("xiao bai"); //指定作者

MODULE_VERSION("1.0"); //指定代码修订号

1)以上的都是一些都该模块的描述,除了上面的还有MODULE_ALIAS(模块的别名) MODULE_DESCRIPTION(描述用途)等。

2)MODULE_LICENSE一般都是要写的,告诉内核该程序使用的许可证,不然在加载 时它会提示该模块污染内核。

3)MODULE_声明可以声明在源代码任意位置,但习惯放在代码的最后。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


二。内核中的printk


printkprintf的用法是差不多的,最大的区别就是printk可以指定打印的优先 级。另外一个区别就是,printf只用在用户态,printk用于内核态。

下面由程序讲解 目录:2nd

/*2nd_module/2nd*/

1 #include

2 #include

3

4 static int __init test_init(void)

5 {

        printk("hello world!\n");

        printk("<0>" "hello world! 0\n");

        printk("<1>" "hello world! 1\n");

        printk("<2>" "hello world! 2\n");

10       printk("<3>" "hello world! 3\n");

11       printk("<4>" "hello world! 4\n");

12       printk("<5>" "hello world! 5\n");

13       printk("<6>" "hello world! 6\n");

14       printk("<7>" "hello world! 7\n");

15       return 0;

16 }

17

18 static void __exit test_exit(void)

19 {

20         printk("good bye!\n");

21 }

22

23 module_init(test_init);

24 module_exit(test_exit);

25

26 MODULE_LICENSE("GPL");

27 MODULE_AUTHOR("xiao bai");

28 MODULE_VERSION("1.0");


编译后加载模块,发现输出内容为:

[root: 2nd]# insmod test.ko

hello world!

hello world! 0

hello world! 1

hello world! 2

hello world! 3

hello world! 4

hello world! 5

hello world! 6


输出唯独缺少了最后一个"hello world! 7",这是因为printk输出优先级的导致 的。printk的优先级如下,在内核目录下inxlude/linux/kernel.h下有记录:

91 #define KERN_EMERG "<0>" /* system is unusable */

92 #define KERN_ALERT "<1>" /* action must be taken immediately */

93 #define KERN_CRIT "<2>" /* critical conditions */

94 #define KERN_ERR "<3>" /* error conditions */

95 #define KERN_WARNING "<4>" /* warning conditions */

96 #define KERN_NOTICE "<5>" /* normal but significant condition */

97 #define KERN_INFO "<6>" /* informational */

98 #define KERN_DEBUG "<7>" /* debug-level messages */

其中<0>的优先级最高,<7>优先级最低。上面的printk语句的优先级都可以用字符 串代替,如下面两句是同等作用的:

p { margin-bottom: 0.21cm; }

printk("<3>" "hello world! 3\n");

printk(KERN_ERR "hello world! 3\n")

如果调用printk使用的优先级低于或等于控制台的默认优先级,就不能被输出到 控制台终端上显示,所以在minicom界面中看不到最后一句的输出。

按照以上的推测,可以得到两个结论:

一、如果不指定prinfk的优先级,prinfk的默认优先级比控制台的优先级高,所 以才能显示在控制台上。

二、控制台的优先级是6,因为低于6优先级的语句不能打印出来。


printk的默认优先级在内核目录kernel/printk.c定义:

47 /* printk's without a loglevel use this.. */

48 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */

49

50 /* We show everything that is MORE important than this.. */

51 #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */

52 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG*/

文件中定义了printk的默认输出优先级为4,并定义了一般使用的最大和最小优先 级17


而终端控制台的输出优先级配置在文件/proc/sys/kernel/printk中:

[root: /]# cat /proc/sys/kernel/printk

7 4 1 7

7 4 1 7分别是:

7console_loglevel //这个就是控制台的默认优先级

4default_message_loglevel // 这个是printk的默认输出优先级

1minimum_console_level

7default_console_loglevel


可以通过修改该文件使所有优先级的消息都显示出来。

[root: /]# echo 8 > /proc/sys/kernel/printk


注意的是,即使没有显示在控制台的内核消息,也会追加到/var/log/messages,通过查看/var/log/messages就能看到。


小技巧:可以通过printk的优先级定义是否输出调试信息:目录:3rd

1 #include

2 #include

3

4 #define DEBUG_SWITCH 0

5 #if DEBUG_SWITCH

6         #define P_DEBUG(fmt, args...) printk("<1>" "[%s]"fmt, __FUNCTION__, ##args)

7 #else

        #define P_DEBUG(fmt, args...) printk("<7>" "[%s]"fmt, __FUNCTION__, ##args)

9 #endif

10

11

12 static int __init test_init(void)

13 {

14         printk("hello world!\n");

15         P_DEBUG("debug!\n");

16         return 0;

17 }

18

19 static void __exit test_exit(void)

20 {

21         printk("good bye!\n");

22 }

23

24 module_init(test_init);

25 module_exit(test_exit);

26

27 MODULE_LICENSE("GPL");

28 MODULE_AUTHOR("xiao bai");

29 MODULE_VERSION("1.0");


#define DEBUG_SWITCH 0时,P_DEBUG语句并不输出到控制台。

相反,当#define DEBUG_SWITCH 1时,P_DEBUG语句输出到控制台。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


三。内核传参————module_param


在用户态的C语言中,函数的传参使用main(int argc, char* argv),内核的传参使用了另外一种方法:

步骤一、在内核函数中用module_param指定模块参数。

步骤二、加载内核时传递参数给模块。


module_param函数使用方法:

module_param(name, type, perm)

name:内核参数的名称,自己定义;

type:内核参数的类型,常见的类型byteshortintlongulongbool charp(字符指针);

perm:内核参数的权限S_IRUGO(对模块参数具有读权限)。其实权限和文件的 权限差不多,具体可以查看"include/linux/stat.h"


所以,要定义一个int模块参数,权限是0644,在函数中需要定义:

int a=0;

module_paaram(a, int, 0644);


内核加载模块时传递参数的方法:

使用命令:insmod xxx.ko a=1

如果加载模块时不指定参数,模块会使用默认值0,否则会使用1


模块加载后,并且他的权限不为0,就可以在/sys/module/xxx/parameter目录下 找到对应的模块参数。

模块参数使用例子:目录 4th

/*2nd_module/4th*/

1 #include

2 #include

3

4 int num = 123;

5 char *name = "xiao bai";

6

7 static int __init test_init(void)

8 {

        printk("hello world!\n");

10        printk("num = %d, name:[%s]\n", num, name);

11        return 0;

12 }

13

14 static void __exit test_exit(void)

15 {

16        printk("good bye!\n");

17 }

18

19 module_init(test_init);

20 module_exit(test_exit);

21 module_param(num, int, 0644);

22 module_param(name, charp, 0644);

23

24 MODULE_LICENSE("GPL");

25 MODULE_AUTHOR("xiao bai");

26 MODULE_VERSION("1.0");


几种指定模块参数时的效果:

[root: 4th]# insmod test.ko

hello world!

num = 123, name:[xiao bai]

[root: 4th]# rmmod test

good bye!

[root: 4th]# insmod test.ko num=321 name='haha'

hello world!

num = 321, name:[haha]

[root: 4th]# rmmod test

good bye!

[root: 4th]# insmod test.ko name='haha'

hello world!

num = 123, name:[haha]


查看/sys/module/test/parameter目录,出现了模块参数:

[root: 4th]# ls /sys/module/test/parameters/

name num


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


四、内核函数间的调用


内核函数间的调用有两种方法:

1)、把需要调用的函数编译进模块,与C语言的静态库类似。

2)、把许压迫被调用的函数导出到符号表,方便模块使用,与C语言的动态库类似


先说第一个方法:多文件编译 目录 5th

1)编写被调用的函数文件haha.c

1 #include

2 #include "haha.h"

3

4 void haha(void)

5 {

        printk("haha!\n");

7 }


2)编写头文件haha.h

1 #ifndef __HAHA_H__

2 #define __HAHA_H__

3

4 void haha(void);

5

6 #endif


3)编写模块文件test.c

1 #include

2 #include

3 #include "haha.h"

4

5 static int __init test_init(void)

6 {

        printk("hello world!\n");

        haha();

        return 0;

10 }

11

12 static void __exit test_exit(void)

13 {

14         printk("good bye!\n");

15 }

16

17 module_init(test_init);

18 module_exit(test_exit);

19

20 MODULE_LICENSE("GPL");

21 MODULE_AUTHOR("xiao bai");

22 MODULE_VERSION("1.0");


4)编写Makefile,与之前的Makefile不一样,因为涉及到多文件编译

1 obj-m += test_haha.o //生成test_haha.ko

2 test_haha-objs += haha.o test.o //test_haha.kohaha.otest.o组成

3

4 KDIR:=/root/Desktop/drives/nfsroot-29/linux-2.6.29

5 all:

        make -C $(KDIR) M=`pwd` modules

7 clean:

        make -C $(KDIR) M=`pwd` modules clean

        rm -f modules.order


编译完毕后生成test_haha,ko,看一下效果

[root: 5th]# insmod test_haha.ko

hello world!

haha!


值得指出的是,上面的方法一般不用。应该使用下面的方法。


第二种方法:导出符号表EXPORT_SYMBOL :目录 6th


导出符号表是指,在定义一个函数后,在模块中使用语句"EXPORT_SYMBOL(xxxxx)" 将函数导出。通过这样,内核就知道了该函数和在内存中对应的地址,这样模块 就可以调用导出的函数了。在"/proc/kallsyms"文件中对应这符号表,它记录了函数的符号和函数在内存所在的地址。


看看方法:

1)6th/core目录下编写被调用的函数的文件haha.c

1 #include

2 #include

3 #include "../include/haha.h"

4

5 int haha(void)

6 {

        printk("haha!\n");

        return 0;

9 }

10

11 EXPORT_SYMBOL(haha); //导出函数

12 MODULE_LICENSE("GPL");


2)在6th/core目录下编写Makefile,用于编译haha.chaha.ko

1 obj-m += haha.o

2

3 KDIR:=/root/Desktop/drives/nfsroot-29/linux-2.6.29

4 all:

        make -C $(KDIR) M=`pwd` modules

6 clean:

        make -C $(KDIR) M=`pwd` modules clean

        rm -f modules.order


3)6th/include目录下编写头文件haha.h

1 #ifndef __HAHA_H__

2 #define __HAHA_H__

3

4 int haha(void);

5

6 #endif


4)6th/driver目录下编写文件test.c

1 #include

2 #include

3 #include "../include/haha.h"

4

5 static int __init test_init(void)

6 {

        printk("hello world!\n");

        haha();

        return 0;

10 }

11

12 static void __exit test_exit(void)

13 {

14         printk("good bye!\n");

15 }

16

17 module_init(test_init);

18 module_exit(test_exit);

19

20 MODULE_LICENSE("GPL");

21 MODULE_AUTHOR("xiao bai");

22 MODULE_VERSION("1.0");


5)6th/driver目录下编写Makefile,用于编译test.c

1 obj-m += test.o

2

3 KDIR:=/root/Desktop/drives/nfsroot-29/linux-2.6.29

4 all:

        make -C $(KDIR) M=`pwd` modules

6 clean:

        make -C $(KDIR) M=`pwd` modules clean

        rm -f modules.order

最终会生成两个文件,一个是core目录下的haha.ko,一个是driver目录下的 test.ko。这两个文件的加载也要讲究顺序。

如果先加载test.ko的话会出错:

[root: driver]# insmod test.ko

test: Unknown symbol haha

insmod: cannot insert 'test.ko': unknown symbol in module or invalid parameter

这是因为内核不能找到函数haha

[root: core]# cat /proc/kallsyms | grep haha //没有显示任何东西


所以需要先加载模块haha.ko,这样就可以在/proc/kallsyms中找到

[root: /]# cd review_driver/2nd_module/6th/core/

[root: core]# insmod haha.ko

[root: core]# cat /proc/kallsyms | grep haha

00000000 a haha.c [haha]

bf000000 t $a [haha]

bf00001c t $d [haha]

bf000044 r __kstrtab_haha [haha]

c4827080 ? __mod_license12 [haha]

bf000054 r __ksymtab_haha [haha]

bf000054 r $d [haha]

00000000 a haha.mod.c [haha]

c482708c ? __module_depends [haha]

c4827098 ? __mod_vermagic5 [haha]

bf000280 d __this_module [haha]

bf000000 T haha [haha]

c0225c10 u printk [haha]

[root: core]#

到出符号表之后就可以加载模块test.ko

[root: core]# cd ../driver/

[root: driver]# insmod test.ko

hello world!

haha!


随便提一下两个小问题:

1)、函数是必须有"#include "

原因一:printk的调用需要

原因二:如果不加上面的命令就不会显示"bf000000 T haha [haha]", 而显示"bf000000 t haha [haha]",小写t表示该符号未定义。

2)、模块的引用技术:

[root: 6th]# insmod core/haha.ko

[root: 6th]# lsmod

haha 904 0 - Live 0xbf000000 //0 无引用

[root: 6th]# insmod driver/test.ko

hello world!

haha!

[root: 6th]# lsmod

test 1084 0 - Live 0xbf003000

haha 904 1 test, Live 0xbf000000 //被引用一次,test模块引用

可以看到,加载了test.ko时,haha模块产生了变化,如果卸载的时候先卸载haha 是不可以的,因为它还被人引用,必须先卸载test


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

源代码:

 2nd_module.rar   

转载于:https://www.cnblogs.com/huty/p/8518610.html

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

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

相关文章

2020-12-24

console.log()&#xff0c;对于一般对于基本类型number、string、boolean、null、undefined 的输出是可信的。但对于Object 等引用类型来说&#xff0c;则就会出现上述异常打印输出。&#xff08;调试复杂数据类型时候通过打断点来看即可&#xff09; 正常预期 <script>…

XAML实例教程系列 - 资源(Resources)

在Windows 8 Metro应用开发中&#xff0c;XAML主要用于应用界面设计&#xff0c;无论是开发人员还是设计人员经常会设计自定义用户界面或者控件行为&#xff0c;其中会涉及到不同方面的代码设计&#xff0c;例如控件模板&#xff0c;控件样式&#xff0c;动画设计等。为了方便设…

解决vue的滚动条监听事件无效 解决vue的滚动条scrollTop距离总是为0无效问题

话不多说 直接上代码&#xff08;方法可以直接复制拿去&#xff0c; html部分需要改成你的元素的ref和点击回到顶部的方法名称&#xff09; html <section ref"scrollbox" class"inner-body"><div>这里放了很多内容 出现了滚动条</div&g…

装载问题

1、回溯法 (1)描述:回溯法是一种选优搜索法&#xff0c;按选优条件向前搜索&#xff0c;以达到目标。但当探索到某一步时&#xff0c;发现原先选择并不优或达不到目标&#xff0c;就退回一步重新选择&#xff0c;这种走不通就退回再走的技术为回溯法。 (2)原理: 回溯法在问题的…

android开发(13) 尝试在流布局中移动控件

我们常用的linearlayout,等都属于流布局&#xff0c;在流布局中如何移动控件呢&#xff1f; 我决定做个尝试。虽然可以使用绝对布局&#xff0c;但我不倾向使用这个布局。那么看看我的方式吧。 记得margin这个属性吗&#xff0c;我们就用来它来控制控件的位置&#xff0c;改动它…

第一章 处理器体系结构

1.请简述精简指令集RISC和复杂指令集CISC的区别 2.请简述数值 0x123456789 在大小端字节序处理器的存储器中的存储方式 3.请简述在你所熟悉的处理器&#xff08;比如双核Cortex-A9&#xff09;中一条存储读写指令的执行全过程 4.请简述内存屏障&#xff08;memory barrier&am…

给element的select添加复选框

需求&#xff1a;要求给select多选的时候&#xff0c;给下拉框前加上复选框样式 element select原样式 需要更改后的样式 html <el-selectv-model"searchObj.knowledgeIds"class"select-box"filterablemultiplecollapse-tagsstyle"margin-left…

修改复选框样式

//默认input[type"checkbox"] {margin-top: 7px;cursor: pointer;position: relative;width: 14px;height: 14px;font-size: 14px;margin-right: 8px;background-color:#fff;}//选中后修改input[type"checkbox"]::after {position: absolute;top: 0;//修改…

Vue 作用域插槽

原博出处&#xff1a; 作者&#xff1a;SentMes 链接&#xff1a;SentMes作者书写的作用于插槽链接 https://www.jianshu.com/p/0c9516a3be80 来源&#xff1a;简书 ** ** ** 十分感谢原作者&#xff0c;写的十分详细&#xff0c;原作者辛苦了&#xff01; 深入理解vue中的s…

I/O多路复用之epoll

2019独角兽企业重金招聘Python工程师标准>>> 在上一章&#xff0c;我们对select进行了大致的描述&#xff0c;知道了它相对传统的阻塞式服务提高了并发度&#xff0c;但是它也由于轮询而导致效率底下。本文对epoll进行讲解&#xff0c;相比select它的并发度更高&…

Xtreme TaskPanel

原文来自方案网 http://www.fanganwang.com/Product-detail-item-1230.html&#xff0c;欢迎转载。 关键字&#xff1a;TaskPanel Codejock Xtreme TaskPanel为Windows开发者提供了一个非常熟悉的任务栏&#xff0c;与Windows资源管理器类似。该任务面板可以像VS.NET工具一样被…

vscode tab键快捷生成元素html标签

按照上图在设置中找到对应的文件夹&#xff0c; 直接加上"emmet.triggerExpansionOnTab": true,这段代码保存 重新打开vscode即可

解决vscode格式化代码html属性换行问题; ctrl+s格式化去除分号,格式化自动单引号;解决js格式化换行问题;mac上的settings.json完整配置

右键格式化文档或者ctrl s保存 html不换行 1.安装两个插件①vetur ②Prettier - Code formatter 2.在vetur的settings.json中设置 配置ctrls触发格式化去除分号和单引号&#xff1b;配置格式化js换行&#xff1b;配置解决html属性换行 将最后一部分的设置&#xff0c;修改…

uniapp使用iconfont字体图标

vue引入字体图标看这篇 本文介绍两种方案&#xff1a;一、使用iconfont字体图标 二、使用icon图片 情景1&#xff1a;使用灰色的字体图标 方案一&#xff1a;使用iconfont字体图标 步骤1&#xff1a;下载iconfont 步骤2&#xff1a;解压后只需要将ifonfont.css这一个文件 &am…

socket选项: SO_REUSEADDR, SO_RCVBUF, SO_SNDBUF

From: http://blog.csdn.net/jasonliuvip/article/details/22591531 最近在看《linux高性能服务器编程》&#xff0c;在此做个日记&#xff0c;以激励自己&#xff0c;同时分享于有需要的朋友。 1. 读取和设置socket文件描述符属性&#xff1a; [cpp] view plaincopy#include …

VScode配置eslint保存自动格式化,eslint格式化去掉分号和双引号。vscode自动保存去掉分号和双引号;““

本文是开启eslint检验和配置eslint格式化&#xff1b;如果想要关闭eslint&#xff0c;查看这篇关闭eslint方法&#xff1b; 1.必须安装的三个插件eslint&#xff0c; prettier-Code formatter &#xff0c;vetur 2.配置setting.json 3.直接将下方代码复制&#xff0c;黏…

uniapp网络请求封装;小程序请求接口封装;uni.request接口封装

另一篇全面封装文章 资源文章下载地址 1.正常使用uni.request()发送请求(未封装) get() {uni.request({url: http://192.168.1.191/abc//main/jiekouming/abclist?workType2,data: {},header: {Token: b042b36fwq909qwe9iiidsai2323sd232dw3},method: GET,success: (res) &…

Nginx_lua

首先让我们来了解一下Nginx_lua的设计指导思想&#xff1a; 1、基于Nginx 快速开发高性能、大并发的网络服务。 2、提供“同步非阻塞” 的I/O 访问接口简化I/O 多路复用体系中的业务逻辑开发&#xff1a; ■“同步”的主体是用户代码与其发起的I/O 请求处理流程之间的时序关系&…

MyTask4

最近稍微做了点修改&#xff0c;把几处bug修复了下&#xff0c;另外新增了授权码功能和数据缓冲功能 先看看效果图 1. 如果要把软件做的高大上一些&#xff0c;你可以加一个授权验证&#xff0c;授权码以字符串形式存放在程序里面&#xff0c;当然你也可以另外开一个窗体&#…