04 linux之C 语言高级编程
gcc和gdb
GNU工具
- 编译工具:把一个源程序编译为一个可执行程序
- 调试工具:能对执行程序进行源码或汇编级调试
- 软件工程工具:用于协助多人开发或大型软件项目的管理,如make、CVS、Subvision
- 其他工具:用于把多个目标文件链接成可执行文件的链接器,或者用作格式转换的工具。
GCC
GCC简介:
- 全称为GNU CC ,GNU项目中符合ANSI C标准的编译系统
- 编译如C、C++、Object C、Java、Fortran、Pascal、Modula-3和Ada等多种语言
- GCC是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%
- 一个交叉平台编译器 ,适合在嵌入式领域的开发编译
GCC编译器的版本:
- GNU Compiler Collection
- C, C++, Objective-C, Fortran, Java, Ada
gcc所支持后缀名解释:
- .c C原始程序
- .C/.cc/.cxx C++原始程序
- .m Objective-C原始程序
- .i 已经过预处理的C原始程序
- .ii 已经过预处理的C++原始程序
- .s/.S 汇编语言原始程序
- .h 预处理文件(头文件)
- .o 目标文件
- .a/.so 编译后的库文件
编译器的主要组件
- 分析器:分析器将源语言程序代码转换为汇编语言。因为要从一种格式转换为另一种格式(C到汇编),所以分析器需要知道目标机器的汇编语言。
- 汇编器:汇编器将汇编语言代码转换为CPU可以执行字节码。
- 链接器:链接器将汇编器生成的单独的目标文件组合成可执行的应用程序。链接器需要知道这种目标格式以便工作。
- 标准C库:核心的C函数都有一个主要的C库来提供。如果在应用程序中用到了C库中的函数,这个库就会通过链接器和源代码连接来生成最终的可执行程序。
GCC的基本用法和选项
Gcc最基本的用法是∶gcc [options] [filenames]
- -c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。
- -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
- -g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。
- -O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。
- -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。
- -I dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。
- -L dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。
GCC的错误类型及对策
-
第一类∶C语法错误
错误信息∶文件source.c中第n行有语法错误(syntex errror)。有些情况下,一个很简单的语法错误,gcc会给出一大堆错误,我们最主要的是要保持清醒的头脑,不要被其吓倒,必要的时候再参考一下C语言的基本教材。
-
第二类∶头文件错误
错误信息∶找不到头文件head.h(Can not find include file head.h)。这类错误是源代码文件中的包含头文件有问题,可能的原因有头文件名错误、指定的头文件所在目录名错误等,也可能是错误地使用了双引号和尖括号。
-
第三类∶档案库错误
错误信息∶链接程序找不到所需的函数库(ld: -lm: No such file or directory )。这类错误是与目标文件相连接的函数库有错误,可能的原因是函数库名错误、指定的函数库所在目录名称错误等,检查的方法是使用find命令在可能的目录中寻找相应的函数库名,确定档案库及目录的名称并修改程序中及编译选项中的名称。
-
第四类∶未定义符号
错误信息∶有未定义的符号(Undefined symbol)。这类错误是在连接过程中出现的,可能有两种原因∶一是使用者自己定义的函数或者全局变量所在源代码文件,没有被编译、连接,或者干脆还没有定义,这需要使用者根据实际情况修改源程序,给出全局变量或者函数的定义体;二是未定义的符号是一个标准的库函数,在源程序中使用了该库函数,而连接过程中还没有给定相应的函数库的名称,或者是该档案库的目录名称有问题,这时需要使用档案库维护命令ar检查我们需要的库函数到底位于哪一个函数库中,确定之后,修改gcc连接选项中的-l和-L项。
GCC编译过程
GCC的编译流程分为四个步骤:
- 预处理(Pre-Processing)
- 编译(Compiling)
- 汇编(Assembling)
- 链接(Linking)
生成预处理代码
$ gcc –E test.c -o test.i
用wc
命令,查看这两个阶段代码大小:$ wc test.c test.i
9 16 127 test.c
842 1934 16498 test.i
851 1950 16625 总用量
test.i比test.c增加了很多内容,主要是放在系统提供的include文件中的。
生成汇编代码
检查语法错误,并生成汇编文件
$ gcc –S test.c –o test.s
生成目标代码
- 方法一,用gcc直接从C源代码中生成目标代码:
$ gcc –c test.s –o test.o
- 方法二,用汇编器从汇编代码生成目标代码:
$ as test.s –o test.o
生成可执行程序
将目标程序链接库资源,生成可执行程序$ gcc test.s –o test
、再运行./test
。
Gdb调试流程
- 首先使用gcc对test.c进行编译,注意一定要加上选项‘
-g
’ - 设置断点后程序在指定行之前停止。
- 只有在代码处于“运行”或“暂停”状态时才能查看变量值。
# gcc -g test.c -o test
# gdb test
命令 | 按键 |
---|---|
查看断点情况 | (gdb) info b |
单步运行 | (gdb) n/(gdb) s |
查看文件 | (gdb) l |
设置断点 | (gdb) b 6 |
查看变量值 | (gdb) p n |
运行代码 | (gdb) r |
恢复程序运行 | (gdb) c |
帮助 | (gdb) help [command] |
退出 | (gdb) q |
条件编译
编译器根据条件的真假决定是否编译相关的代码。
其语法如下:
#ifdef <macro>……#else……#endif
根据宏是否定义
定义:
根据宏的值
还有一种方式就是直接放数值0、1。
内存管理
C/C++定义了4个内存区间:
- 代码区/全局变量与静态变量区/局部变量区即栈区/动态存储区,即堆区。
静态存储分配
- 通常定义变量,编译器在编译时都可以根据该变量的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。
- 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
动态存储分配
有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为。
所有动态存储分配都在堆区中进行。
从堆上分配,亦称动态内存分配。程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
堆内存的分配与释放
当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。
堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化。
malloc/free
void * malloc(size_t num)
:分配空间
void free(void *p)
:释放空间
- malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
- malloc申请到的是一块连续的内存,有时可能会比所申请的空间大。其有时会申请不到内存,返回NULL。
- malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型。
- 如果free的参数是NULL的话,没有任何效果。
- 释放一块内存中的一部分是不被允许的。
注意事项:
- 删除一个指针p(
free(p);
),实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针。 - 动态分配失败。返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。
- malloc与free是配对使用的, free只能释放堆空间。如果malloc返回的指针值丢失,则所分配的堆空间无法回收,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存malloc返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。
野指针
不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的。 “野指针”的成因主要有两种:
- 指针变量没有被初始化。
- 指针p被free之后,没有置为NULL,让人误以为p是个合法的指针。指针操作超越了变量的作用范围。这种情况让人防不胜防。
Makefile
Make简介
工程管理器,顾名思义,是指管理较多的文件。
Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入Makefile文件的内容来执行大量的编译工作。
Make将只编译改动的代码文件,而不用完全编译。
Makefile基本结构
Makefile是Make读入的唯一配置文件。
- 由make工具创建的目标体(target),通常是目标文件或可执行文件。(生成什么)
- 要创建的目标体所依赖的文件(dependency_file)(由谁生成)
- 创建每个目标体时需要运行的命令(command)(怎么生成)
注意:命令行前面必须是一个“TAB键”,否则编译错误为:*** missing separator. Stop。
Makefile格式:
target : dependency_files<TAB> command
例子:
f1.c:
f2.c:
head.h:
main.c:
通过makefile生成一个目标代码文件:(.c->.o->obj)。
如果有一个文件和clean重命名,报make:'test' is up to date.
的话,我们可以加一行语句,生成一个假目标,就可以继续执行了:
创建和使用变量
创建变量的目的:用来代替一个文本字符串:
- 系列文件的名字
- 传递给编译器的参数
- 需要运行的程序
- 需要查找源代码的目录
- 你需要输出信息的目录
- 你想做的其它事情。
变量定义的两种方式
-
递归展开方式
VAR=var
它可以向后引用变量,但不能对该变量进行任何扩展,例如
CFLAGS = $(CFLAGS) -O
-
简单方式
VAR:=var
用这种方式定义的变量,会在变量的定义点,按照被引用的变量的当前值进行展开,这种定义变量的方式更适合在大的编程项目中使用,因为它更像我们一般的编程语言。
变量的使用:$(VAR)
。如果想用"$
“字符的话必须要用”$$
"。变量名一般大写。
用?=定义变量
dir := /foo/barFOO ?= bar
含义是,如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined)FOO = barendif
为变量添加值
可以通过+=
为已定义的变量添加新的值
Main=hello.o hello-1.o
Main+=hello-2.o
预定义变量
变量名 | 作用 |
---|---|
AR | 库文件维护程序的名称,默认值为ar。AS汇编程序的名称,默认值为as。 |
CC | C编译器的名称,默认值为cc。CPP C预编译器的名称,默认值为$(CC) –E。 |
CXX | C++编译器的名称,默认值为g++。 |
FC | FORTRAN编译器的名称,默认值为f77 |
RM | 文件删除程序的名称,默认值为rm -f |
ARFLAGS | 库文件维护程序的选项,无默认值。 |
ASFLAGS | 汇编程序的选项,无默认值。 |
CFLAGS | C编译器的选项,无默认值。 |
CPPFLAGS | C预编译的选项,无默认值。 |
CXXFLAGS | C++编译器的选项,无默认值。 |
FFLAGS | FORTRAN编译器的选项,无默认值。 |
自动变量
变量名 | 作用 |
---|---|
$* | 不包含扩展名的目标文件名称 |
$+ | 所有的依赖文件,以空格分开,并以出现的先后为序,可能 包含重复的依赖文件 |
$< | 第一个依赖文件的名称 |
$? | 所有时间戳比目标文件晚的的依赖文件,并以空格分开 |
$@ | 目标文件的完整名称 |
$^ | 所有不重复的目标依赖文件,以空格分开 |
$% | 如果目标是归档成员,则该变量表示目标的归档成员名称 |
环境变量
- make在启动时会自动读取系统当前已经定义了的环境变量,并且会创建与之具有相同名称和数值的变量
- 如果用户在Makefile中定义了相同名称的变量,那么用户自定义变量将会覆盖同名的环境变量
Make使用
直接运行make。
选项
-C dir
读入指定目录下的Makefile-f file
读入当前目录下的file文件作为Makefile-i
忽略所有的命令执行错误-I dir
指定被包含的Makefile所在目录-n
只打印要执行的命令,但不执行这些命令-p
显示make变量数据库和隐含规则-s
在执行命令时不显示命令-w
如果make在执行过程中改变目录,打印当前目录名
Makefile的隐含规则
隐含规则1:编译C程序的隐含规则
- “.o”的目标的依赖目标会自动推导为“.c”,并且其生成命令是“ ( C C ) – c (CC) –c (CC)–c(CPPFLAGS) $(CFLAGS)”
隐含规则2:链接Object文件的隐含规则
- “” 目标依赖于“.o”,通过运行C的编译器来运行链接程序生成(一般是“ld”),其生成命令是:“ ( C C ) (CC) (CC)(LDFLAGS) .o ( L O A D L I B E S ) (LOADLIBES) (LOADLIBES)(LDLIBS)”。这个规则对于只有一个源文件的工程有效,同时也对多个Object文件(由不同的源文件生成)的也有效。例如如下规则:
x : x.o y.o z.o
并且“x.c”、“y.c”和“z.c”都存在时,隐含规则将执行如下命令:
cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
如果没有一个源文件(如上例中的x.c)和你的目标名字(如上例中的x)相关联,那么,你最好写出自己的生成规则,不然,隐含规则会报错的。
比如:下面的test就会报错,而要用f1
或者f2
、main
。
.c会自动生成.o,把三个.o生成target。
VPATH的用法
VPATH : 虚路径
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。
Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:../headers
上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)
没用vpath:
用vpath:
Makefile的嵌套
下面是一个例子:
当前路径下的makefile文件:
当前目录下的所有文件和嵌套文件:
f1、f2、main下面的makefile文件内容:与下面类似。
这个执行过程就是当前下的makefile会把变量值export
传给各个嵌套文件夹下的makefile文件。就可以实现嵌套了。
执行结果:
相关文章:

