乱码三千 – 分享实用IT技术

乱码三千 – 码出一个新世界


  • 首页

  • 归档

  • 搜索

GDB与GDBServer配合实现在安卓设备中进行程序调试

发表于 2021-01-30

实验环境

  • windows开发平台

  • 安卓模拟器(ARM架构+linux系统 已Root):

    可以通过adb shell getprop指令查看当前设备的cpu架构

  • arm-linux-androideabi编译工具 gdb和gdbserver皆存放在此开发包下

实验开始

第一步 编写测试代码 文件名为test.c

1
2
3
4
5
6
7
#include <stdio.h>

int main(){
char *a="he"
printf("hello pangshu");
return 0;
}

第二步 将测试代码编译成可执行文件

1
arm-linux-androideabi-gcc.exe -g test.c -o main -static #输出可执行文件名为main

第三步 将可执行文件传送到模拟器中

1
adb push main /data/local/tmp

第四步 将gdbserver工具传送到模拟器中

1
adb push gdbserver /data/local/tmp

第五步 进入模拟器shell窗口,使用gdbserver执行程序

1
./gdbserver 192.168.177.71:23946 main #这里的ip是宿主机的ip  23946为监听端口

第六步 在宿主机中运行gdb工具

1
gdb.exe main  #这里需要指定调试的执行文件

此时进入到gdb模式

第七步 在gdb模式下连接模拟器中的gdbserver

1
(gdb) target remote 192.168.0.1:23946  #这里的ip是模拟器的ip

连接成功后进入断点调试模式,该模式下可以使用~调试指令进行相关调试

开始调试

  1. 使用list指令列出所有源代码 可简写为l

    1
    (gdb) l
  2. 使用break指令设置断点位置 可简写为b

    1
    (gdb) b main #在main函数处打断点
  3. 使用continue指令运行到断点处 可简写为c

    1
    (gdb) c
  4. 使用step指令进行单步执行 可简写为s

    1
    (gdb) s   #会进入函数内部
  5. 使用next执行进行单步执行 可简写为n

    1
    (gdb) n  #不会进入函数内部
  6. 使用print指令打印变量的值 可简写为a

    1
    (gdb) p a #打印变量a的值
  7. 使用quit指令退出调试模式 可简写为q

    1
    (gdb) q

更多调试指令

GCC调试工具GDB的常用指令

关于arm-linux-androideabi的获取

建议下载Android NDK开发包,然后将里面的GCC套件单独抽出来使用,NDK提供了抽包脚本make-standalone-toolchain,在bulid目录的tools文件夹中可以找到,执行脚本自动抽取打包成压缩包到当前目录:

1
python make-standalone-toolchain.py --arch arm

附加

如果是在非安卓系统的ARM模拟器上,比如qemu模拟器,那么直接使用官方的arm-none-linux-eabi即可,即便是安卓设备,如果没有代码调试需求的话,仅仅是编译运行程序,也是完全够用了

但是你需要进行代码调试的话,由于android系统的安全策略,arm-none-linux-eabi包中的gdbserver无法运行,提示:

1
error: only position independent executables (PIE) are supported.

为了解决这个问题,我们因此采用arm-linux-androideabi,这里面的gdbserver可以正常运行

上面的例子中使用的NDKr17的版本

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Makefile的详细介绍和使用

发表于 2021-01-29

待完善。。。

makefile详细介绍和使用

Makefile定义规则

参考链接1:https://seisman.github.io/how-to-write-makefile/invoke.html

参考链接2:https://www.cnblogs.com/LittleHann/p/3855905.html

规则是makefile中最重要的概念,其告诉make 目标文件的依赖关系,以及如何生成及更新这些目标文件。在makefile文件规则有2种,一种是显式规则,另一种是隐式规则。

  1. 显示规则

显式规则用于说明何时及如何重新生成目标,其列出了目标依赖的文件信息,并通过调用命令来创建或更新目标,其语法一般为:

1
2
3
4
targets : prerequisites

recipe
…
  • targets:为要生成或更新的目标

  • prerequisites:为目标依赖的关系

  • recipe:为生成目标的命令,

    一个规则可以有多条recipe,比如

    1
    2
    3
    foo.o : foo.c defs.h

    cc -c -g foo.c

