文章目录
- 下载链接
- Linux系统
- 基础指令
- 目录相关
- 文件相关
- 压缩相关
- 进程相关
- 网络相关
- IPC相关
- 系统资源相关
- 权限相关
- 其他
- 常用工具
- vim
- gcc/g++
- gdb
- make
- git
- 进程概念
- 冯诺依曼
- 操作系统
- 进程概念
- 进程控制
- 进程状态
- 环境变量
- 虚拟地址空间
- 进程替换
- 进程信号
- 信号概念与本质
- 信号种类
- 信号生命周期
- 函数可重入与不可重入
- volatile
- 信号的相关操作
- 核心转储
- 进程通信
- System V IPC
- 为什么操作系统需要向用户提供进程间通信
- 进程间通信种类
- 多线程
- 线程概念
- 线程控制
- 线程安全
- 网络
- 网络基础1
- 网络套接字
- 网络基础2
- 系统中的概念
- 同步和异步
- 同步和互斥
- 并发和并行
- 原子性
- 基础IO
- fd的本质
- FILE*和fd
- 缓冲区
- 文件系统
- 动静态库
下载链接
链接: https://pan.baidu.com/s/1hRTh7rSesikisgRUO2GBpA?pwd=utgp 提取码: utgp
Linux系统
基础指令
目录相关
-
cd
-
ls
-
pwd
文件相关
-
touch
-
cp
-
mv
-
rm
-
mkdir
-
rmdir
-
less
-
less [选项] [文件名]
-
-i 忽略搜索大小写
-
-N 显示行号
-
/ ? 向上下搜索字符串
-
n/N 前进/后退一个搜索
-
-
head
-
head [选项] [文件名]
-
-n 行数
-
-
tail
-
-f
- 不断刷新最后一行到屏幕上
-
-n
- 行数
-
-
find
-
find [从哪里搜] [按什么搜] [搜什么]
-
find ~ -name Http.hpp
-
-
grep
-
-i 忽略大小写
-
-n 输出行号
-
-v 反向选择
-
压缩相关
-
zip
-
zip [压缩包名] [文件位置]
-
zip test.zip test/*
-
-
unzip
-
unzip [目标文件名] [解压到某一目录下]
-
unzip test.zip -d /tmp
-
-
tar
-
tar [选项] [目标文件名] [从某一目录]
-
tar -cvf /tmp/etc.tar
-
进程相关
-
ps
-
kill
网络相关
- netstat
IPC相关
-
ipcs
- 查看通信资源
-
ipcrm
- 删除通信资源
系统资源相关
-
top
-
free
-
fdisk
-
df
- 挂载的分区使用情况
-
du
- 查看目录下文件的空间占用
权限相关
-
切换用户
- su [用户名]
-
更改权限
- chmod 777 [文件名]
-
更改所属组
- chgrp
其他
常用工具
vim
-
模式
-
插入
-
功能
- 插入文字
-
-
底行
-
功能
- 文件保存退出,文件替换,找字符串,列出行号
-
操作
-
/ 字符串
- 查找字符串
-
-
-
普通
-
功能
- 控制屏幕光标移动,删除,复制等
-
操作
-
光标移动
-
hjkl
-
G:移动到最后
-
gg:文本的开始
-
-
删除
- dd:删除行
-
复制
- yy:复制
-
粘贴
- p:粘贴
-
剪切
- 上面组合一下
-
撤销/反撤销
-
u:撤销上一次
-
R:撤销恢复
-
-
-
-
gcc/g++
-
编译过程
-
预处理
-
宏定义替换,头文件展开,条件编译,去除注释
-
gcc -E hello.c -o hello.i
-
-
编译
-
检查语法错误等,最后翻译成汇编语言
-
gcc -S hello.i -o hello.s
-
-
汇编
-
把汇编转换为二进制代码
-
gcc -c hello.s -o hello.o
-
-
链接
-
链接成可执行文件
-
gcc hello.o -o hello
-
链接在做什么
-
链接方式
-
静态链接
- 把库文件的代码全部加入到可执行文件中,但是也就不需要库文件了
-
动态链接
- 动态链接则将链接过程推迟到了程序运行时。编译时,编译器和链接器不会将库的实际内容合并到可执行文件中
-
-
-
-
默认的链接方式
- 默认采取的是动态链接
-
动态库和静态库的生成
-
动态库生成
-
先生成 .o 文件
- gcc -fPIC -c sub.c add.c
-
再生成动态库
- gcc -shared -o [目标包的名字] [所依赖的.o文件]
-
-
静态库生成
-
先生成 .o 文件
- gcc -c xxx.o xxx.c
-
再生成静态库
- ar -rc [目标包的名字] [所依赖的.o文件]
-
-
-
动态库和静态库的使用
-
程序生成时库的链接搜索路径
- gcc test.c -Imymath_lib/include/ -lmymath -L mymath_lib_so/lib
-
程序运行时库的加载搜索路径
- gcc test.c -I mymath_lib/include/ -l mymath -L mymath_lib/lib
-
-
结论
- 静态库提供给别人去使用,只需要把对应的.h头文件和对应的.a文件交给别人就够了,其中这个.a文件就是我们前面所说的.o文件的集合
-
gcc常见选项
-
-E
-
生成预处理后的代码
- 还是文本代码
-
-
-S
-
生成编译后的代码
- 汇编
-
-
-c
-
生成汇编后的代码
- 二进制
-
-
-o
-
进行链接
- 生成可执行程序
-
-
-static
- 必须采取静态链接的方式
-
-fPIC
-
与位置无关码
- 一般用于生成动态库
-
-
-shared
-
shared
- 表示生成共享库格式
-
-
-L
-
link
- 告诉编译器,编译的时候需要使用的库的存储路径
-
-
-I
-
include
- 告诉编译器,编译的时候要使用的头文件路径
-
-
-l
-
link
- 告诉编译器,编译的时候需要使用这个库的名称
-
-
-g
-
debug
- 告诉编译器,要产生调试信息
-
-
gdb
-
功能
-
程序调试的前提
- gcc -g
-
gdb加载程序
- gdb ./main
-
常见调试操作
-
开始调试,加载运行参数
-
run -I -a
-
start -I -a
-
-
逐步调试
-
n
-
s
-
I
-
p
-
until
-
-
断点调试
-
b
-
i b
-
d
-
watch
-
-
函数调用栈信息
- bt
-
make
git
进程概念
冯诺依曼
-
外设
-
IO
-
数据流
-
存储分级与IO效率
-
所有硬件都是围绕内存工作的
操作系统
-
目的
- 与硬件交互,管理软硬件资源
-
定位
- 给应用程序提供良好的运行环境
-
管理
- 先描述,再组织
-
库函数与系统调用接口
- 库函数内部是封装了系统调用接口的
进程概念
-
原因
- 当程序运行时,要从硬盘加载到内存当中,操作系统为了更方便的管理每个程序的运行,就要首先描述出每一个进程的相关信息,所以有了进程控制块,而Linux中的PCB就是task_struct
-
描述信息
-
内存
- mm_struct
-
文件
-
files_struct
- struct file * file_arrays[]
-
-
数据
- 寄存器中存储的上下文数据
-
信号
-
信号的阻塞位图
- sigset_t blocked
-
信号的处理方法
- struct sigaction
-
-
进程控制
-
进程创建
-
fork
-
复制
- 以父进程为模板,为子进程创建PCB,子进程和父进程共享代码和数据
-
返回值
-
父进程返回子进程的pid
-
子进程返回0
-
-
-
vfork
- 共享同一个虚拟地址空间
-
创建一个进程的流程
-
找到父进程的PCB对象,malloc一个PCB来存放子进程,用父进程的PCB初始化子进程,子进程的PCB指向父进程的代码和数据,子进程和父进程都加入调度队列开始排队等待调度
-
当有一方要改变数据时,就会触发写时拷贝
-
-
-
进程终止
-
终止的几种情况
-
正常终止,结果正确:代码正常执行完毕,正确退出码是0
-
正常终止,结果不正确:代码也正常执行结束了,但是不在合适的地点退出,退出码不为0
-
异常:代码没有正常执行结束,可以使用echo $?来查看
-
exit code:当进程收到信号而退出后,可以父进程可以通过回收资源收到退出码,以查看子进程的退出情况
-
-
终止的操作对比
-
exit和_exit:_exit是系统调用,exit内部封装了这个系统调用
-
main和return
-
-
进程终止系统的行为
-
- 根据被终止进程的标识,操作系统会从它的PCB集合中找到该进程的PCB,读取该进程的状态
-
- 如果该进程处于执行状态,会立即停止执行,并修改状态标识,表示这个进程被终止
-
- 回收进程的资源
-
- 从运行队列中移除
-
-
-
进程等待
-
进程等待的原因
-
防止内存泄漏,子进程退出,父进程不回收,就会导致僵尸状态的出现
-
僵尸进程:父进程创建子进程后,子进程异常终止,父进程并没有调用对应系统调用获取子进程的退出信息,子进程的进程描述符等资源仍在系统中占用资源,那么此时子进程就变成了僵尸进程
-
-
进程等待的方式
-
wait:pid_t wait(int *status);
-
waitpid: pid_t waitpid(pid_t pid, int *status, int options);option为0,表示阻塞等待,WNOHANG表示非阻塞等待
-
status是一个输出型参数,0-7是退出信号,8-15是位图
-
-
signal和exit code
-
阻塞等待和非阻塞等待
-
阻塞等待是停在函数调用位置等待,直到回收资源成功
-
非阻塞等待是,每到接口处就检测,搭配循环使用,可以做其他事
-
-
进程状态
-
创建,就绪,运行,阻塞,终止状态
-
每一种状态就是宏定义
-
状态变换本质就是修改宏的值,放入不同的队列
-
-
就绪状态
- 当进程的时间片用完之后,就会从CPU上剥离下来,此时会保存寄存器的代码和数据,存储到PCB当中,紧接着把进程的PCB加入到就绪队列当中,等待下一次调度运行
-
挂起状态
- 当进程在阻塞状态时,如果内存资源不足,会暂时把阻塞进程的代码和数据置换到磁盘的swap分区中,当进程被调度的时候再把数据加载进来
-
转换流程
-
僵尸进程
-
产生原因
- 子进程终止,父进程不回收子进程资源
-
危害
- 子进程的数据没有被回收,就会内存泄漏
-
避免
-
进程等待
- 主动调用接口,waitpid进行阻塞或非阻塞等待
-
SIGCHLD
- 子进程结束后,会向父进程发送一个信号,父进程可以对于该信号进行自定义设置方案,即可处理
-
-
-
孤儿进程
-
产生原因
- 子进程未终止,父进程先终止了
-
处理
- 这是无害的,bash会领养孤儿进程,由bash进程进行回收资源
-
-
守护进程
-
后台运行
- 不接受任何终端的输入
-
脱离控制
- 自己创建一个会话,成为会话组长进行管理自己
-
独立生命周期
- 用孤儿进程的方式由bash领养,避免父进程影响
-
总结
- 连续2次fork进行变成孤儿进程,再自己创建一个会话管理自己
-
环境变量
-
概念
-
用来指定操作系统运行环境的一些参数
- 动静态库的位置
-
PATH
- 指定命令的搜索途径
-
HOME
- 指定用户的主工作目录
-
SHELL
- 当前shell,一般是bash
-
-
相关命令
-
echo 查看环境变量
-
export 新增一个环境变量
-
env 显示所有环境变量
-
unset 清除环境变量
-
set 显示本地定义的环境变量
-
-
特性
-
main函数参数的第三个参数
-
环境变量信息是以脚本配置文件形式存在的
-
每次登陆从 .bash_profile 当中读取内容创建表
-
本地变量不能被子进程继承,环境变量可以
-
环境表本质上是一个字符指针数组
-
-
命令
-
常规命令
- fork子进程让子进程执行该命令
-
内建命令
- shell命令行的函数,直接读取环境变量
-
-
代码中获取设置环境变量
-
getenv
-
putenv
-
setenv
-
虚拟地址空间
-
是什么
- 一个mm_struct结构体
-
为什么
-
提高内存利用率
-
增加内存访问控制
-
保持进程独立性
-
-
怎么做
-
分段式内存管理
- 程序由若干个逻辑分段组成,代码分段,数据分段,栈段,堆段等,不同的段有不同的属性,用分段的形式可以把段分离开
-
分页式内存管理
- 产生连续的内存空间,把整个虚拟地址和物理内存空间划分为固定尺寸的大小,每一页是4KB
-
段页式内存管理
-
先划分成逻辑意义的段,也就是分段机制
-
再把每一个段划分成多个固定大小的页
-
由段号,段内页号,页内偏移定位信息
-
-
进程替换
-
替换原理
-
创建新进程:调用成功后,整个进程的代码和数据会替换为目标的代码和数据
-
后续进程处理方式:不会处理后续的进程
-
-
系统调用接口
-
execl
-
execle
-
execlp
-
execv
-
execvpe
-
execvp
-
-
MySQL shell
进程信号
信号概念与本质
-
软件中断,通知进程发生了某个事件,打断进程当前操作,去处理这个事件
-
信号是提前定义好的内容,进程提前就知道应对措施
-
信号的本质是对位图做写入工作
信号种类
-
非可靠信号
- 1-31
-
可靠信号
- 34-64
信号生命周期
-
信号的产生
-
硬件产生
-
键盘产生:硬件的光电信号->中断信号->中断方法
-
异常产生:状态寄存器->操作系统检测寄存器内容->发信号
-
-
软件产生
-
系统调用产生:kill/raise/abort
-
软件条件产生:alarm设定闹钟提供软件条件/管道触发
-
-
-
信号在进程中注册
-
原理
- 把函数指针添加到处理方法的数组中
-
-
信号在进程中注销
-
原理
- 把函数指针从处理方法的数组中移除
-
-
信号的处理
-
原理
-
处理方式
-
默认
- SIG_DFL
-
忽略
- SIG_IGN
-
自定义
-
void (*sighanler_t)(int signo)
-
自定义处理方式捕捉
-
-
修改处理方式
-
signal
-
sigaction
-
-
-
用户内核转换
-
用户态:是一种受限的状态,能访问的资源是有限的
-
内核态:是一种操作系统的工作状态,能访问大部分资源
-
-
-
信号的保存
-
信号递达:信号准备被处理,处理方式有:默认,忽略,自定义
-
信号未决:信号传输成功但还未处理这个状态
-
信号阻塞:表示信号被阻塞,信号不会被识别
-
-
信号的阻塞
-
原理
- 在阻塞信号集合中标记,即可不处理
-
如何实现
- sigprocmask
-
函数可重入与不可重入
-
函数可重入
- 在多个执行流中同时进入一个系统调用
-
如何判断
-
对于临界资源进行调用
-
临界资源的操作是否安全
-
volatile
-
保持内存可见性
- 防止过度优化
信号的相关操作
-
int sigemptyset(sigset_t *set);
-
int sigfillset(sigset_t *set);
-
int sigaddset(sigset_t *set, int signum);
-
int sigdelset(sigset_t *set, int signum);
-
int sigismember(const sigset_t *set, int signum);
-
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
-
int sigpending(sigset_t *set);
-
int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);
-
void (*signal(int sig, void (*func)(int)))(int);
核心转储
- 将错误信息存储到一个文件中,方便调试,由于占用内存过大默认关闭
进程通信
System V IPC
-
InterProcess Communication
-
System V是一种规范标准,在规范标准下定义的接口和设计都有相似性,使用成本不会很高
为什么操作系统需要向用户提供进程间通信
-
进程隔离和地址空间保护
- 为了保护数据独立,每个进程有独立的进程地址空间,所以操作系统要提供专用的机制来进行数据交换
-
协同工作和资源共享
- 在多任务中,可能会需要多个进程共同协作完成任务
-
系统模块解耦
- 让进程和进程之间解耦,可以通过自己独立的方式进行资源共享,而不是相互耦合
进程间通信种类
-
管道
-
作用
- 实现进程之间数据传输
-
本质
- 内核中的一块缓冲区
-
原理
- 多个进程访问同一块缓冲区实现通信
-
分类
-
匿名管道
-
缓冲区没有标识符
-
只能用于具有亲缘关系的进程间通信
-
-
命名管道
-
缓冲区有标识符文件
- 管道文件
-
任意进程都可以打开管道文件进行缓冲区访问
-
-
-
特性
-
四种情况
-
管道没有数据,写端必须等待
-
管道写满数据,读端必须等待
-
写端关闭,读端读取到0
-
读端关闭,写端收到13号信号
-
-
五种特性
-
默认给读写端提供同步机制
-
匿名管道允许具有血缘关系的进程间通信
-
面向字节流
-
生命周期随进程
-
单向通信
-
-
-
理解进程阻塞
-
管道接口
-
pipe:int pipe(int fd[2]);(输出型参数)
-
mkfifo:int mkfifo(const char * pathname,mode_t mode)
-
-
-
共享内存
-
原理
-
通信的本质是让不同的进程看到同一份资源
-
共享内存的本质,在系统层面上把内存申请好,再映射到两个进程的地址空间中,映射结束之后,此时只需要把映射在虚拟地址中的起始地址返回给用户,用户就可以通过起始地址进行访问了
-
-
key和shmid
-
对于key值是用来创建共享内存时的参数,可以由函数ftok创建:key_t ftok(const char *pathname, int proj_id);
-
shmid是创建共享内存的返回值,对于共享内存的操作都要靠id来做,有些类似于文件描述符fd
-
-
接口
-
shmget:int shmget(key_t key, size_t size, int shmflg);
-
size:一般设置为4096的整数倍,开辟空间是以4096为单位开辟的
-
IPC_CREAT:没有就创建,有就返回
-
IPC_EXCL:搭配上面选项使用,保证只有一个共享内存
-
0666:表示创建文件所需要的权限
-
-
shmat:void *shmat(int shmid, const void *shmaddr, int shmflg);
-
创建共享内存返回的shmid
-
将共享内存挂接在虚拟地址的指定位置,一般设置为nullptr
-
挂接方式:设置为0
-
返回值:需要强转,参考malloc
-
-
shmdt:int shmdt(const void *shmaddr);
- 挂接成功后虚拟空间的地址
-
shmctl:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
-
创建时返回的shmid
-
IPC_RMID:立即删除
-
通常设置为nullptr
-
-
-
特性
-
效率高:共享内存是进程间通信中效率最高的一种方式
-
原因:减少拷贝,直接控制
-
生命周期:随内核
-
-
ipc指令
-
ipcs
-
ipcs -m:显示共享内存
-
ipcs -s:显示信号量
-
ipcs -q:显示消息队列
-
-
ipcrm
-
ipcrm -m shmid:移除共享内存
-
ipcrm -s semid:移除信号量
-
ipcrm -q msgid:移除消息队列
-
-
-
-
消息队列
-
信号量
-
本质:本质是一个计数器,用来保护公共资源
-
临界资源:被保护起来的资源
-
临界区:访问临界资源的代码
-
同步性
-
互斥性:计数器上限为1
-
原子性:指只有两态,要不然完成,要不然没完成,原子性是保证信号量处于安全的必要前提
-
PV操作:申请资源和释放资源导致计数器产生变化
-
多线程
线程概念
-
进程概念
-
把一个可执行程序运行起来就是进程
-
代码和数据+内核数据结构(PCB)
-
-
Linux下线程实现
-
进程是资源分配的基本单位
线程是调度的基本单位 -
Linux没有线程概念,采用的是轻量级进程,复用进程的PCB结构进行处理
-
-
线程间的独有与共享
-
共享
-
代码和数据
-
自定义函数和全局变量
-
文件描述符表
-
信号处理方式
-
工作目录
-
-
独有
-
一组寄存器的数据内容(重要)
-
线程独有自己的栈空间(重要)
-
线程ID
-
信号屏蔽字
-
调度优先级
-
errno
-
-
-
多线程/多进程任务处理的优缺点
-
优点
-
创建新线程的代价比新进程小
-
线程切换比进程切换要容易
-
线程占用资源比进程占用资源少
-
充分利用多处理器并行
-
计算较多的进程,可以把计算分配到其他线程中
-
线程可以等待不同的IO操作
-
-
缺点
-
性能损失,增加了额外的切换的损耗
-
健壮性较低,可能会出现不该共享的变量
-
一个线程异常会导致全部异常
-
编写难度比较高
-
-
线程控制
-
线程创建
-
线程在虚拟地址空间中有自己独有的线程地址空间
-
线程的数据会存储在mmap区域,有线程的局部存储和线程自己的栈结构
-
-
线程终止
- pthread_exit函数
-
线程等待
-
已经退出的线程,如果不回收资源,还会存储在进程的地址空间当中
-
创建新线程就不会复用刚才的退出的线程的地址空间
-
-
线程分离
-
线程可以自己调用函数把自己和主线程分离
-
int pthread_detach(pthread_t thread);
-
如果不关心线程的返回值,那么就可以让线程分离,当线程结束的时候可以直接由操作系统回收
-
线程安全
-
概念
- 多个线程对于临界资源的争抢访问操作,但不会造成数据的二义性
-
如何实现
-
互斥
- 保证安全性
-
同步
- 保证合理性
-
互斥实现
-
互斥锁
-
信号量
- 信号量初始化为1,当有资源申请时,如果信号量满足就申请成功,如果不满足就阻塞等待
-
-
同步实现
-
条件变量
- 判断流程和循环判断是否满足条件
-
信号量
-
生产消费者模型
-
full_count:记录缓冲区中已有产品数量
-
empty_slot:记录缓冲区可用空位数量
-
-
-
-
生产消费者模型
-
场景
- 并发编程的模型,用来解决多线程共享数据的问题
-
作用
-
解耦合
- 分离生产者和消费者的任务,使得它们可以独立工作,互不影响
-
支持忙闲不均
- 有缓冲区,有同步的概念
-
支持并发
- 生产者和消费者可以同时执行,提高系统的效率,允许存在处理速度的不同
-
-
实现
-
线程安全队列
-
生产者消费者线程创建
-
-
总结
-
三二一原则
-
三个原则
-
生产者和生产者之间是互斥关系
-
消费者和消费者之间是互斥关系
-
生产者和消费者之间又是互斥又是同步
-
生产者生产,要不然生产了要不然没生产,在这个过程中消费者不可以介入,必须要保持互斥
-
消费者消费前提是生产者要生产,所以要有同步的概念存在
-
-
-
两种角色
-
生产者
-
消费者
-
-
一个交易场所
- 某个特定的内存空间
-
-
-
-
读者写者问题模型
-
读写锁
-
概念
- 允许多个线程进行读取,只允许一个线程写入
-
实现原理
-
读锁获取
-
- 检查写锁是否持有,如果没有持有就允许读锁
-
- 如果写锁持有,或者读锁满了,就阻塞等待
-
- 当满足条件后会唤醒阻塞的线程
-
-
写锁获取
-
- 先检查是否有读锁,再检查是否有写锁,必须独占
-
- 如果不满足,就阻塞等待
-
- 如果满足了,就唤醒阻塞的线程
-
-
读锁释放
- 如果读完了,就释放读锁,如果没人读了,就唤醒阻塞的写进程
-
写锁释放
- 如果写完了,就释放写锁,此时写进程和读进程都可以申请,根据特定策略进行发放
-
-
优先级信息
- 按照线程请求锁的先后顺序来决定锁的分配
-
-
自旋锁
-
概念
-
让试图获取锁但发现锁已被占用的线程(或执行单元)在原地循环等待(即“自旋”)
-
这样可以避免被切换上下文调度
-
-
实现原理
- 循环申请某个锁,直到申请成功
-
使用场景
- 用于申请锁临界区比较少的情况
-
-
悲观乐观锁
- 上述基本都是悲观锁,乐观锁一般是说不管怎么说先把数据改了再说,如果冲突了再放弃,一般适用于冲突几率很小的场景
-
-
-
线程池
-
概念
- 预先创建一组可复用的线程,当有新任务来就选择一个空闲线程执行,任务结束回到线程池等待下一次分配
-
解决的问题
-
解决了线程创建和销毁的开销
-
方便于对于线程进行管理和控制
-
-
实现
-
线程池管理,工作线程,任务队列,任务接口
-
创建线程池,提交任务,任务分配,执行任务,回收线程
-
-
-
线程安全的单例模式
-
设计模式
-
单例模式概念
- 资源只需要被加载一次
-
单例模式实现
-
饿汉模式
-
初始化加载所有资源
-
所有对象共享一个资源
-
手撕实现
-
-
懒汉模式
-
需要的时候再加载
-
所有执行流对象共享一个资源
-
手撕实现
-
-
-
STL容器安全
- 不安全,需要自己保证
-
智能指针
- shared_ptr 安全
-
网络
网络基础1
网络套接字
- 本质可以看成是进程间通信
网络基础2
-
应用层
-
HTTP协议
-
概念
-
超文本传输协议
- 就是超过了普通的文本,也可以传输图片文字音频视频…这些都叫做超文本
-
常见状态码
-
1xx
- 表示中间状态
-
2xx
- 成功
-
3xx
- 资源重定向
-
4xx
- 客户端错误
-
5xx
- 服务端错误
-
-
常见字段
-
HOST
- 服务器域名
-
Content-Length
- 数据长度
-
Connection
- 决定长短链接
-
Content-Type
- 数据格式
-
Content-Encoding
- 数据压缩方法
-
-
-
GET/POST
-
区别
-
GET是从服务器获取资源
-
POST是对资源做处理
-
-
安全和幂等
- GET是,POST不是
-
-
特性
-
HTTP/1.0
- 短连接,性能不好,一般不考虑
-
HTTP/1.1
-
优点
- 简单,灵活,扩展,广泛,跨平台
-
缺点
- 明文传输,无状态(Cookie)
-
性能优点
-
长连接+管道
- 这个功能基本不开放
-
解决了请求阻塞问题
-
-
性能缺点
-
头部没压缩,相同的头部占用资源
-
响应按序响应,可能会阻塞
-
没有请求优先级控制
-
只能客户端请求,服务端被动响应
-
-
-
HTTP/2.0
-
优点
-
头部压缩,二进制
-
并发传输
- 注意一下并发传输,说的是在一条TCP连接中可以有多个Stream,每一个流里面有Message,Message里面放的Frame,一个或多个Frame二进制流构成了是HTTP/1的数据,单个Frame是最小单位
-
主动连接
- 比如对于前端CSS的内容,如果使用的是HTTP/1,要不停的申请,但是如果使用HTTP/2.0,可以主动发送CSS的相关信息
-
-
缺点
- TCP层的队头阻塞问题没有解决
-
-
HTTP/3.0
- 直接把底层协议换成UDP,但是普及很慢
-
-
缓存
-
实现方式
- 把请求和响应的数据缓存在本地,如果请求的方式是一样的,那么直接从本地拿响应的数据
-
强制缓存
- 服务器发回数据时预估一个过期时间,如果数据没过期就从本地拿
-
协商缓存
- 服务器对比一下更改时间,如果数据没变,就发回响应告诉客户端直接从缓存里面拿就行
-
-
发展历史
-
-
HTTPS协议
-
解决问题
- 窃听,篡改,冒充
-
途径
- 信息加密,校验机制,身份证书
-
-
-
传输层
-
UDP
-
特性
-
无连接
- 只要知道对端地址就可以发数据
-
不可靠
- 不关心是否安全送达
-
面向数据包
- 只能整个整个发,但是不会粘包问题
-
-
协议字段
-
源端口、目的端口、数据报长度、校验和
- 如果校验和出错就会丢弃
-
-
数据包长度的特性
-
数据类型uint16_t
-
数据报长度不超过64k
-
面向数据报
-
-
-
-
TCP
-
字段
-
源端口/目的端口
-
序号/确认序号
-
首部长度
-
标志位
-
URG 紧急指针是否有效
-
ACK 确认号是否有效
-
PSH 让接收端赶快读取数据
-
RST 重新建立连接 复位报文段
-
SYN 请求建立连接 同步报文段
-
FIN 提示本端要关闭了 结束报文段
-
-
窗口大小
-
校验和
-
紧急指针
-
-
特性
-
面向连接
-
三次握手和四次挥手
-
原因
-
第三次握手是可以携带数据的
-
-
-
可靠传输
-
面向字节流
-
-
-
系统中的概念
同步和异步
-
同步
- 同步讲究一个先后顺序,比如说管道访问的时候必须要先有写的内容,才能读,如果不符合这样的需求就进行阻塞,只有当满足要求了才能进行运行,读取数据等等,是一个有先后的问题
-
异步
- 表示的是这个操作不依赖其他的步骤,即使资源不就绪也不会阻塞,比如说可以把read使用fctl设置为非阻塞,一种场景是在网络中发送请求后,无需阻塞等待,可以等到收到回复后再处理
同步和互斥
-
同步和互斥中的同步和同步与异步之间的同步不太一样,侧重点不同,但是也比较相似,正常来说同步与互斥中的同步说的是同步访问
-
同步访问
- 强调的是对于多个线程访问临界资源要有一定的顺序性,这样来维护数据一致性,避免竞争
-
互斥
- 互斥强调的是排他性,在同一时刻我只允许一个线程进行访问临界资源,互斥可以看做是同步的一种特例情况
并发和并行
-
并发
-
多个任务在同一时间内交错执行
-
通过快速切换,营造出是同一时刻一起执行的假象
-
-
并行
-
并行是真正意义上的一起执行
-
操作系统把任务分配给不同的处理器核心
-
原子性
-
完整性
- 原子性只有两态,要不然不开始,要不然完成,如果开始了就必须完成,不会受到任何的影响
-
一致性
- 因为有上述的特性,所以原子性保证不会出现数据竞争的情况
-
隔离性
- 从外界的视角来看,原子性的操作是一瞬完成的,因为要不然是没有开始前的状态,要不然已经完成了,只有两态
基础IO
fd的本质
-
文件描述符,本质上是数组的下标
-
fd本质上是files_struct结构体下的fd_array的下标
-
分配规则:寻找最小的,没有被使用的数据的位置,分配给指定的打开文件
-
创建的每一个进程会默认打开三个文件,标准输入/输出/错误
-
0:标准输入
-
1:标准输出
-
2:标准错误
-
-
重定向函数:dup()/dup2()
-
int dup(int oldfd);
- 返回旧文件描述符
-
int dup2(int oldfd, int newfd);
-
将新文件描述符覆盖到旧文件描述符,
并关闭新文件描述符 -
覆盖成功返回新文件描述符的值,
覆盖失败返回-1
-
-
-
重定向的本质:新文件描述符覆盖旧文件描述符
FILE*和fd
-
FILE*描述文件的结构体对象,其中包含了文件操作的基本属性,其中包括fd
-
fd是文件描述符,本质上是数组的下标
缓冲区
-
用户级缓冲区:由语言本身提供的缓冲区,由外部加载到内存
-
内核级缓冲区:内核用的缓冲区,将内核数据刷新到磁盘
-
网络缓冲区
-
文件缓冲区
-
文件页缓冲区:存储数据
-
文件系统缓冲区:存储元数据
-
-
-
FILE中就包含了文件描述符和用户级的文件缓冲区
文件系统
-
磁盘
-
物理地址(CHS地址)
-
磁道–Cylinder柱面
-
盘面–Head磁头
-
扇区–Sector扇区
-
-
逻辑地址(LBA地址)
- logical block address
-
-
分区
-
将一整个磁盘分成不同的分区进行管理
-
分治的思想体现
-
-
格式化
-
在使用磁盘前,提前对磁盘的组进行数据的初始化,有多少被占用,当前还有多少可用
-
提前将对于磁盘的管理信息写入文件系统中,这个写入的过程就是格式化的过程
-
格式化确实会清楚文件的数据内容,但是文件的管理数据从来都在,不会被清空
-
-
分区的各个组成模块
-
Boot Block:引导启动块,负责启动整个系统,检查相关外设信息,存储引导加载程序的代码和数据,位于起始地址,通常加载一些配置信息
-
Block Group:用于将文件系统的数据划分为较小的逻辑单元,以提高文件系统的性能和管理效率
-
Super Block:超级块,包括了文件系统的元数据信息,超级块通常有备份,磁盘的文件系统的管理转换成了在内核中对于超级块的管理
-
Group Descriptor Table:块组描述符表,主要是用来存储的是块组的起始位置和使用情况
-
Block Bitmap:位图,用来记录数据块的分配使用情况
-
Inode Bitmap:位图,用来记录索引节点的分配情况
-
Inode Table:一张用来存储文件属性的表,表中存储的是Inode结构体,有固定的大小,可以根据偏移量定位到需要的Inode
-
Data Blocks:一个用来存储文件内容的表,表中存在多个数据块,每一个数据块有固定大小,可以根据偏移量快速定位到需要的数据块
-
-
inode的理解
-
文件=内容+属性(inode)
-
inode中存储的是文件的属性信息,也会存储文件的数据块的指针信息,有了inode就能访问文件的内容和属性了
-
-
软链接
-
ln -s test.c newtest.c
-
相当于是快捷方式的作用,拥有自己独特的inode编号,是一个独立的文件
-
-
硬链接
-
不是一个独立文件,和原文件享有一个inode编号
-
硬链接是在当前目录下新增了一个文件名到inode的映射关系,同时引用计数加一
-
-
目录文件
-
创建一个目录,本质上要分配新的inode编号和数据块,并在当前目录下加入当前目录和上级目录,在上级目录新增该目录的信息,修改时间和硬链接数
-
创建一个文件,本质上要分配新的inode编号和数据块,在上级目录中新增文件名到inode的映射关系,更新修改时间和硬链接数
-
创建软链接,会在该目录下分配新的inode编号和数据块,数据块中存储的是链接的路径
-
创建硬链接,会在指定位置创建一个硬链接,具有原文件的inode编号以及数据内容,相当于是另外一个入口点
-
动静态库
-
打包静态库
- ar -rc <xxx.o> <xxx.a>
-
打包动态库
-
gcc -fPIC -c <xxx.c> -> 与位置无关码
-
gcc -shared -o <xxx.o> <xxx.so>
-
-
include/lib
-
include文件夹下放置的是程序所需要的头文件
-
lib文件夹下放置的是程序所需要的动态库
-
-
编译选项:gcc test.c -I mymath_lib/include/ -l mymath -L mymath_lib/lib
-
头文件的搜索路径
-
库的名称
-
库的搜索路径
-
-
动态库的理解