shadowsocks 配置

1. 安装shadowsocks

sudo apt-get install wget
wget -N —no-check-certificate https://raw.githubusercontent.com/ToyoDAdoubi/doubi/master/ssr.sh && chmod +x ssr.sh && bash ssr.sh

选择 google的BBR加速,依次输入以下代码,并回车即可。

wget —no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh
chmod +x bbr.sh
./bbr.sh
然后重新启动即可

shadowsocks 下载 地址

https://github.com/shadowsocks/shadowsocks-windows/releases



来源
https://ssvpns.com/5%E5%88%86%E9%92%9F%E6%90%AD%E5%BB%BA%E8%87%AA%E5%B7%B1%E7%9A%84%E7%BF%BB%E5%A2%99ss%E6%9C%8D%E5%8A%A1%E5%99%A8


Shell脚本编写规范

  1. Shell脚本在第一行会指出由哪个程序(解释器)来执行脚本中的内容
    一般为:#!/bin/bash 或 #! /bin/sh
  2. 跟在 # 后面的内容表示注释
    在shell脚本中尽量不用中文注释,尽量用英文注释
  3. Shell脚本的命名应以.sh为扩展名
    例如:1.sh
  4. 中括号[]两端至少要有1个空格,因此,键入中括号时即留出空格[ ],然后在退格键入中间内容,并确保两端都至少由一个空格
  5. for循环语句

for
do
内容
done

  1. if 条件

if 条件内容
then
内容
fi

  1. Shell 中的变量

变量就是用一个固定的字符串(也可能是字符、数字等的组合)代替更多、更复杂的内容,该内容里可能还会包含变量、路径、字符串等其他内容
变量的赋值方法为: 先写变量名称,紧接着是 “=” ,最后是值。中间无任何空格。 通过echo命令加上 $变量名,即可输出变量的值。 双引号,以防止出错变量的值一般要加上。
定义变量时变量名建议用大写,如 A=simplexue B=99
# 查看变量内容 echo $A 或 echo ${A}
A=str
echo $A
赋值时使用引号的作用

  • 双引号:允许通过$符号引用其他变量值
  • 单引号:禁止引用其他变量值,$视为普通字符
  • 反撇号:命令替换,提取命令执行后的输出结果 全局变量的定义方法 export 变量名

A=10
>>># B=$A+10 //10+10
>>># C=”$A+10” //10+10
>>># E=’$A+10’ //$A+10
>>># D=ls //ls输出的结果
位置参数
位置参数是一种在调用 Shell 程序的命令行中按照各自的位置决定的变量,是在程序名之后输入的参数。 位置参数之间用空格分隔,Shell取第一个位置参数替换程序文件中的 $1,第二个替换 $2 , 依次类推。$0 是一个特殊变量,它的内容是当前这个shell程序的文件名,所以 $0 不是一个位置参数
#! /bin/bash
A=$1
echo $(($A+$2))
B=$(($A+$1))
echo $B
————————————————————-
>>># bash 10 10
20
20
预定义变量
预定义变量和环境变量相类似,也是在Shell一开始就定义的变量,不同的是,用户只能根据shell的定义来使用这些变量,所有预定义变量都是由符号“$”和另一个符号组成。 常见的Shell预定义变量有以下几种。

  • $# :位置参数的数量
  • $* :所有位置参数的内容
  • $? :命令执行后返回的状态,0表示没有错误,非0表示有错误
  • $$ :当前进程的进程号
  • $! :后台运行的最后一个进程号
  • $0 :当前执行的进程名

! /bin/bash
echo $1
echo ${2}+${3}
echo $# #打印出位置参数的数量
echo $* #打印出位置参数的内容
echo $? #打印出命令执行后返回的状态
echo $$ #打印出当前进程的进程号
echo $0 #打印出当前进程的进程名

Shell脚本的条件测试

条件测试语句 说明
test 测试表达式 这是利用test命令进行条件测试表达式的方法
[测试表达式] 这是通过 中括号进行条件测试表达式 和test命令相同
[[测试表达式]] 这是通过 双中括号进行条件测试表达式 和test和[]更新的语法格式
&& 逻辑与
|| 逻辑或
expr 可用与整数运算,也还有其他功能

A=”hello”
expr length “$A” //计算A字符串的长度

文件测试操作符

常用文件测试操作符 说明
-d 文件存在且为目录则为真
-f 文件存在且为文件则为真
-e 文件存在则为真
-s 文件存在且大小不为0则为真
-r 文件存在且可读则为真
-w 文件存在且可写则为真
-x 文件存在且可执行则为真
-L 文件存在且为链接文件则为真
f1 -nt f2 文件f1比文件f2新则为真
12 -ot f2 文件f1比文件f2旧则为真