其中foo.o为target,foo.c defs.h 为prerequisites,cc -c -g foo.c为recipe。

示例讲解

1
2
3
4
5
6
7
8
9
10
test:main.o channle.o
gcc main.o channle.o -o test
main.o:main.c function.h
gcc -c main.c -o main.o
channle.o:channle.c WavHead.h
gcc -c channle.c -o channle.o -std=c99

.PHONY:clean
clean:
-rm -rf *.o

执行的过程简单说就是最终需要生成一个名为test的文件,这个文件需要main.o和channle.o,于是继续往下执行,然后通过命令gcc -c main.c -o main.o得到了main.o文件,同理再得到channle.o文件,最后通过命令gcc main.o channle.o -o test进行链接最终就会得到一个名为test的可执行文件了。

上面的代码在linux的命令窗口下输入make命令就可以执行了,最终会生成一个test的可执行文件。 如果需要清除生成的中间.o文件,输入make clean就可以全部清除了。

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

GCC工具的具体使用

发表于 2021-01-29

编译工具链

高级语言翻译成机器语言不是一步到位的,以C语言为例,通常要经历以下四个步骤:

1
2
3
预处理--->编译--->汇编--->连接

源代码--->汇编代码--->目标代码--->可执行程序

每一步都需要使用不同的工具,比如源代码需要借助编译工具翻译成汇编代码,汇编代码需要借助汇编器翻译成目标代码,最后还要借助连接器帮忙整理汇总, 那么这些个工具集合到一块就叫做工具链

GCC工具链

由GNU提供的一整套的工具集,这套工具集中包含了汇编器,编译器和链接器,二进制转换,调试工具等

通过GCC,我们可以一步完成源码到可执行文件的编译, 也可以单步独立进行,方便程序员获取中间代码代码,进行调试

GCC常用命令选项

假设只编译单个源文件test.c

  1. 无选项编译

    1
    2
    3
    gcc test.c  
    或者
    gcc test.o

    在当前目录下直接生成可执行文件,默认名称为a.out

  2. 选项-o

    1
    gcc test.c  -o test

    在当前目录下生成名为test的可执行文件

  3. 选项-E

    1
    gcc -E test.c  -o test.i

    在当前目录下生成名为test.i的预处理文件

  4. 选项-S

    1
    gcc -S test.c  -o test.s

    在当前目录下生成名为test.s的汇编文件,将源码转成汇编代码

  5. 选项-c

    1
    gcc -c test.c

    在当前目录下生成名为test.o的目标文件

  6. 选项-O数字

    1
    gcc -O1 test.c  -o test

    在当前目录下生成名为test的可执行文件,并且使用编译优化级别1编译程序。可选级别为1~3,级别越大优化效果越好,但编译时间越长。

多文件编译

比如一个汇编文件aaa.s一个C源文件test.c:

  1. 方式一 多文件同时编译

    直接追加文件名进行同时编译输出即可

    1
    gcc aaa.s test.c -o bbb

    如果要编译的文件都在同一个目录下,可以用通配符gcc *.c -o 来进行编译

  2. 方式二 多文件分开编译

    首先将源文件编译成目标文件

    1
    2
    3
    gcc -c aaa.s  //生成aaa.o

    gcc -c test.c //生成test.o

    然后将所有目标文件连接成可执行文件

    1
    gcc  test.o aaa.o -o test
  3. 方式三 编写makefile文件进行编译

    第一步 makefile文件编写

    1
    2
    3
    4
    # 我是注释
    SRC=aaa.s test.c
    main: $(OBJS) #指定需要生成的文件名称以及相应的依赖关系
    gcc -o main $(SRC) #生成所需要的指令

    第二步 使用bin包下的cs-make工具,直接在命令窗口中执行该指令,默认在当前目录虚招makefile文件

    1
    # cs-make

    该指令实际上执行的就是makefile中我们编写的指令gcc -o main aaa.s test.c

以上三种方法相比较,第一中方法编译时需要所有文件重新编译,而第二种方法可以只重新编译修改的文件,未修改的文件不用重新编译 ,第三种方法适用于文件较多依赖关系复杂的工程编译

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

汇编语言之行x86_32汇编

发表于 2021-01-28

两大汇编语法

