Linux 命令
cd ..
rm
cp
ldd x.c
ll
man 2/3
man 7 signal
touch
ls -l x.xxx 查看文件信息
ulimit -a
tty
ifconfig
netstat
查看进程:
ps aux/ajx (a、u、j、x的含义)
实时显示进程动态:
top
杀死进程:
kill
查看管道缓冲大小命令:
ulimit a
查看系统定义的信号列表:
kill –l
ipcs
ipcrm
查看指定进程的 LWP 号:
ps –Lf pid
查看当前 pthread 库版本:
getconf GNU_LIBPTHREAD_VERSION
快捷键
Ctrl+L 清空终端
Shift+G 调到文件末尾
I/O vim插入
Esc :wq 保存并退出
gdb调试总体学习
第1章 Linux系统编程入门
1.2 GCC(1)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S3TsaJKO-1640703132781)(https://i.loli.net/2021/10/25/TPBzc4wdDGRfsNu.png)]
-
gcc test.cpp -o app ./app gcc test.c ./a.out
gcc test.c -E -o test.i
gcc test.i -S -o test.s
gcc test.s -c -o test.o
gcc test.o -o test.out
./test.out
gcc test.c //一步其实都干了
1.3 GCC(2)
- 通常:gcc编译c,g++编译c++
- .c,一个认为是C,一个是C++
- .cpp,都会认为是C++
- gcc不会定义__cplusplus,g++会,宏标志着把代码按C还是C++语法解释
- 编译可以用gcc/g++,链接可以用g++或者gcc -lstdc++
- 编译阶段g++自动调用gcc
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lVL1Twfp-1640703132787)(https://i.loli.net/2021/10/25/86SiVNMKa31erdC.png)]
- -D方便调试
1.4 静态库
1.5 静态库的使用
-
gcc main.c -o app -I ./include/ -l calc -L ./lib/
1.6 动态库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7Z1NFJS-1640703132790)(https://i.loli.net/2021/10/27/MVR4lkZKwG3yqaX.png)]
1.7 动态库加载失败的原因
1.8 解决动态库加载失败问题
- 修改环境变量LD_LIBRARY_PATH
- 修改/etc/ld.so.cache
- /lib/,/usr/lib不建议使用
1.9 静态库和动态库的对比
1.10-1.12 Makefile
- makefile:自动化编译
1.13-1.16 GDB调试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FqHRjYRw-1640703132796)(https://i.loli.net/2021/10/28/PcElBxMd5wV4UbT.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XynEG9TP-1640703132797)(https://i.loli.net/2021/10/28/nHAeoVQbMhWj5wd.png)]
1.17 标准C库IO函数和Linux系统IO函数对比
1.18 虚拟地址空间
1.19 文件描述符
1.20-1.24 open、close、read 、write、lseek、stat、lstat
-
lesson09-lesson12有函数解读
-
rwx,读写可执行
-
0777 八进制,每个7表示该位用户的权限,rwx都有就是111(7)
-
stat:返回文件的信息
-
lstat:获取软连接文件的信息
1.25 模拟实现 ls -l 命令
- lesson12 ls-l.c代码
1.26 文件属性操作函数
- lesson13
1.27 目录操作函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2vZ3GLhi-1640703132801)(https://i.loli.net/2021/10/30/PdAIOj35MzogGLX.png)]
- lesson14
1.28 目录遍历函数
1.29 dup、dup2函数
1.30 fcntl函数
- lesson17
第2章 Linux多进程开发
2.1 进程概述
2.2 进程状态转换
- ps、top、kill
- STAT各个参数含义
- PPID(父进程号)、PGID(进程组号)
2.3 进程创建
- fork()
- fork()的返回值会返回两次。一次是在父进程中,一次是在子进程中。
- 在父进程中返回创建的子进程的ID,
在子进程中返回0
如何区分父进程和子进程:通过fork的返回值。
在父进程中返回-1,表示创建子进程失败,并且设置errno
2.4 父子进程虚拟地址空间情况
-
实际上,更准确来说,Linux 的 fork() 使用是通过写时拷贝 (copy- on-write) 实现。
写时拷贝是一种可以推迟甚至避免拷贝数据的技术。
内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。
只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。
也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。
注意:fork之后父子进程共享文件,
fork产生的子进程与父进程相同的文件文件描述符指向相同的文件表,引用计数增加,共享文件偏移指针。
2.5 父子进程关系及GDB多进程调试
- 父子进程之间的关系:
- 区别:
1.fork()函数的返回值不同
父进程中: >0 返回的子进程的ID
子进程中: =0
2.pcb中的一些数据
当前的进程的id pid
当前的进程的父进程的id ppid
信号集
- 共同点:
某些状态下:子进程刚被创建出来,还没有执行任何的写数据的操作
- 用户区的数据
- 文件描述符表
- GDB多进程调试
2.6 exec函数族
- fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。
- 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
2.7 进程退出、孤儿进程、僵尸进程
- 进程退出:exit()、_exit()
- 孤儿进程:
- 父进程运行结束,但子进程还在运行(未运行结束)
- 每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init ,而 init
进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束
了其生命周期的时候,init 进程就会代表党和*出面处理它的一切善后工作。 - 因此孤儿进程并不会有什么危害。
- 僵尸进程:
- 进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程
- 僵尸进程不能被 kill -9 杀死
- 如果父进程不调用 wait() 或 waitpid() 的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免
2.8-2.9 wait/waitpid 函数
- 在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要主要指进程控制块PCB的信息
(包括进程号、退出状态、运行时间等) - 父进程可以通过调用wait或waitpid得到它的退出状态同时彻底清除掉这个进程
- wait() 和 waitpid() 函数的功能一样,区别在于,wait() 函数会阻塞,waitpid() 可以设置不阻塞,waitpid() 还可以指定等待哪个子进程结束
- 注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环
2.10 进程间通信简介
- Inter Processes Communication
- 同步:看医生一个一个进去
- 异步:看医生一起进去
2.11 匿名管道概述
-
管道指匿名管道
-
ls | wc -l
-
管道的特点(ppt)
-
管道是半双工的:数据传输指数据可以在一个信号载体的两个方向上传输,但是不能同时传输
-
匿名管道只能在具有公共祖先的进程(父进程与子进程,或者两个兄弟进程,具有亲缘关系)之间使用
-
管道数据结构是循环队列
2.12 父子进程通过匿名管道通信
-
创建匿名管道:
int pipe(int pipefd[2]);
2.14 管道的读写特点和管道设置为非阻塞
-
读管道:
管道中有数据,read返回实际读到的字节数。
管道中无数据:
写端被全部关闭,read返回0(相当于读到文件的末尾)
写端没有完全关闭,read阻塞等待 -
写管道:
管道读端全部被关闭,进程异常终止(进程收到SIGPIPE信号)
管道读端没有全部关闭:
管道已满,write阻塞
管道没有满,write将数据写入,并返回实际写入的字节数
2.15 有名管道介绍及使用
-
FIFO、有名管道、命名管道
-
FIFO 在文件系统中作为一个特殊文件存在,但 FIFO 中的内容却存放在内存中
-
当使用 FIFO 的进程退出后,FIFO 文件将继续保存在文件系统中以便以后使用
-
mkfifo xxx int mkfifo(const char *pathname, mode_t mode);
-
有名管道的注意事项:
1.一个为只读而打开一个管道的进程会阻塞,直到另外一个进程为只写打开管道
2.一个为只写而打开一个管道的进程会阻塞,直到另外一个进程为只读打开管道
读管道:
管道中有数据,read返回实际读到的字节数
管道中无数据:
管道写端被全部关闭,read返回0,(相当于读到文件末尾)
写端没有全部被关闭,read阻塞等待
写管道:
管道读端被全部关闭,进行异常终止(收到一个SIGPIPE信号)(读端都关闭了,就说明没有人去读数据,那就不能往管道里写数据,写了也没啥用。当初设计的时候就是这样设计的。)
管道读端没有全部关闭:
管道已经满了,write会阻塞
管道没有满,write将数据写入,并返回实际写入的字节数。
2.16 有名管道实现简单版聊天功能
- lesson24
2.17-2.18 内存映射
-
将磁盘文件的数据映射到内存,用户通过修改内存就能修改磁盘文件
-
lesson25
-
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
-
匿名映射:不需要文件实体进程一个内存映射,与上面fd参数有关
2.19 信号概述
- 引发内核为进程产生信号的各类事件:输入Ctrl+C、硬件发生异常、系统状态变化、运行 kill 命令或调用 kill 函数
- 信号特点
- 三种状态:产生、未决、递达
- 各种信号
2.20-2.21 kill、raise、abort、alarm、setitimer函数
-
lesson26
-
kill:
int kill(pid_t pid, int sig); 功能:给任何的进程或者进程组pid, 发送任何的信号 sig
-
raise
int raise(int sig); 功能:给当前进程发送信号
-
abort
void abort(void); 功能: 发送SIGABRT信号给当前的进程,杀死当前进程
-
alarm
unsigned int alarm(unsigned int seconds); 功能:设置定时器(闹钟)。函数调用,开始倒计时,当倒计时为0的时候,函数会给当前的进程发送一个信号:SIGALARM SIGALARM :默认终止当前的进程,每一个进程都有且只有唯一的一个定时器。
-
setitimer
int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value); - 功能:设置定时器(闹钟)。可以替代alarm函数。精度微妙us,可以实现周期性定时
2.23 signal 信号捕捉函数
-
sighandler_t signal(int signum, sighandler_t handler); 功能:设置某个信号的捕捉行为
-
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 检查或者改变信号的处理。信号捕捉
2.24 信号集及相关函数
- 多个信号可使用一个称之为信号集的数据结构来表示,数据类型为 sigset_t
- 两个非常重要的信号集: “阻塞信号集” ,“未决信号集”;这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我们直接对这两个信号集进行位操作。而需自定义另外一个集合,借助信号集操作函数
来对 PCB 中的这两个信号集进行修改。 - 信号的 “未决” 是一种状态,指的是从信号的产生到信号被处理前的这一段时间。
- 信号的 “阻塞” 是一个开关动作,指的是阻止信号被处理,但不是阻止信号产生。
- 相关函数…前面是操作自己的信号集,后两个是系统调用
2.27 SIGCHLD 信号
- SIGCHLD信号产生的条件
- 子进程终止时
- 子进程接收到 SIGSTOP 信号停止时
- 子进程处在停止态,接受到SIGCONT后唤醒时
- 以上三种条件都会给父进程发送 SIGCHLD 信号,父进程默认会忽略该信号
- 可以解决僵尸进程问题,默认忽略但是可以不忽略,子进程终止时候给父进程发送SIGCHLD
2.28-2.29 共享内存
- 共享内存允许两个或者多个进程共享物理内存的同一块区域
- 速度更快,无需内核介入
- 使用步骤:
-
共享内存和内存映射的区别
-
共享内存可以直接创建,内存映射需要磁盘文件(匿名映射除外)
-
共享内存效果更高
-
内存
所有的进程操作的是同一块共享内存。
内存映射,每个进程在自己的虚拟地址空间中有一个独立的内存。
-
数据安全
- 进程突然退出
共享内存还存在
内存映射区消失
- 运行进程的电脑死机,宕机了
数据存在在共享内存中,没有了
内存映射区的数据 ,由于磁盘文件中的数据还在,所以内存映射区的数据还存在。
-
生命周期
-
- 内存映射区:进程退出,内存映射区销毁
- 共享内存:进程退出,共享内存还在,标记删除(所有的关联的进程数为0),或者关机
如果一个进程退出,会自动和共享内存进行取消关联。
2.30-2.31 守护进程
- 进程组
- 会话:一组进程组的集合
- 守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件
- 生命周期很长,守护进程会在系统启动的时候被创建并一直运行直至系统被关闭。它在后台运行并且不拥有控制终端。没有控制终端确保了内核永远不会为守护进
程自动生成任何控制信号以及终端相关的信号(如 SIGINT、SIGQUIT)。
第3章 Linux多线程开发
3.1 线程概述
- 进程是 CPU 分配资源的最小单位,线程是操作系统调度执行的最小单位
- 进程线程区别
- 共享什么不共享什么
3.2-3.7 线程相关api,线程属性
- lesson29
3.8 线程同步
3.9 互斥量/互斥锁
-
互斥量:mutex 是 mutual exclusion的缩写
3.10 死锁
3.11 读写锁
3.12 生产者和消费者模型
3.13 条件变量(阻塞线程)
3.14 信号量
第4章 Linux网络编程
4.1 网络结构模式
- C/S结构:Client - Server,服务器 - 客户机
- B/S结构:Browser/Server,浏览器/服务器
4.2-4.3 MAC地址、IP地址、端口
-
网卡具有MAC地址(独一无二的 48 位串行号),属于OSI地址第二层
-
Media Access Control Address,直译为媒体存取控制位址,也称局域网地址、
以太网地址、物理地址或硬件地址 -
48 位(6个字节)、12 个 16 进制数。如:00-16-EA-AE-3C-40;,其中前 3 个字节,16 进制数 00-16-EA 代表网络硬件制造商的编号,后 3 个字节,16进制数 AE-3C-40 代表该制造商所制造的某个网络产品(如网卡)的系列号。
-
IP 地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址
-
32 位的二进制数,4个字节
-
每个 IP 地址包括两个标识码(ID),即网络ID 和主机 ID。同一个物理网络上的所有主机都使用同一个网络 ID,网络上的一个主机(包括网络上工作站,服务器和路由器等)有一个主机 ID 与其对应。
-
ABC类地址,0对应当前主机、255是广播地址不算
-
子网掩码:子网掩码只有一个作用,就是将某个 IP 地址划分成网络地址和主机地址两部分
-
端口:IP 地址比作一间房子,端口就是出入这间房子的门,给每个应用程序提供一个端口,进程唯一的编号
-
一个应用程序可以有多个端口
-
周知端口\注册端口\动态端口\私有端口
4.4 网络模型
- OSI(Open System Interconnection)七层参考模型
- TCP/IP四层模型
4.5 协议
- RST是重置
- 生存时间:TTL,表明是数据报在网络中的寿命,即为“跳数限制”,由发出数据报的源点设置这个
字段。路由器在转发数据之前就把 TTL 值减一,当 TTL 值减为零时,就丢弃这个数据报。
4.6-4.7 网络通信的过程
- ARP协议:根据IP地址找MAC地址,给所有人发,ip地址对应的进行arp应答
4.8 socket 介绍
- socket 是由 IP 地址和端口结合的
4.9 字节序
-
字节序分为大端字节序(Big-Endian) 和小端字节序(Little-Endian)
-
大部分都采用小端
-
小端字节序则是指整数的高位字节存储在内存的高地址处,而低位字节则存储在内存的低地
址处。 -
小端: 整数:0x01020304 (01是整数的高位) 内存-> 04 03 02 01
-
大端字节序是指一个整数的最高位字节(23 ~ 31 bit)存储在内存的低地址处,低位字节(0 ~ 7 bit)存储在内存的高地
址处;
4.10 字节序转换函数
- htons、htonl、ntohs、ntohl
4.11 socket地址
- socket地址其实是一个结构体
4.12 IP地址转换函数
4.13 TCP 通信流程
4.14 socket 函数
- socket()、bind()、listen()、accept()、connect()、write()、 read()
4.15-4.16 TCP通信实现
- lesson32
4.17 TCP三次握手
-
三次握手发生在客户端连接的时候,当调用connect(),底层会通过TCP协议进行三次握手。
-
ACK、SYN(握手)、FIN(挥手)
-
发送时候seq随机生成,两边seq不同
-
收到时候ack收到确认后在上一步sep+1(SYN=1),通信时候+数据长度
-
客户端和服务器ack不同,谁确认收到谁+,发的时候不变
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h4CMfslb-1640703132806)(https://i.loli.net/2021/11/13/PYzUb6u4DV5m1sf.png)]
4.18 滑动窗口
- 滑动窗口是 TCP 中实现诸如 ACK 确认、流量控制、拥塞控制的承载结构。
4.19 TCP四次挥手
4.20 多进程实现并发服务器
- lesson33
4.23 TCP状态转换
- 2MSL(Maximum Segment Lifetime):保证安全性、可靠性;被动断开方没有收到ACK
4.24 半关闭、端口复用
- 半关闭:四次挥手一次FIN,一次ACK之后的状态
- 端口复用:多个套接字绑定同一个端口
4.25 IO多路复用简介
- select、poll
- epoll
4.26 select API介绍
4.27 select代码编写
4.28 poll API介绍及代码编写
4.29 epoll API介绍
4.30 epoll 代码编写
- lesson36
4.31 epoll的两种工作模式
- LT、ET
4.32 UDP通信实现
- lesson36
4.33 广播
- lesson37
4.34 组播(多播)
- 单播单个、广播全部、多播在两者中提供折中方案
- 广播一般局限于局域网内使用,而组播既可以用于局域网,也可以用于广域网
4.35 本地套接字通信
第5章 项目实战与总结
5.1 阻塞和非阻塞、同步和异步(网络IO)
-
网络IO阶段1:数据就绪
- 阻塞:调用IO方法的线程进入阻塞状态
- 非阻塞:不会改变线程的状态,通过返回值判断
-
→
-
操作系统 TCP接收缓冲区
-
→
-
网络IO阶段2:数据读写(根据应用程序和内核的交互方式)
- 同步:机场机票自己去取 效率低编程简单
- 异步:机场机票别人给送来 效率高编程复杂
-
→
-
应用程序
-
阻塞 != 同步
-
非阻塞 != 异步
-
陈硕:在处理 IO 的时候,阻塞和非阻塞都是同步 IO,只有使用了特殊的 API 才是异步 IO。(select、poll、epoll是同步的)
-
Linux异步IO借口:aio_read() aio_write()
-
一个典型的网络IO接口调用,分为两个阶段,分别是“数据就绪” 和 “数据读写”,数据就绪阶段分为阻塞和非阻塞,表现得结果就是,阻塞当前线程或是直接返回。
-
同步表示A向B请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),数据的读写都是由请求方A自己来完成的(不管是阻塞还是非阻塞);异步表示A向B请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),向B传入请求的事件以及事件发生时通知的方式,A就可以处理其它逻辑了,当B监听到事件处理完成后,会用事先约定好的通知方式,通知A处理结果。
5.2 Unix、Linux上的五种IO模型
- 阻塞 blocking:等待函数返回
- 非阻塞 non-blocking(NIO):每隔一段时间检测是否就绪
- IO复用:select、poll、epoll(阻塞IO只能单个、这些函数可以同时阻塞多个IO操作)
- 信号驱动:继续运行并不阻塞,收到信号后,处理IO事件(第一阶段等待数据异步、第二阶段拷贝读写数据同步),用的很少(信号在多线程中不好处理)
- 异步 asynchronous:编程麻烦,出错不好排查
5.3 Web服务器简介及HTTP协议
- 报文信息、请求方法、状态码
5.4 服务器编程基本框架和两种高效的事件处理模式
- I/O处理单元、逻辑单元、网络存储单元、请求队列
- Ngix
- Reactor(核反应)、Proactor
- 同步 I/O 模型通常用于实现 Reactor 模式,异步 I/O 模型(同步也可以)通常用于实现 Proactor 模式
- Reactor 主线程只负责监听文件描述符上是否有事件发生,读写数据,接受新的连接,以及处理客户请求均在工作线程中完成
- Procator 将所有 I/O 操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑
5.5 线程同步机制类封装及线程池实现
- 线程池