字符串测试操作符

常用字符串测试操作符 说明
-n 若字符串长度不为0,则为真
-z 若字符串长度为0,则为真
“字符串1” == “字符串2” 若字符串1等于字符串2,则为真
“字符串1” != “字符串2” 若字符串1不等于字符串2,则为真

注: == 和 != 两端要有空格 ,(())不能用于字符测试

逻辑操作符

在[]和test中使用的操作符 在[[]]和(())中使用的操作符 说名
-a && 与,两端都为真,才为真
-o || 或, 两端有一个为真,就为真
! ! 非, 两端相反,则结果为真

test 1 == 1 -a 2 == 2
[ 1 == 1 -a 2 == 2 ]

if 条件判断语句

单条件判断##############
if 条件判断
命令
else
命令
fi
#或
if 条件判断;then
命令
else
命令
fi
###双条件判断#####
if 条件判断
then
命令
elif 条件判断
then
命令
else
命令
fi

case 条件判断语句

case 变量 in
[1-9])
命令
;;
[a-z])
命令
;;
*) # 表示最后匹配
命令
esac

for循环语句

for ((i=1;i<=10;i++))
do
echo “循环$i”
done
for ((i=1;i<=10;i++));do
echo “循环$i”
done

while循环语句

i=0
while [$i -lt 10]
do
let i++
echo $i
done

命令 含义
read -p -s 等代用户输入 -p表示提示语 -s看不见输入内容
exit 退出指令
exprot 创建当前终端下的全局变量
PATH 记录命令执行时的默认是搜索路径

read name
echo “输入的是$name”
read a1 a2 a3 a4 //输入多个
read -p “请输入” a1 //就会在提升语后输入 而不是在下一行
read -sp “请输入密码” a1 //就会在提升语后输入 而不是在下一行 而且看不见输入内容




https://blog.csdn.net/qq_36119192/article/details/82964713


MakeFile

  • MakeFile 就是 自动化编译脚本

在Linux中把代码编辑成bin (二进制文件) 是使用gcc编译器
在Linux 中 它不关心文件后缀名,但 它的可执行文件后缀名为bin —elf 文件

MakeFile 工作原理

  • make / qmake / cmake
    在当前文件夹下去寻找makefile / Makefile 的文件去指导gcc去完成编译

    Gcc 参数

    | 参数 | 含义 | | —- | —- | | -c | 对文件进行编译 但是不链接 | | -o | 指定输出文件名 | | -g | 指定 输出文件为 Debug 版本 不加-g自动生成 Release 版本 | | -D | 允许从编译程序命令行定义宏符号 -Ddebug | | -I | 指定第三方头文件位置 | | -L | 指定链接库的搜索目录 -L/usr/lib | | -l(小L) | 指定链接库名字 -lqt | | -O | 指定优化等级 有 -O1 -O2 -O3 不可以特意使用 |

Linux 程序发布流程

  • 确定程序是否存在符号表
    readelf -s test-1
  • 导出符号表
    objcopy —only-keep-debug test-1 test-1.symbol
  • 生成发布版程序
    objcopy —strip-debug test-1 test-1-release
    strip test-1-release 再一次对发布版去除符号表
  • 使用符号表进行程序debug
    gdb -q —symbol=test-1.symbol —exec=test-1-release

查看符号表 symbol-file ./test-1.symol