两种语法主要是针对x86架构汇编而言,对于其他架构没有这么一个说法

  • Intel型语法: Intel官方语法,在Windows平台原生环境中采用该语法
  • AT&T型 :非Intel官方语法,在Unix/Linux的GCC编译环境中采用该语法

原生环境搭建

  • windows系统
  • RedAsm集成工具

指令和语法

在让我们看看 x86_64 平台提供了哪些寄存器给我们使用,

  • 16个通用寄存器,例如,rax,rbx,rcx,rdx等
  • 6个16位段寄存器,例如:cs,ds,等

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

GCC工具链都包含哪些工具

发表于 2021-01-27

GCC

GCC原名为GNU C语言编译器(GNU C Compiler),原本只能处理C语言。后来随着功能的扩展,支持的语言种类越来越多 ,故更名为GCC(GNU Compiler Collection,GNU编译器套件)

因此 GCC既可以指代C编译器,也可以指代GNU编译套件

其套件囊括了许多子工具:

  • gcc: C 编译器

  • g++: C++ 编译器

  • cpp: C 预处理器

  • as: 汇编器

  • ld: 连接器

  • objcopy: 目标文件翻译器,用于从连接器输出中创建一个ROM 映像

  • objdump: 目标文件阅读器, 用于反汇编目标文件

  • make: make 工具

  • gdb: 源代码调试器

GCC工具链

一个程序从代码编译到机器执行,中间需要经历很多步骤,比如从预编译,编译,到汇编和连接, 这一系列环环相扣过程中涉及到的GNU工具集,称之为GCC工具链

在windows平台中,我们有许多的图形化IDE可以选择,一般编译工具链都集成进了软件内部,无需开发者关心,但是在Linux平台,基本以命令行的方式进行操作,那么对于开发者来说,需要了解每个工具的作用和具体使用方法

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

汇编语言之GNU ARM

发表于 2021-01-25

什么是GNU

GNU最开始其实是一个操作系统,旨为打造一个开源免费自由的操作系统,目前操作系统还在完善中

GNU计划: 最初目标是创建一套完全自由的操作系统GNU 和相应的软件

GCC :(GNU Compiler Collection)GNU编译器套件,GNU提供的一整套的工具集,这套工具集中包含了汇编器,编译器和链接器,二进制转换,调试工具等

GCC优势:

  • 免费开源
  • 贴近系统底层,功能强大,灵活性高
  • 跨平台,方便交叉编译

GCC劣势:

  • 工具基本采用命令行方式,学习和使用门槛较高

接下来我们要学习的就是GNU计划众多的产物之一GNU FOR ARM

汇编器与指令集

  1. 什么是汇编器

    将汇编语言翻译成机器码的工具

  2. 什么是编译器

    将高级语言翻译成机器语言或者汇编语言的工具

  3. 汇编器和编译器的区别

    汇编器的服务对象是汇编语言,编译器的服务对象是高级语言

  4. 汇编器和汇编语法伪指令的关系

    不同的CPU对应不同的指令集 ,不同的汇编器对应不同的伪指令集和汇编语法。

    每种汇编器都可以有自己的伪指令集和自己的语法

使用不同的汇编器汇编同一个cpu架构的汇编代码,所对应的指令绝对是一致的,但伪指令各有千秋

1
2
3
4
5
6
7
8
9
;使用ARM官方的汇编器
AREA test, CODE
mov R3,#5
END

;使用GNU的汇编器
.text ;伪指令
mov R3,#5 ;传送指令皆为mov
.end

常见的汇编器

  • MASM汇编器:微软旗下专为x86架构打造的一款汇编器,支持8086汇编和win32汇编
  • GNU汇编器 : 简称为GAS,是GNU旗下的一款免费开源跨平台汇编器其子集中包含了支持多种架构的汇编器,比如GNU FOR ARM就是单独面向ARM架构的汇编器,此外还有GNU FOR X86等
  • NASM汇编器: 是一款面向x86架构的汇编器,支持8086汇编和win32汇编,同时可跨平台, 免费开源
  • ARMASM汇编器:ARM官方原生的汇编器,集成在了ADS工具上,适用于ARM架构,我们也一般称之为ADS汇编器

两种ARM汇编器的各自用途

  • ARMASM汇编器:一般用于windows平台
  • GAS汇编器:支持windows平台和linux平台,方便跨平台交叉编译