04 linux之C 语言高级编程
gcc和gdb GNU工具 编译工具:把一个源程序编译为一个可执行程序调试工具:能对执行程序进行源码或汇编级调试软件工程工具:用于协助多人开发或大型软件项目的管理,如make、CVS、Subvision其他工具:用于把多个目标文件链…...

深入学习 Redis - Stream、Geospatial、HyperLogLog、Bitmap、Bitfields 类型扩展
目录 前言 Stream geospatial HyperLogLog Bitmaps Bitfields 前言 redis 中最关键的五个数据类型 String、List、Hash、Set、Zset 应用最广泛,同时 redis 也推出了额外的 5 个数据类型,他们分别是针对特殊场景才进行的应用的. Ps:这几种…...

Windows11+Opencv+Clion编译源码
Windows11OpencvClion编译源码 参考:https://www.robotsfan.com/posts/69395e08.html 注意事项 编译过程中使用的软件,开源码等所有工具的安装路径一定不要有中文和空格。cmake过程会下载一些文件,如果是局域网的话可能下载不下来…...

【机器学习】Cost Function
Cost Function 1、计算 cost2、cost 函数的直观理解3、cost 可视化总结附录 首先,导入所需的库: import numpy as np %matplotlib widget import matplotlib.pyplot as plt from lab_utils_uni import plt_intuition, plt_stationary, plt_update_onclic…...