elf生成过程

  1. 预编译:把.c 和.h 文件 预编译成 .i 文件
    • gcc -E -o hello.i hello.c
  • 预编译过程中会把:宏定义展开
    1. 把typedef展开
    2. 把条件预编译展开
    3. 把头文件包含到调用文件中去
  1. 汇编:.i生成 .s文件 .s 是汇编语言
    • gcc -S -o hello.s hello.i
  2. 编译:.s 生成 .o 但还不是可执行文件 还差一步链接
    • gcc -c -o hello.o hello.s 必须生成 .o文件
  3. 链接:生成可执行文件 ELF
    • 如果只有一个.c文件是可以不需要链接直接可执行的
    • gcc -o hello hello.o
      • 生成 hello 文件 用hello.o生成 什么都不加就是链接

        写MakeFile

        目标文件:依赖文件
        命令
        makefile 的文件名字必须是 makefile 或 Makefile 不可以是其他的文件名字 也没有后缀名
        命令 前面必须有 Tab 键
        语法意思是:用这个命令用依赖文件去生成目标文件
        但是:生成文件是顺序必须倒过来写 因为当makefile具有递归性,当上面没有找到文件时就会向下去寻找所以:
        hello:hello.o
        gcc -o hello hello.o
        hello.o:hello.s
        gcc -c hello.s -o hello.o
        hello.s:hello.i
        gcc -s hello.i -o hello.s
        hello.i:hello.c
        gcc -E hello.c -o hello.i
        Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。。。。。

        变量

        obj = 常量 变量名字按照C的命名规则来
        obj := 变量
        obj += 追加变量
        ${obj} 调用变量 {} () 都可以
        \ 换行符
        # 注释符
        objcet := hello.o word.o
        cc = gcc
        FLAG = -c
        hello.o:hello.c
        $(cc) $(FLAG) -o hello.o hello.c

        伪目标

        .PHONY: 伪目标标签
        filec = hello.o word.o
        .PHONY //在这个标签后面的都为伪目标
        clean:
        rm -rf ${filec}
        ~~~~~~~~~~~~
        命令行调用
        >>> make clean

        通配符

        % 代替一个文件
        * 代替所有文件
        匹配任意一个
        .PHONY //在这个标签后面的都为伪目标
        clean:
        rm -rf *.o //删除所有.o文件

        隐式规则

        隐式规则体现的编译器的智能性,
        直接用 .c 也可以生成出 .o文件 因为编译器真的已经帮助我们生成了.i .s文件
        只要编译结果名字一样 编译器就可以通过推断找到一样名字的 .c 文件编译

        自动变量

        $@ 代表目标文件
        $^ 代表依赖文件
        $< 代表第一个依赖文件
        cc = gcc
        %.o:%.c
        $(cc) -c -o $@ $^
        通过上面的添加就可以写出很简洁的makefile
        ————————————————————————————————————————————————————
        objcet:= wello.o word.o
        cc = gcc
        CFLAGS = -g -static
        DEFS = —D
        FLBS = -L/work/mylib/
        TARGET = helloword
        $(TARGET):$(object)
        $(cc) $(FLAG) $(DEFS) -o %@ %^ $(FLB)
        .PHONY
        clean:
        rm -rf *.o

        函数

        Makefile 中调用函数的方式是 $(函数名 参数)
  • wildcard 提取当前文件夹下所有参数的文件
    SRC = $(wildcard *.c) 提取当前文件夹下所有.c 的文件
  • patsubst 字符串替换函数
    OBJS = $(patsubst %.c,%.o,$(SRC))

含义是:
$(SRC) 代表内容池
把内容池中所有的 .c 文件替换成 .o 文件

  • 修改好后的makefile
    简洁 通用 以后使用只需要修改文件名字就行了 单目录版

SRC = $(wildcard .c)
OBJS = $(patsubst %.c,%.o,$(SRC))
cc = gcc
FLAG = -g -static
DEFS =
INCLUDE =
FLBS = -L/work/mylib/
TARGET = helloword
$(TARGET):$(object)
$(cc) $(FLAG) $(DEFS) -o %@ %^ $(FLB)
.PHONY
clean:
rm -rf
.o $(TARGET)

变量名含义

FLAG -g 是否为Dubug 版本
LIB -l 库文件

  • FIB -L/work/mylib/print.so 指定库路径

DEFS -D 宏定义
TARGET 目标文件
INCLUDE

编译多级目录

  • 使用 makefile.build 脚本进行编译

脚本在 TIM 文件夹中
本程序的Makefile分为3类:
1. 顶层目录的Makefile
2. 顶层目录的Makefile.build
3. 各级子目录的Makefile
一、各级子目录的Makefile:
它最简单,形式如下:
obj-y += file.o
obj-y += subdir/
“obj-y += file.o”表示把当前目录下的file.c编进程序里,
“obj-y += subdir/“表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。
注意: “subdir/“中的斜杠”/“不可省略
二、顶层目录的Makefile:
它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,主要是定义工具链、编译参数、链接参数──就是文件中用export导出的各变量。
三、顶层目录的Makefile.build:
这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o
详细的讲解请看视频。
四、怎么使用这套Makefile:
1.把顶层Makefile, Makefile.build放入程序的顶层目录
2.修改顶层Makefile
2.1 修改工具链
2.2 修改编译选项、链接选项
2.3 修改obj-y决定顶层目录下哪些文件、哪些子目录被编进程序
2.4 修改TARGET,这是用来指定编译出来的程序的名字
3. 在各一个子目录下都建一个Makefile,形式为:
obj-y += file1.o
obj-y += file2.o
obj-y += subdir1/
obj-y += subdir2/
4. 执行”make”来编译,执行”make clean”来清除,执行”make distclean”来彻底清除