由于移动设备如安卓和iphone底层都是采用GNU的编译环境,我们如果要进行移动端的开发,那么势必需要掌握GNU ARM, 同时和ADS和KEIL收费工具相比,GUN工具全部免费,方便开发者进行使用

如果你是从事android开发,有兴趣可以去翻NDK r17以下版本的库,里面用的编译工具就是GCC

GNU ARM开发环境搭建

我们需要准备以下两个工具:

  1. GCC编译套件
  2. 安卓模拟器

GCC编译套件根据cpu架构和操作系统的不同,又分为了很多子类:

  • 纯ARM裸机: 对应arm-none-eabi工具包
  • ARM架构+Linux操作系统:对应arm-none-linux-eabi工具包

由于接下来我们选择在安卓模拟器上进行开发学习,因此我们选择arm-none-linux-eabi这套工具来进行代码的编译

工具下载

GCC工具的具体使用

伪指令和伪操作

  1. 注释

    1
    @我是注释
  2. 段的声明

    • 代码段

      1
      2
      .text
      @代码
    • 数据段

      1
      2
      .data
      @代码
  • 自定义一个段

    1
    .section .pangshu @定义一个名为.panghsu的段
  1. 函数或者标签的声明

    1
    2
    3
    fun:  @在GNU环境中标签后面需要加冒号,而原生环境则不用
    mov R0,#4
    bx lr
  2. 数据的声明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .byte @定义单字节数据,例如:.byte 0x14;
    .short @定义双字节数据,例如:.short 0x1000;
    .long @定义四字节数据,例如:.long 0x10001000;
    .quad @定义8字节,如:.quad 0x1234567890abcd;
    .float @定义浮点数,如:.float 0f-314159265358979323846264338327/95028841971.693993751E-40 @ -pi

    @字符串定义
    .string “abcd”, “efgh”, “hello!”
    .asciz “qwer”, “sun”, “world!”
    .ascii “welcome/0”
    @需要注意的是:.ascii伪操作定义的字符串需要自行添加结尾字符’/0’。
  3. 数据的批量定义

    • 格式如下:

      1
      2
      3
      .rept @重复次数
      @数据定义代码
      .endr @结束重复定义
    • 示例

      1
      2
      3
      .rept 3
      .byte 0x23
      .endr
  4. 关于align

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    .global _start
    _start:
    mov r0, #0x12

    .byte 0x12
    .byte 0x34

    ;.align 后跟为0,1,2或者不跟参数时都当作是4字节对齐
    .align
    .byte 0x56

    ; 2^3次方,8字节对齐
    .align 3
    .word 0x1

    ; 2^5次访,32字节对齐
    .align 5
    .word 0x2

    ; 填充0x12345678,直到16字节对齐
    .balignl 16,0x12345678

    ;字符串
    .ascii "abc123"

    .align
    ;.ascii和.asciz的区别是,.asciz会在字符串后自动添加结束符\0.
    .asciz "def456"

    mov r0, #0xab

    ;.balign[wl] align, fill_value, max_padding
    .align
    ; .balign 后跟的align参数必须为2的次方,否则会报错,按字节填充, fill_value要为字节
    .balign 8, 0x12

    ; .balignw 按2字节填充
    .balignw 8, 0x3456

    ; .balignl 按4字节填充
    .balignl 8, 0xabcdef01

    反汇编后的结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    00000000 <_start>:
    0: e3a00012 mov r0, #18
    4: 3412 .short 0x3412 // .byte 0x12 和 .byte 0x34
    6: 0000 .short 0x0000 // .align 引起的填充
    8: 00000056 andeq r0, r0, r6, asr r0 // .byte 0x56
    c: e1a00000 nop ; (mov r0, r0) // .align 3 8字节对齐
    10: 00000001 .word 0x00000001 // .word 0x1
    14: e1a00000 nop ; (mov r0, r0) // .align 5 ,32字节对齐
    18: e1a00000 nop ; (mov r0, r0)
    1c: e1a00000 nop ; (mov r0, r0)
    20: 00000002 .word 0x00000002 // .word 0x2
    24: 12345678 .word 0x12345678 // .balignl 16,0x12345678,填充0x12345678,直到16字节对齐
    28: 12345678 .word 0x12345678
    2c: 12345678 .word 0x12345678
    30: 31636261 .word 0x31636261 // .ascii "abc123"
    34: 3332 .short 0x3332
    36: 0000 .short 0x0000
    38: 34666564 .word 0x34666564 // .asciz "def456"
    3c: 3635 .short 0x3635
    3e: 00 .byte 0x00
    3f: e3a000ab mov r0, #171 ; 0xab // mov r0, #0xab, 这里就不对齐了
    43: 00 .byte 0x00
    44: 12121212 .word 0x12121212 // .balign 8, 0x12
    48: e1a00000 nop ; (mov r0, r0)
    4c: e1a00000 nop ; (mov r0, r0)
    50: e1a00000 nop ; (mov r0, r0)
    54: e1a00000 nop ; (mov r0, r0)
    58: e1a00000 nop ; (mov r0, r0)
    5c: e1a00000 nop ; (mov r0, r0)