【黑马头条之内容安全第三方接口】
本笔记内容为黑马头条项目的文本-图片内容审核接口部分 目录 一、概述 二、准备工作 三、文本内容审核接口 四、图片审核接口 五、项目集成 一、概述 内容安全是识别服务,支持对图片、视频、文本、语音等对象进行多样化场景检测,有效降低内容违规风…...

回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图)效果一览基本介绍程序设计参考资料效果一览 基本介绍 MATLAB实现GRNN广义回归神经网络多输入单输出回归…...
STM32 HAL库函数——HAL_UART_RxCpltCallback()详解
HAL_UART_RxCpltCallback函数 他是谁,他和谁有关功能用法每收到一个字符,就自动调用一次??示例----接收未知长度的字符 他是谁,他和谁有关 HAL_UART_RxCpltCallback 是一个回调函数,用于在使用 HAL 库进行…...

前端调用合约如何避免出现transaction fail
前言: 作为开发,你一定经历过调用合约的时候发现 gas fee 超出限制,但是不知道报了什么错。这个时候一般都是触发了require错误合约校验。对于用户来说他不理解为什么一笔交易会花费如此大的gas,那我们作为开发如何尽量避免这种情…...
选择器的使用
目录 层级选择器属性选择器伪类选择器结构伪类选择器目标伪类选择器 层级选择器 /*子代选择器:选出box下的所有li标签*/.box>li{background-color: aliceblue;}/* 选出box后面的第一个兄弟li标签 */.boxli{background-color: aliceblue;}/* 选出box后面的所有兄…...

软考A计划-系统集成项目管理工程师-项目干系人管理-上
点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 👉关于作者 专注于Android/Unity和各种游…...

F5 LTM 知识点和实验 2-负载均衡基础概念
第二章:负载均衡基础概念 目标: 使用网页和TMSH配置virtual servers,pools,monitors,profiles和persistence等。查看统计信息 基础概念: Node一个IP地址。是创建pool池的基础。可以手工创建也可以自动创…...

安全学习DAY08_算法加密
算法加密 漏洞分析、漏洞勘测、漏洞探针、挖漏洞时要用到的技术知识 存储密码加密-应用对象传输加密编码-发送回显数据传输格式-统一格式代码特性混淆-开发语言 传输数据 – 加密型&编码型 安全测试时,通常会进行数据的修改增加提交测试 数据在传输的时候进行…...

OpenCloudOS 与PolarDB全面适配
近日,OpenCloudOS 开源社区签署阿里巴巴开源 CLA (Contribution License Agreement, 贡献许可协议), 正式与阿里云 PolarDB 开源数据库社区牵手,并展开 OpenCloudOS (V8)与阿里云开源云原生数据库 PolarDB 分布式版、开源云原生数…...
如何在Linux系统中使用yum命令安装MySQL
1、安装软件 # yum install -y https://repo.mysql.com//mysql80-community-release-el7-8.noarch.rpm # yum -y install mysql-community-server网址来源:https://dev.mysql.com/downloads/repo/yum/ 2、启动软件 # systemctl enable mysqld# systemctl start my…...

在Ail Linux中手动配置IPv6
第一步,登录阿里云服务器控制台,在“概览”页面找到对应实例,然后单击实例ID。 第二步,在“实例详情”页面中的“网络信息”栏目中,可以发现“IPv6 地址”中没有数据,然后单击“专有网络”的专有网络ID。 第…...

TCP如何保证服务的可靠性
TCP如何保证服务的可靠性 确认应答超时重传流量控制滑动窗口机制概述发送窗口和接收窗口的工作原理几种滑动窗口协议1比特滑动窗口协议(停等协议)后退n协议选择重传协议 采用滑动窗口的问题(死锁可能,糊涂窗口综合征)死…...

【云原生系列】openstack搭建过程及使用
目录 搭建步骤 准备工作 正式部署OpenStack 安装的过程 安装组件如下 登录页面 进入首页 创建实例步骤 上传镜像 配置网络 服务器配置 dashboard配置 密钥配置免密登录 创建实例 绑定浮动ip 免密登录实例 搭建步骤 准备工作 1.关闭防火墙和网关 systemctl dis…...

无涯教程-jQuery - Menu组件函数
小部件菜单功能可与JqueryUI中的小部件一起使用。一个简单的菜单显示项目列表。 Menu - 语法 $( "#menu" ).menu(); Menu - 示例 以下是显示菜单用法的简单示例- <!doctype html> <html lang"en"><head><meta charset"utf-…...
Django用户登录验证和自定义验证类
一、FBV 用户登录验证 1.1 登录验证并加入 session 用户登录时,使用 authenticate 验证用户名和密码是否正确,正确则返回一个用户对象。 用户名默认的字段名是 username 密码默认的字段名是 password 将已验证的用户添加到当前会话(session)中&#x…...

json-server详解
零、文章目录 json-server详解 1、简介 Json-server 是一个零代码快速搭建本地 RESTful API 的工具。它使用 JSON 文件作为数据源,并提供了一组简单的路由和端点,可以模拟后端服务器的行为。github地址:https://github.com/typicode/json-…...

MacOS Monterey VM Install ESXi to 7 U2
一、MacOS Monterey ISO 准备 1.1 下载macOS Monterey 下载🔗链接 一定是 ISO 格式的,其他格式不适用: https://www.mediafire.com/file/4fcx0aeoehmbnmp/macOSMontereybyTechrechard.com.iso/file 1.2 将 Monterey ISO 文件上传到数据…...

哈工大计算机网络课程网络安全基本原理详解之:消息完整性与数字签名
哈工大计算机网络课程网络安全基本原理详解之:消息完整性与数字签名 这一小节,我们继续介绍网络完全中的另一个重要内容,就是消息完整性,也为后面的数字签名打下基础。 报文完整性 首先来看一下什么是报文完整性。 报文完整性…...
K8s:K8s 20个常用命令汇总
写在前面 博文内容为节译整理,用于温习理解不足小伙伴帮忙指正 对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式࿰…...

DHCP防护原理
电脑刚连接到网络 是没有IP地址的 。 通过发送广播到DHCPO服务器。 DHCP服务器响应对应的 IP地址(简要过程)。 如果有人私自挂接WIFI,相当于DHCP服务器,但这个DHCP服务器是假的,就会引起电脑接入获取家用WIFI的地址&…...
leetcode2434. 使用机器人打印字典序最小的字符串 出栈顺序 贪心+栈
https://leetcode.cn/problems/using-a-robot-to-print-the-lexicographically-smallest-string/ 给你一个字符串 s 和一个机器人,机器人当前有一个空字符串 t 。执行以下操作之一,直到 s 和 t 都变成空字符串。请你返回纸上能写出的字典序最小的…...

【程序设计】一文讲解程序设计目标:高内聚,低耦合
前言 软件设计的目标是高内聚、低耦合。 如果代码是高耦合和低内聚的,就会出现修改一个逻辑,会导致多处代码要修改,可能影响到多个业务链路,这增加了出bug的业务风险,同时增加了测试回归的范围,导致研发成…...

nginx mirror代码分析
实现方式 mirror逻辑的工作阶段: ngx在log phase之后(在ngx_http_free_request处调用)已完成向client端返回response,在log phase之后完成close connection(短链接),在该阶段处理mirror逻辑不…...
Python代理模式介绍、使用
一、Python代理模式介绍 Python代理模式(Proxy Pattern)是一种结构型设计模式。在代理模式中,代理对象充当了另一个对象的占位符,以控制对该对象的访问。 代理对象和被代理对象实现了相同的接口,因此它们可以互相替代…...

《MySQL45讲》笔记—索引
索引 索引是为了提高数据查询效率,就像书的目录一样。如下图,索引和数据就是位于存储引擎中: 索引常见模型 哈希表 以键值对存储的数据结构。适用于只有等值查询的场景。 有序数组 在等值查询和范围查询场景中性能都特别优秀。但是有…...
Android usb host模式通信示例
当使用Android设备作为USB主机时,可以使用Android提供的USB API来进行USB通信。下面是一个简单的Android USB通信的示例。在这个示例中,我们将发送一条消息到连接的USB设备并从USB设备接收响应。 首先,在AndroidManifest.xml文件中添加以下权…...