2020年6月
1、Linux系统常用指令
2、命令解析器shell
3、Linux下常用快捷键
tab键的作用
主键盘快捷键
4、linux下的目录结构
5、文件和目录操作相关的命令
5.1 tree命令 以树状形式查看指定目录内容
5.2 ls命令
5.3 cd命令
5.4 pwd命令 查看用户当前所处的工作目录
5.5 which命令 显示命令所在的目录
5.6 touch命令 如果文件不存在, 创建新文件, 如果文件存在, 更新文件的最后修改时间。命令使用方式:touch 文件名
5.7 mkdir命令
5.8 rmdir命令 只能删除空目录
5.9 rm命令
5.10 cp命令
5.11 mv命令
//********** 五个查看文件指令
5.12 cat命令 将文件内容一次性输出到终端。
5.13 more命令 文件内容分页显示到终端,但是只能一直向下浏览,不能回退。
5.14 less命令 文件内容分页显示到终端,可以自由上下浏览。
5.15 head命令
5.16 tail命令 一个比较重要的应用:显示日志 : tail -f test.log
//**********
5.17 软链接
5.18 硬链接
5.19 wc 显示文件行数, 字节数, 单词数
5.20 whoami 显示当前登陆的用户名
6、用户权限、用户、用户组
6.1 修改文件权限chmod
6.2 修改文件所有者和所属组
6.3 修改文件所属组
7、find命令
8、grep命令
9、find和grep命令结合使用
先使用find命令查找文件, 然后使用grep命令查找哪些文件包含某个字符串
如“find . -name "*.c" | xargs grep -n "main" ”
10、Linux中常用的压缩工具
gzip和bzip2 不能压缩目录,只能一个一个文件进行压缩,压缩之后会使原文件消失
tar工具
rar工具
zip工具
11、软件的安装和卸载
11.1 在线安装
软件安装:sudo apt-get install 软件名
软件卸载:sudo apt-get remove 软件名
更新软件列表:sudo apt-get update
清理安装包:sudo apt-get clean
清理的是缓存路径:/var/cache/apt/archives
11.2 软件包安装
在Ubuntu系统下必须有deb格式的安装包
软件安装 sudo dpkg -i xxx.deb
软件卸载 sudo dpkg -r 软件名
12、VIM
12.1 Vi有三种基本工作模式: 命令模式、文本输入模式、末行模式。
12.2 Vim基本操作
命令模式下的操作
切换到文本输入模式
末行模式下的操作
13、gcc编译器
13.1 gcc的工作流程
gcc编译器将c源文件到生成一个可执行程序,中间一共经历了四个步骤:
下面以test.c为例介绍gcc的四个步骤:
gcc -E test.c -o test.i
gcc -S test.i -o test.s
gcc -c test.s -o test.o
gcc test.o -o test
一步生成最终的可执行程序:
gcc test.c -o test
13.2 gcc常用参数
-v 查看gcc版本号, --version也可以
-E 生成预处理文件
-S 生成汇编文件
-c 只编译, 生成.o文件, 通常称为目标文件
-I 指定头文件所在的路径
-L 指定库文件所在的路径
-l 指定库的名字
-o 指定生成的目标文件的名字
-g 包含调试信息, 使用gdb调试需要添加-g参数
14、静态库和共享(动态)库
14.1 库的介绍
什么是库?
使用库有什么好处?
库制作完成后, 如何给用户使用?
14.2 静态库(static library)
静态库可以认为是一些目标代码的集合, 是在可执行程序运行前就已经加入到执行码中,
成为执行程序的一部分. 按照习惯, 一般以.a做为文件后缀名.
静态库的命名一般分为三个部分:前缀:lib; 库名称:自定义即可, 如test;后缀:.a。如,libtest.a
静态库的制作
静态库的使用
静态库的优缺点
14.3 共享库(shared library)/动态库
共享库的制作
共享库的使用
如何让系统找到共享库
共享库的特点
14.4 比较静态库和动态库的优缺点
15、makefile
makefile文件中定义了一系列的规则来指定, 哪些文件需要先编译, 哪些文件需要后编译,
哪些文件需要重新编译, 甚至于进行更复杂的功能操作, 因为makefile就像一个Shell脚本一样,
其中也可以执行操作系统的命令. makefile带来的好处就是——“自动化编译”, 一旦写好,
只需要一个make命令, 整个工程完全自动编译, 极大的提高了软件开发的效率.
15.1 makefile的基本规则
makefile基本规则三要素:
目标: 要生成的目标文件
依赖: 目标文件由哪些文件生成
命令: 通过执行该命令由依赖文件生成目标
15.2 makefile工作原理
基本原则:
若想生成目标, 检查规则中的所有的依赖文件是否都存在:
如果有的依赖文件不存在, 则向下搜索规则, 看是否有生成该依赖文件的规则:
如果有规则用来生成该依赖文件, 则执行规则中的命令生成依赖文件;
如果没有规则用来生成该依赖文件, 则报错.
如果所有依赖都存在, 检查规则中的目标是否需要更新, 必须先检查它的所有依赖,
依赖中有任何一个被更新, 则目标必须更新.(检查的规则是哪个时间大哪个最新)
若目标的时间 > 依赖的时间, 不更新
若目标的时间 < 依赖的时间, 则更新
15.3 makefile中的变量
在makefile中使用变量有点类似于C语言中的宏定义, 使用该变量相当于内容替换,
使用变量可以使makefile易于维护, 修改起来变得简单。
makefile有三种类型的变量:
普通变量
自带变量
自动变量
15.4 makefile函数
makefile中的函数有很多, 在这里给大家介绍两个最常用的。
1. wildcard – 查找指定目录下的指定类型的文件
src=$(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src
2. patsubst – 匹配替换
obj=$(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
15.5 makefile的清理操作
16、gdb调试
16.1 gdb介绍
GDB(GNU Debugger)是GCC的调试工具。其功能强大, 现描述如下:
GDB主要帮忙你完成下面四个方面的功能:
*启动程序, 可以按照你的自定义的要求随心所欲的运行程序。
*可让被调试的程序在你所指定的断点处停住。(断点可以是条件表达式)
*当程序被停住时, 可以检查此时你的程序中所发生的事。
*动态的改变你程序的执行环境。
16.2 生成调试信息
16.3 启动gdb
16.4 显示源代码
16.5 设置断点
16.6 调试代码
16.7 查看变量的值
17、文件IO
从本章开始学习各种Linux系统函数, 这些函数的用法必须结合Linux内核的工作原理来理解,
因为系统函数正是内核提供给应用程序的接口, 而要理解内核的工作原理, 必须熟练掌握C语言,
因为内核也是用C语言写的, 我们在描述内核工作原理时必然要用“指针”、“结构体”、“链表”这些名词来组织语言,
就像只有掌握了英语才能看懂英文书一样, 只有学好了C语言才能看懂我描述的内核工作原理。
3.1 C库IO函数的工作流程
3.2 C库函数与系统函数的关系
3.3 虚拟地址空间
3.4 pcb和文件描述符表
2020年6月28日(文件和目录操作)
1、文件权限计算方法:
mode & ~umask
2 思考: 阻塞和非阻塞是文件的属性还是read函数的属性?
通过读普通文件测试得知: read函数在读完文件内容之后, 若再次read,则
read函数会立刻返回, 表明read函数读普通文件是非阻塞的.
设备文件: /dev/tty 标准输入STDIN_FILENO
通过读/dev/tty终端设备文件, 表明read函数读设备文件是阻塞的.
结论: 阻塞和非阻塞不是read函数的属性, 而是文件本身的属性.
socket pipe这两种文件都是阻塞的.
使用st_mode成员判断文件类型:
if((sb.st_mode & S_IFMT) ==S_IFLNK)
{
printf("连接文件\n");
}
if (S_ISREG(sb.st_mode))
{
printf("普通文件\n");
}
判断文件权限:
if(sb.st_mode & S_IROTH)
{
printf("---R----");
}
3、lstat和stat函数:
3.1 对于普通文件来说, lstat函数和stat函数一样
3.2 对于软连接文件来说, lstat函数获取的是连接文件本身的属性,
stat函数获取的是连接文件指向的文件的属性.
4、目录操作:
4.1 打开目录 opendir
4.2 循环读目录: readdir
4.3 关闭目录: closedir
5、dup和dup2函数:
复制文件描述符----详情看图
6、fcntl函数:
6.1 复制文件描述符: int fd = fcntl(oldfd, F_DUPFD, 0);
6.2 获得和设置文件的flag属性:
int flag = fcntl(fd, F_GETFL, 0);
flag |= O_APPEND;
fcntl(fd, F_SETFL, flag);
2020年6月30日(进程控制)
1、程序与进程
什么是程序?编译好的二进制文件
什么是进程?运行着的程序。
程序员角度:运行一系列指令的过程
操作系统角度:分配系统资源的基本单位
二者区别:
*程序占用磁盘,不占用系统资源
*内存占用系统资源
*一个程序对应多个进程
2、fork与父子程序
3、execlp族函数
4、孤儿进程与僵尸进程
孤儿进程:父进程kill,子进程被init进程领养
僵尸进程:子进程kill,父进程没有回收子进程的资源(PCB)。有害
如何解决僵尸进程?kill父进程,子进程的资源被init进程回收。
5、wait函数 回收子进程或多个子进程
返回值 成功 终止子进程的ID 失败 -1
作用:*阻塞等待 *回收子进程资源 *查看死亡原因
6、waitpid函数 回收多个子进程
返回值 成功 终止子进程的ID 子进程都回收了 -1
2020年7月1日(进程控制)
1、IPC 进程间通信
(1)pipe管道 半双工 ps_grep
优点:简单,相比信号,套接字实现进程间通信,简单很多。
缺点:1. 只能单向通信,双向通信需建立两个管道。
2. 只能用于父子、兄弟进程(有共同祖先)间通信。该问题后来使用fifo有名管道解决。
(2)fifo有名管道
FIFO常被称为命名管道,以区分管道(pipe)。管道(pipe)只能用于“有血缘关系”的进程间。
但通过FIFO,不相关的进程也能交换数据。
FIFO是Linux基础文件类型中的一种。但,FIFO文件在磁盘上没有数据块,仅仅用来标识内核中一条通道。
各进程可以打开这个文件进行read/write,实际上是在读写内核通道,这样就实现了进程间通信。
(3)mmap文件映射共享IO --速度最快
1、munmap函数
2、mmap父子进程通信
3、匿名映射
4、mmap无血缘关系进程间通信
(4)本地socket --最稳定
(5)信号 --携带信息量最小
(6)共享内存
(7)消息队列
2、信号的概念
2020年7月2日(信号)
1、学习目标
*了解信号中的基本概念
*熟练使用信号相关的函数
*参考文档使用信号集操作相关函数
*熟练使用信号捕捉函数signal
*熟练使用信号捕捉函数sigaction
*熟练掌握使用信号完成子进程的回收
2、信号的机制
进程A给进程B发送信号,进程B收到信号之前执行自己的代码,收到信号后,不管执行到程序的什么位置,
都要暂停运行,去处理信号,处理完毕后再继续执行。与硬件中断类似——异步模式。
但信号是软件层面上实现的中断,早期常被称为“软中断”。
每个进程收到的所有信号,都是由内核负责发送的。
2.1 信号的状态
信号有三种状态:产生、未决和递达。
未决:产生和递达之间的状态。主要由于阻塞(屏蔽)导致该状态。
递达:递送并且到达进程。
2.2 信号的处理方式
执行默认动作
忽略信号(丢弃不处理)
捕捉信号(调用用户的自定义的处理函数)
2.3 信号的特质
信号的实现手段导致信号有很强的延时性,但对于用户来说,时间非常短,不易察觉。
2.4 阻塞信号集和未决信号集
阻塞信号集中保存的都是被当前进程阻塞的信号。若当前进程收到的是阻塞信号集中的某些信号,
这些信号需要暂时被阻塞,不予处理。
信号产生后由于某些原因(主要是阻塞)不能抵达,这类信号的集合称之为未决信号集。
在屏蔽解除前,信号一直处于未决状态;若是信号从阻塞信号集中解除阻塞,则该信号会被处理,并从未决信号集中去除。
2.5 信号的四要素
1 信号的编号
2 信号的名称
3 产生信号的事件
4 信号的默认处理动作
3、信号相关函数
3.1 signal函数
函数作用:注册信号捕捉函数
3.2 kill函数/命令
描述:给指定进程发送指定信号
3.3 abort函数raise函数
raise函数 函说描述:给当前进程发送指定信号(自己给自己发)
abort函数 函数描述:给自己发送异常终止信号 6) SIGABRT,并产生core文件
3.4 alarm函数
函数描述:设置定时器(闹钟)。在指定seconds后,内核会给当前进程发送14)SIGALRM信号。
进程收到该信号,默认动作终止。每个进程都有且只有唯一的一个定时器。
3.5 setitimer函数
函数描述:设置定时器(闹钟),可代替alarm函数,精度微秒us,可以实现周期定时
4、信号集相关
4.1 未决信号集和阻塞信号集的关系
阻塞信号集是当前进程要阻塞的信号的集合,未决信号集是当前进程中还处于未决状态的信号的集合,
这两个集合存储在内核的PCB中。
4.2 信号集相关函数
由于信号集属于内核的一块区域,用户不能直接操作内核空间,为此,内核提供了一些信号集相关的接口函数,
使用这些函数用户就可以完成对信号集的相关操作。
上述变量类型的定义的查找有个小窍门: 可以执行gcc的预处理命令:
gcc -E test.c -o test.i 这样头文件就会展开,可以直接到test.i文件中看到相关变量类型的定义。
5、信号捕捉函数
signal函数
sigaction函数
6、SIGCHLD信号
6.1 产生SIGCHLD信号的条件
子进程结束的时候
子进程收到SIGSTOP信号
当子进程停止时,收到SIGCONT信号
6.2 SIGCHLD信号的作用
子进程退出后,内核会给它的父进程发送SIGCHLD信号,父进程收到这个信号后可以对子进程进行回收。
6.3 使用SIGCHLD信号完成对子进程的回收
2020年7月4日(守护进程和线程)
学习目标
说出守护进程的特点
独立完成守护进程的创建
独立实现多个线程的创建
独立实现线程的退出和资源回收
理解线程同步的思想
1、守护进程
1.1 守护进程介绍
Daemon(精灵)进程,是Linux中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。
一般采用以d结尾的名字,如vsftpd。Linux后台的一些系统服务进程,没有控制终端,不能直接和用户交互。
不受用户登录、注销的影响,一直在运行着,他们都是守护进程。如:预读入缓输出机制的实现;ftp服务器;nfs服务器等。
总结守护进程的特点:
* Linux后台服务进程
* 独立于控制终端
* 周期性的执行某种任务
* 不受用户登陆和注销的影响
* 一般采用以d结尾的名字
1.2 进程组和会话
进程组是一个或者多个进程的集合,每个进程都属于一个进程组,引入进程组是为了简化对进程的管理。
当父进程创建子进程的时候,默认子进程与父进程属于同一个进程组。
会话 * 一个会话是一个或多个进程组的集合。
* 创建会话的进程不能是进程组组长
* 创建会话的进程成为一个进程组的组长进程,同时也成为会话的会长。
* 需要有root权限(ubuntu不需要)
* 新创建的会话丢弃原有的控制终端
* 建立新会话时,先调用fork, 父进程终止,子进程调用setsid函数
可以使用ps ajx来查看进程组ID和会话ID
进程组和会话的关系图
1.3 创建守护进程的模型
第1步:fork子进程,父进程退出
第2步:子进程调用setsid函数创建新会话
第3步:改变当前工作目录chdir
第4步:重设文件掩码 mode & ~umask
第5步:关闭文件描述符
第6步:执行核心工作
2、线程
2.1 什么是线程
线程:有PCB,但没有独立的地址空间,多个线程共享进程空间,相当于合租。
在Linux操作系统下:
线程:最小的执行单位
进程:最小分配资源单位,可看成是只有一个线程的进程。
线程的特点
* 类Unix系统中,早期是没有“线程”概念的,80年代才引入,借助进程机制实现出了线程的概念。因此在这类系统中,进程和线程关系密切。
* 线程是轻量级进程(light-weight process),也有PCB,创建线程使用的底层函数和进程一样,都是clone
* 从内核里看进程和线程是一样的,都有各自不同的PCB.
* 进程可以蜕变成线程
* 在linux下,线程最是小的执行单位;进程是最小的分配资源单位
如果复制对方的地址空间,那么就产出一个“进程”;
如果共享对方的地址空间,就产生一个“线程”。
2.2 线程共享资源
2.3 线程非共享资源
2.4 线程优、缺点
优点:
* 提高程序并发性
* 开销小
* 数据通信、共享数据方便
缺点:
* 库函数,不稳定
* gdb调试、编写困难
* 对信号支持不好
优点相对突出,缺点均不是硬伤。Linux下由于实现方法导致进程、线程差别不是很大。
2.5 pthread_create函数
2.6 pthread_exit函数
在线程中禁止调用exit函数,否则会导致整个进程退出,取而代之的是调用pthread_exit函数,这个函数是使一个线程退出,
如果主线程调用pthread_exit函数也不会使整个进程退出,不影响其他线程的执行。
2.7 pthread_join函数
函数描述:阻塞等待线程退出,获取线程退出状态。其作用,对应进程中的waitpid() 函数。
2.8 pthread_detach函数
线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。
进程若有该机制,将不会产生僵尸进程。僵尸进程的产生主要由于进程死后,大部分资源被释放,一点残留资源仍存于系统中,导致内核认为该进程仍存在。
2.9 pthread_cancel函数
函数描述:杀死(取消)线程。其作用,对应进程中 kill() 函数。
2.10 pthread_equal函数
函数描述:比较两个线程ID是否相等。
2.11 进程函数和线程函数比较
3、线程属性
linux下线程的属性是可以根据实际项目需要,进行设置,之前讨论的线程都是采用线程的默认属性,
默认属性已经可以解决绝大多数开发时遇到的问题,如果对程序的性能提出更高的要求,则需要设置线程属性,
本节以设置线程的分离属性为例讲解设置线程属性。
4、线程同步
4.1 线程同步的概念
线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。
同时其它线程为保证数据一致性,不能调用该功能。
4.3 互斥锁主要相关函数
* pthread_mutex_t 类型
pthread_mutex_init函数 初始化一个互斥锁(互斥量) ---> 初值可看作1
pthread_mutex_destroy函数 销毁一个互斥锁
pthread_mutex_lock函数 对互斥所加锁,可理解为将mutex--
pthread_mutex_unlock函数 对互斥所解锁,可理解为将mutex ++
pthread_mutex_trylock函数 尝试加锁
4.4 加锁和解锁
lock尝试加锁,如果加锁不成功,线程阻塞,阻塞到持有该互斥量的其他线程解锁为止。
unlock主动解锁函数,同时将阻塞在该锁上的所有线程全部唤醒,至于哪个线程先被唤醒,取决于优先级、调度。
默认:先阻塞、先唤醒。
总结:使用互斥锁之后,两个线程由并行变为了串行,效率降低了,但是可以使两个线程同步操作共享资源,从而解决了数据不一致的问题。
线程同步:
互斥锁: 线程A和线程B共同访问共享资源, 当线程A想访问共享资源的时候,
要先获得锁, 如果锁被占用, 则加锁不成功需要阻塞等待对方释放锁;
若锁没有被占用, 则获得锁成功--加锁, 然后操作共享资源, 操作完之后,
必须解锁, 同理B也是和A一样.
---->也就是说, 同时不能有两个线程访问共享资源, 属于互斥操作.
2020年7月5日(线程同步)
学习目标:
熟练掌握互斥量的使用
说出什么叫死锁以及解决方案
熟练掌握读写锁的使用
熟练掌握条件变量的使用
理解条件变量实现的生产消费者模型
理解信号量实现的生产消费者模型
1、互斥锁
1.1 互斥锁的使用步骤
第1步:创建一把互斥锁
pthread_mutex_t mutex;
初始化互斥锁
pthread_mutex_init(&mutex);---相当于mutex=1
在代码中寻找共享资源(也称为临界区)
pthread_mutex_lock(&mutex); -- mutex = 0
[临界区代码]
pthread_mutex_unlock(&mutex); -- mutex = 1
释放互斥锁资源
pthread_mutex_destroy(&mutex);
注意:必须在所有操作共享资源的线程上都加上锁否则不能起到同步的效果。
1.3 死锁
死锁并不是linux提供给用户的一种使用方法,而是由于用户使用互斥锁不当引起的一种现象。
2、读写锁
读写锁也叫共享-独占锁。当读写锁以读模式锁住时,它是以共享模式锁住的;
当它以写模式锁住时,它是以独占模式锁住的。写独占、读共享。
读写锁非常适合于对数据结构读的次数远大于写的情况。读锁、写锁并行阻塞,写锁优先级高。
读并行,写独占,当读写同时等待锁的时候写的优先级高
3、条件变量
条件本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场 所。
条件变量的两个动作:条件不满足, 阻塞线程;条件满足, 通知阻塞的线程解除阻塞, 开始工作。
4、信号量
信号量相当于多把锁, 可以理解为是加强版的互斥锁
2 相关函数
定义信号量 sem_t sem;
int sem_init(sem_t *sem, int pshared, unsigned int value);
函数描述: 初始化信号量
函数参数:
sem: 信号量变量
pshared: 0表示线程同步, 1表示进程同步
value: 最多有几个线程操作共享数据
函数返回值:成功返回0, 失败返回-1, 并设置errno值
int sem_wait(sem_t *sem);
函数描述: 调用该函数一次, 相当于sem--, 当sem为0的时候, 引起阻塞
函数参数: 信号量变量
函数返回值: 成功返回0, 失败返回-1, 并设置errno值
int sem_post(sem_t *sem);
函数描述: 调用一次, 相当于sem++
函数参数: 信号量变量
函数返回值: 成功返回0, 失败返回-1, 并设置errno值
int sem_trywait(sem_t *sem);
函数描述: 尝试加锁, 若失败直接返回, 不阻塞
函数参数: 信号量变量
函数返回值: 成功返回0, 失败返回-1, 并设置errno值
int sem_destroy(sem_t *sem);
函数描述: 销毁信号量
函数参数: 信号量变量
函数返回值: 成功返回0, 失败返回-1, 并设置errno值
2020年7月10日(网络编程基础-socket)(tcp三次握手-并发)
1、网络基础
1. 协议的概念
2. 网络应用程序设计模式
3. 分层模型OSI、TCP/IP
4. 通信过程
5. 协议格式
6. TCP协议
常见网络知识面试题
1. TCP如何建立链接
2. TCP如何通信
3. TCP如何关闭链接
4. 什么是滑动窗口
5. 什么是半关闭
6. 局域网内两台机器如何利用TCP/IP通信
7. internet上两台主机如何进行通信
8. 如何在internet上识别唯一一个进程
答:通过“IP地址+端口号”来区分不同的服务
9. 为什么说TCP是可靠的链接,UDP不可靠
10. 路由器和交换机的区别
11. 点到点,端到端
2、Socket编程
1. 套接字概念
2. 预备知识
网络字节序
IP地址转换函数
sockaddr数据结构
3. 网络套接字函数
4. C/S模型-TCP
5. 出错处理封装函数
3、高并发服务器
1. 多进程并发服务器
2. 多线程并发服务器
3. 多路I/O转接服务器
4. epoll进阶
2020年7月11日(广播组播、本地套接字、libevent)
2020年7月12日(HTML、HTTP协议)
2020年7月14日(HTTP、正则表达式)
2020年7月14日(线程池)