指令和伪指令的区别

  • 指令: 有与之对应的机器码,能被cpu所识别,和编译器无关

  • 伪指令:没有与之对应的机器码,无法被cpu识别,只能被编译器识别,不同编译器伪指令不一样

    不同的CPU对应不同的指令集;不同的汇编器对应不同的语法和伪指令集

例子:ARM原生编译器和GNU FOR ARM

两种汇编器语法对比一览表

GNU ARM汇编 ADS ARM汇编
“@”或“/…/” “;”
.include GET
.equ EQU
.global EXPORT
.extern IMPORT
.long DCD
.end END
entry: ENTRY
.text AREA Init,CODE,READONLY
.data AREA Block,DATA,READWRITE
.macro MACRO
.endm MEND

汇编语言和C语言交互

1.引入其他源文件函数

使用import或者extern伪指令

1
2
3
4
5
6
7
8
9
;使用import伪指令
AREA code, CODE
import fun1 ;导入其他源文件中名为fun1的函数
END

;使用extern伪指令
AREA code, CODE
extern fun1
END

两者区别:

  • import:不管当前文件是否使用该引入的函数,该标签都会加入当前文件符号表,即为静态引用
  • extern:只有当前文件使用了该函数,才会将此标签加入符号表,即为动态引用

2.导出当前源文件中函数供其他文件访问

使用export或者global伪指令

1
2
3
4
5
6
7
8
;使用import伪指令
AREA code, CODE
export fun ;导出fun函数供其他源文件使用

fun
mov R0,#4
bx lr
END

3.外链汇编之C语言调汇编函数

第一步,在汇编原文件中将函数暴露出来给供外部调用,使用export或者global伪指令:

1
2
3
4
5
6
7
8
9
10
11
12
AREA code, CODE
export arm_strcpy ;或者使用global

arm_strcpy
loop
ldrb R4,[R0],#1 ;如果使用ldr 那么将偏移值改成4
cmp R4,#0
beq over
strb R4,[R1],#1
b loop
over
END

第二步,在C文件中引用汇编中的函数,C文件中只能使用extern伪指令:

1
2
3
4
5
6
7
extern arm_strcpy(char *src,char*des);

int main2(){
char *a="hello pangshu";
char b[64];
arm_strcpy(a,b);
}

4.外链汇编之汇编调c语言函数

第一步,在C文件中编写好函数

1
2
3
int c_sum(int a,int b){
return a+b;
}

第二步, 在汇编文件中引入函数,使用import或者extern伪指令

1
2
3
4
5
6
7
AREA code, CODE
import c_sum

mov R0,#1 ;第一个参数
mov R1,#2 ;第二个参数

END

第三步, 使用BL指令调用函数

1
2
3
4
5
6
7
AREA code, CODE
import c_sum

mov R0,#1 ;第一个参数
mov R1,#2 ;第二个参数
BL c_sum
END

在ARM中函数参数使用R0~R3这三个寄存器来进行传递,最多传递4个参数,超过4个参数使用栈进行处理,函数返回值通过R0进行传递

5.内嵌汇编

GNU内嵌汇编,格式如下:

1
2
3
4
5
6
7
int main2(){
__asm__( //大括号改成中括号
"mov R5,#0x00000005\n" //汇编指令需要使用引号包裹,多条语句之间使用回车换行符进行分隔
"mov R6,#0x00000005"
); //需要以分号结尾
return 0;
}

学习工具

  • 在线ARM汇编编辑器:https://azm.azerialabs.com/

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