特殊含义关键字

关键字 含义
override 覆盖变量
export 导出变量到全局

override OPENWRT_BUILD=1 //把 OPENWRT_BUILD 变量 重新赋值为1
export OPENWRT_BUILD //把OPENWRT_BUILD 导出到全局


GDB 调试基本命令

目标

  1. gdb FileName gdb 加上要调试的文件名
  2. 程序已经运行 在用gdb 挂接上去
  3. 使用 core 文件 启动程序

    GDB 基本命令

  • 想要调试的程序 在gcc 中必须加上 -g | l | 显示函数体内容 | | —- | —- | | b | 给程序下断点 | | info breakpoints | 查看当前程序下的断点 | | run | 运行程序 | | s set | 步进 进入函数中运行调试 | | n nest | 步出 不进入函数中调试 | | p | 查看变量信息 | | u | 跳出当前循环 | | info lpcals | 查看当前函数中所有局部变量的值 | | set listsize | 更换字体大小 | | x / n、f、u | 查看变量地址 | | bt | 查看函数当前函数是谁调用的 | | info frame | 打印栈所有信息 | | shell | 运行shell 命名 | | finish | 结束当前函数 | | disable | 停止断点 | | enable | 启动断点 | | file | 载入符号表 | | set args | 设置 程序进入参数 | | quit | 退出gdb | | display | 每次运行打印信息 | | commands bnum ~~end | 执行到某个断点执行commands bnum中的命令 |

list l
>>> gdb hello //启动gdb
gdb>> l main //显示main 函数内容
gdb>> list 4 //显示主程序前4行代码
gdb>> l hell:4 //显示主程序前4行代码
break
b 18 //在程序18行下断点
break 18 //在程序18行下断点
b 8 if sum>100 //在sum>100时在第8行停下 条件断点
b hello.c:18 if sum>100 //在hello.c文件中的第18行 当sum>100时在第18行停下 条件断点
b heClass::fun //在 heclass类中的fun函数设置断点 针对虚函数
print
x 按十六进制格式显示变量。 d 按十进制格式显示变量。 u 按十六进制格式显示无符号整型。c o 按八进制格式显示变量。 t 按二进制格式显示变量。 a 按十六进制格式显示变量。p/a i c 按字符格式显示变量。p/c i f 按浮点数格式显示变量。
p i //查看i变量的值c
p i=100 //把i的值改为100
p arr@24 //查看arr数组的24个元素
until u

set listsize
gdb>> set listsize20 //设置字体为20
*examine x

符代参数:

参数 含c义 助记
n 表示显示内存的长度 个数
f 表示显示的格式,跟print 的格式参数相同 单位
u 表示从当前地址往后请求的字节数 字符

u参数可以用下面的字符来代替
b表示单字节,h表示双字节,w表示四字节,g表示八字节
gdb>> x &i //查看i变量的内存地址
gdb>> x/d &i //查看i变量的内容地址的值为十进制
gdb>> x/10xw 0xffe74 //以十六进制查看10个四字节的地址
gdb>> x/100dw x //查看x数组的100个元素 用10进制四字节表示查看
shell
gdb>> shell pwd //在gdcb中运行shell命名
disable / enable c 暂时失效断点
gdb>> info breakpoints //查看当前断点ID号
Num Type Disp Enb Address What
1 breakpoint keep y 0x000055555555464e in main at hello.c:3
breakpoint already hit 1 time
gdb>> disable 1 //取消1号断点
gdb>> enable
gdb>>quit //退出gdb

导入符号表的方法

  1. 启动后在gdb里面导入

file ./hello.symbol

  1. 在启动gdb时导入

gdb —symbol-hello.symbol —exec-hello
1.启动后在gdb里面导入
gdb>> file ./hello.symbol
//在当前文件夹下导入hello.symbol 符号表,hello.symbol是用 objcopy —only-keep-debug 生成的
~~~~~~~~~~~~
2.在启动gdb时导入
shell#>> gdb —symbol-hello.symbol —exec-hello
—symbol 表示符号表文件
—exec 启动文件
set args
启动gdb后设置参数
gdb>> set atgs 10 20 30 40 // 传入 4个参数
gdb>> b 20 // 设置断点在20行出
gdb>> bt //查看当前函数调用栈
display
gdb>> display a //每次运行都打印a的值
gdb>> display 0x1024 //每次运行都打印地址的值
commands bnum ~~end
gdb>> b 20 //设置断点
gdb>> info breakpoints //查看断点id
1 breakpoint keep y 0x00005555555546ea in main at hello.c:15
breakpoint already hit 1 time
gdb>> commands 1 //在1号断点id出设置触发代码
> print a
> shell pwdc
> end //结束输入
geb>> run //运行