视频帧率和码率对视频质量和文件大小的影响

发表于 2021-01-24

我们从画面流畅度,画面清晰度,和视频文件体积三个方面进行分析:

帧率(FPS)

指每秒显示图像的张数

比如30帧,表示每秒显示30张图像

帧率越大,画面越流畅,帧率越小,画面越卡顿,如果低到1帧/秒,那么就相当于一个幻灯片了

帧率不会影响到画面的清晰度,只会影响画面的流畅度和文件的体积,帧率越大,视频对应的体积越大

分辨率(resolution)

指像素点分布密度

比如24寸的显示器,设置1920x1080的分辨率,那就是横向由1920个像素点构成,纵向由1080个像素点构成,也就是说在屏幕尺寸固定的情况下,分辨率越高,画面越清晰细腻,反之,画面越模糊

分辨率不会影响画面的流畅度,只会影响画面的清晰度和文件的体积,分辨率越大,视频体积越大

码率(Bitrate)

指每秒传输的数据位数,单位kbps 即千位每秒 ,这里的位指的是二进制位

基本的算法是:

  • 每秒传输的数据量=码率/8

  • 视频文件体积=码率/8x视频时长(s) =每秒传输的数据量*视频时长(s)

比如500Kbps,也就是每秒传输62K大小的数据, 假如按照帧率30fps进行计算,那么每张图片大小约为2kb大小

也就是说视频时长固定的情况下,码率越高,文件体积越大,同时视频显示的有效像素越多,视频更加接近原始分辨率,反之,码率越低,文件体积越小,但是视频能显示的有效像素就越少,原本1080p的分辨率,每帧图像至少需要占用20k的数据量,但是码率过低每帧只能分配2K的量,此时像素点显示不全,就会造成视频模糊不清晰

因此,码率若是过低,再高的分辨率都拯救不了画质,反而会适得其反,

事实上,低码率环境下,低分辨率画面要比高分辨率画面更加清晰

码率不会影响画面的流畅度,但是会影响画面的清晰度和文件的体积

我们的需求

我们一般追求高清流畅的画质,同时文件体积尽可能小,那么该如何找到帧率 码率和分辨率三者的平衡点呢?

首先在我们录制视频的时候,屏幕的分辨率一般是固定的,随着不同的电脑分辨率也不同(当然你要手动调整也行)

其次,为了保证视频的流畅度我们一般将帧率设置在25fps以上

那么我们想减小视频的体积的话,只能从码率入手了, 找到一个画质能接受,体积小的平衡点

比如1980x1080的分辨率,我使用500kbps左右的码率,差不多可以接受,OBS在录制时默认也是在这个码率内来回波动

以下是常见分辨率和码率之间平衡参考表:

举例:如果要想百分百还原1080p HQ的画质,至少需要5.76Mkpbs码率的支撑,如果是直播的话需要至少9M的宽带才能稳定传输对应的数据量,否则画面卡顿

直播中,在分辨率和网速一定的情况下,我们会适当降低码率,牺牲部分清晰度的来保证视频的流畅性

如果网速不行又希望画面还清晰流畅,那么就降低拍摄的分辨率,同时降低数据传输量也就是码率值,当然分辨率降低之后所谓的视频清晰度也只是相对的,凡事总有取舍

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

关于mysql崩溃之error establishing a database connection

发表于 2021-01-22

起因

最近在进行网站检查的时候突然发现我的一个子网站挂了,提示error establishing a database connection, 如果是网站刚建立那好解决,80%的概率是数据连接参数不正确,或者是数据库端口没有开放

但是我这个网站运行很长一段时间了,之前一直好好的,突然之间就挂了, 而且这个数据库我使用的是docker进行维护,同时,在同一个mysql容器中我放置了好几个网站的数据,其他网站运行却是正常的

而且我通过第三方连接数据库的工具可以正常连接到被挂网站的数据库

通过以上情况可以排除以下原因:

  • mysql容器没有问题
  • 数据库端口和连接参数也没问题(已经检查过配置文件,没有被外部篡改过)
  • 网站程序正常运行

这种情况下该如何处理呢? 当然是找日志了

第一步:查看主程序日志,没问题

第二步:查看mysql容器日志,发现问题

1
docker logs --tail=50 mysql

Table './wordpress_wai/wp_options' is marked as crashed and should be repaired when using LOCK TABLES

数据库没有问题,但是表有问题

解决方案

对表进行修复即可:

首先登录mysql选择指定的数据库,然后执行以下命令:

  1. 执行修复指令

    1
    repair table wp_option
  2. 检查表的状态

    1
    check table wp_option

修复前最好先备份数据库

1
mysqldump -uroot -p密码 数据库名 >xxxxx.sql

如果表损坏比较严重,可能无法备份数据库

如果你不知道如何查看mysql日志,那么直接运行备份数据库指令,也能帮你检查数据库是否存在问题

修复完成后无需重启mysql容器, 直接刷新网址即可正常访问

2021年9月1日补充

突然数据库又崩了, 网站同样提示error establishing a database connection

我查看docker日志 报如下错误:

1
Database page corruption on disk or a failed file read of page [page id: space=0, page number=5]. You may have to recover from a backup

此时mysql容器已经进不去了, 百度了一下说是数据库受损 要在my.cnf配置文件中添加innodb_force_recovery=1

可是我在conf目录下并没有找到my.cnf文件 不知道是被谁给删了 难道被入侵了

只好新建一个配置文件看看可不可行

1
vim my.cnf

然后将以下内容拷贝进去:

1
2
3
4
5
6
7
8
9
10
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

# Custom config should go here
!includedir /etc/mysql/conf.d/

wq保存退出 然后重启mysql容器, 重新访问网站 还是不行

紧接着我在配置文件末尾添加了innodb_force_recovery=1