确定程序是否存在符号表

readelf -s 确定程序是否存在符号表
readelf -s hello //加上文件名

导出符号表文件

objcopy —only-keep-debug
objcopy —only-keep-debug hello hello.symbol
// 把hello的符号表导出成hello.symbol文件

用Debug程序生成Release 程序

objcopy—strip-debug
objcopy —srtip-debug hello hello.release
// 把Debug版的hello程序脱离符号表生成hello.release程序



GDB高级使用方法

GDB 观察点

是当某一个内存/变量被查看/修改时暂停到这个内存这个地址上

  • watch 地址
  • info watchpoints
  • rwatch

如果在局部变量于全局变量重名 他会按照就近原则来匹配
要观察全局就要加上函数名字和双分号
watch i // 在最近的i变量设置内容访问断点
watch main::i // 在main函数中的全局i变量设置内容访问断点
watch *0x10964 // 在0x10964这个内存上设置设置内容访问断点

捕捉点

可以设置捕捉点来捕捉程序运行时的一些事件,如:载入共享库(动态链接库)或是C++的异常。设置捕捉点的格式为:

  • catch | 作用 | 含义 | | | —- | —- | —- | | throw | 一个C++抛出的异常 | 只在C++程序中可以使用 | | catch | 一个C++捕捉到的异常 | 只在C++程序中可以使用 | | exec | 调用系统调用exec时 | exec 表示系统调用 如:在一个进程中启动另一个程序 | | fork | 调用系统调用fork时 | fork 表示创建进程 | | load/load | 载入共享库(动态链接库)时 | load 表示 载入新的库文件时 | | unload 或 unload | 卸载共享库(动态链接库)时 | unload表示 删除载入库时 |

gdb>> throw
gdb>> catch exec
gdb>> load

搜索原代码

命令 含义
reverse-search 全部搜索
forward-search 向前面搜索
search 向前面搜索

forward-search
没有生成的变量 或 还未调用的函数 是搜索不到的
gdb>> b 20 //设置断点
gdb>> run //启动程序 只有进入堆占的 内容才会被搜索到
gdb>> search fun //查找堆占中的fun

GDB多进程多线程调试

  • 多进程
    进程是一些资源的总和:内存 文件 时间片 协处理器(gpu dsp)
    进程是为了运行程序 进程的创建是复制(fork) 完全复制
    gid 表示进程
  • 多线程
    程序执行单元 线程在进程中 是一直轻量级的进程

  • 测试调试

程序中生成进程 GDB会默认跟随新的进程执行(子进程)

命令 含义
show follow-fork-mode 显示当前跟随进程 是 parent or child
set follow-fork-mode parent 跟随父进程调试
set follow-fork-mode child 跟随子进程调试
set detach-on-fork off 设置未跟随进程暂停运行
info inferiors 查看当前所有运行进程 带*表示正在查看的进程
remmove-inferiors 删除一个进程
add-inferior 复制一个进程

dgb>> set detach-on-fork off //暂停的进程等于已经被杀死 不可以在恢复,可以挂接上去
gdb>> info inferiors //查看当前所有运行进程
gdb>> shell ps -ef | grep 3980 //在系统进程中查找 3980的进程
gdb>> inferior <进程编号> // 跳转到其他进程中去
gdb>> remmove-inferiors <进程编号> //删除一个进程

挂接到另一个进程中去

命令 含义
inferior 切换到其他进程中去
attach 挂接到另一个进程中

gdb>> info inferiors //查看当前所有运行进程
gdb>> attach 3889 //挂接到3889进程上

  • attach

gdb>>
gdb>> attach 38891 //挂接到 38891进程中

  • add-inferior

add-inferior [-copies n] [-exec executable]
//copies 表示复制进程ID executable 表示新开一个进程 文件路径
add-inferior -copies 3 //复制3号进程
add-inferior -exec ./hello //新开hello程序

gdb attach 挂接进程

启动方式 2 通过进程ID挂接到程序中
shell>> gdb attach 38891 //挂接到38891进程上
gdb>>