1
2
3
4
5
6
7
8
9
10
11
12
13
[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
secure-file-priv= NULL
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

# Custom config should go here
!includedir /etc/mysql/conf.d/


innodb_force_recovery=1

保存重启后, 网站正常访问, 问题解决

但是mysql容器日志一直提示:

1
[ERROR] [MY-012803] [InnoDB] innodb_force_recovery is on. We do not allow database modifications by the user. Shut down mysqld and edit my.cnf to set innodb_force_recovery=0

于是我把innodb_force_recovery值设为0 网站没问题 暂且就这样

关于innodb_force_recovery参数

  • Mode 1当遇到损坏页时,不使 MySQL 崩溃
  • Mode 2不运行后台操作
  • Mode 3不会尝试回滚事务
  • Mode 4不计算统计数据或应用存储/缓冲的变化
  • Mode 5在启动过程中不查看撤消日志
  • Mode 6在启动时不从重做日志(ib_logfiles)前滚

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

GCC调试工具GDB的常用指令

发表于 2021-01-20

常用指令

  1. 进入调试模式

    1
    gdb 可执行文件
  2. 如果忘了指定调试文件可以使用file指令指定

    1
    (gdb) file 文件名
  3. 使用quit指令退出调试模式 可简写为q

    1
    (gdb) q
  4. 使用start指令开始调试 停在第一行代码处

    1
    (gdb) start
  5. 使用step指令进行单步执行 可简写为s

    1
    (gdb) s   #会进入函数内部
  6. 使用next执行进行单步执行 可简写为n

    1
    (gdb) n  #不会进入函数内部
  7. 汇编级别单步执行(上面n和s为c语言级别单步指令)

    1
    2
    (gdb) ni #不进入函数内部
    (gdb) si #会进入函数内部
  8. 使用list指令列出所有源代码 可简写为l

    1
    (gdb) l
  9. 使用break指令设置断点位置 可简写为b

    1
    2
    3
    4
    5
    (gdb) b main #在main函数处打断点
    (gdb) b 10 #在第十行位置打断点
    (gdb) b test:10 #在test文件的第十行位置打断点
    (gdb) b 0x3400a #在0x3400a内存位置打断点
    (gdb) b 10 if i==3 #设置条件断点 i等于3时在第十行位置打断点 适用于循环
  10. 使用delete+断点编号指令删除断点 可简写为d

    1
    (gdb) delete 3 #删除编号为3的断点  清除时GDB不会给出任何提示
  11. 使用 clear+断点行号指令清除断点

    1
    (gdb) clear 3 #清除第三行的断点  清除时GDB会给出提示
  12. 使用 disable/enable + 断点编号 指令冻结或启动断点

    1
    disable 3,4 #冻结编号为3和4的断点 多个断点使用逗号分隔
  13. 使用info break指令查看断点的情况

    1
    (gdb) info break
  14. 使用 tbreak 指令设置临时断点

    1
    (gdb) tbreak 行号/函数名 #设置临时断点,到达后被自动删除
  15. 使用 awatch/watch + 变量 设置变量读写观察点

    1
    2
    (gdb) awatch/watch a #当变量a被读出或写入时程序被暂停 
    (gdb) rwatch a #当变量a被读出时程序被暂停
  16. 使用continue指令运行到断点处 可简写为c

    1
    (gdb) c
  17. 使用print指令打印变量的值 可简写为p

    1
    (gdb) p a #打印变量a的值
  18. 使用x指令打印指定内存地址数据

    1
    (gdb) x /6cb 0x804835c #打印地址0x804835c起始的内存内容,连续6个字节,以字符格式输出。
  19. 使用run指令运行整个程序 可简写为r

    1
    (gdb) r  #如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处
  20. 使用 call 指令直接运行某个函数

    1
    (gdb) call fun #在当前位置执行函数fun
  21. 使用display 指令设置需要跟踪的变量

    1
    (gdb) display a #跟踪变量a 每次断点到该处就显示该变量的值
  22. 使用 info display 显示当前所有跟踪的情况

    1
    (gdb) info display
  23. 使用undisplay+编号 指令取消对变量的跟踪

    1
    (gdb) undisplay 3 #取消对编号为3的跟踪事件
  24. 使用 set+ 变量 指令改变变量的值

    1
    (gdb) set i=3 #临时设置变量i的值为3
  25. 使用 set 指令设置运行时参数

    1
    (gdb) set i=3 #临时这只变量i的值为3
  26. 使用 show 指令查看运行时参数

    1
    (gdb) show i
  27. 使用 finish 指令函数结束

    1
    (gdb) finish
  28. 使用help指令查看指令使用说明

    1
    2
    (gdb) help print #查看print指令的解释说明
    (gdb) help #查看所有指令
  29. 使用info reg指令查看寄存器状态

    1
    (gdb)  info reg
  30. 使用 info stack指令查看堆栈状态

    1
    (gdb) info stack
  31. 运行shell指令

    1
    (gdb) shell ls   #运行shell指令ls。
  32. 其他指令

    1
    2
    3
    4
    5
    6
    7
    (gdb)  path #可设定程序的运行路径。 
    (gdb) show paths #查看程序的运行路径。


    (gdb)  cd   #相当于shell的cd命令。

    (gdb)  pwd  #显示当前的所在目录
  1. 使用回车重复上一条指令

本文为作者原创 转载时请注明出处 谢谢

img

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

视频教程录制计划

发表于 2021-01-17

技术视频

  1. 《Android进阶之逆向安全反编译视频教程-胖薯出品》

    • 录制时间 2020年11月6日
    • 部分视频观看:点击跳转
  2. 《Smali语言从入门到精通视频教程-胖薯出品》

    • 录制时间 2020年11月6日
    • 部分视频观看:点击跳转
  3. 《程序员进阶之三大架构汇编语言入门视频教程-胖薯出品》

    • 录制时间 2020年12月14日
    • 部分视频观看:点击跳转
  4. 《ARM汇编进阶之ARM64汇编视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  5. 《MIPS汇编进阶之MIPS64汇编视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  6. 《X86汇编进阶之Win32汇编视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  7. 《X86汇编进阶之Win64汇编视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  8. 《lua语言从入门到实战视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  9. 《硬件开发入门视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  10. 《从0到1打造一门属于自己的编程语言视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  11. 《从0到1开发一款操作系统视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  12. 《音乐制作之视唱练耳视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  13. 《虚幻游戏开发从0到1视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  14. 《音频插件开发视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  15. 《SO库的反编译视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:
  16. 《360和腾讯加固的原理和脱壳视频教程-胖薯出品》

    • 录制时间
    • 部分视频观看:

大家好 我已入驻面包多, 后续的付费教程会在上面发布 感谢大家的支持, 主页地址 : https://mbd.pub/o/newban/work

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

1…282930…51

乱码三千

android程序员一枚,擅长java,kotlin,python,金融投资,欢迎交流~

505 日志
145 标签
RSS
© 2026 乱码三千
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%