文件与I/O
文件系统
![]()
- * 每个进程在PCB(Process Control Block)中都保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指针,指向内核中的file结构体
- file结构体成员
- f_flags:File Status Flag
- f_pos:当前读写位置
- f_count:引用计数(Reference Count)
- 每个file结构体指向一个file_operations结构体,这个结构体成员都是函数指针,指向实现各种文件操作的内核函数
- 每个file结构体都有一个指向dentry(directory entry 目录项)结构体的指针,内核在dentry cache中缓存了目录的树状结构,每个节点是一个dentry结构体,可根据路径(如/home/akaedu/a)找到文件的inode
- inode结构体保存着从磁盘分区的inode上读来的信息,如所有者、文件大小、类型、权限等
- 每个inode结构体都有一个指向inode_operations结构体的指针,后者是一组函数指针指向一些完成文件目录操作的内核函数,如添加删除文件和目录、跟踪符号链接等
- inode结构体有一个指向super_block结构体的指针,后者保存着从磁盘分区的超级块上读来的信息,如文件系统类型,块大小等,其s_root成员是一个指向dentry的指针,表示这个文件系统的根目录被mount到哪里
- dup和dup2可用来复制一个现存的文件描述符,使这两个文件描述符指向同一个file结构体
- 硬链接(hard link):一个inode号对应多个文件名,即一个文件使用了多个别名
- 软链接(soft link):一个inode号对应一个文件名,普通文件
![]()
![]()
进程
![]()
环境变量
- PATH:可执行文件的搜索路径,可包含多个目录,用:隔开,通过echo命令查看值
- SHELL:当前Shell,值通常是/bin/bash
- TERM:当前终端类型
- LANG:语言和locale,决定字符编码及时间、货币等信息的显示格式
- HOME:当前用户主目录的路径
进程控制
- fork:系统调用函数,调用后进入内核,根据父进程复制出一个子进程。调用一次,返回两次(父进程调用一次,父进程和子进程中各返回一次)
- gdb只能跟踪一个进程(默认是父进程),而不能同时跟踪多个进程
- exec:用fork创建子进程后,子进程需要调用exec以执行另一个程序
- wait和waitpid:进程终止是Shell(父进程)调用wait或waitpid得到它的退出状态同时彻底删除这个进程,若进程终止后但父进程未调用wait或waitpid对它进行清理,这是的进程状态为僵尸进程
进程间通信
- 每个进程各自有不同的用户地址空间,看不到其他进程的全局变量,进程间要交换数据必须通过内核
- 在内核中开辟一块缓冲区,进程1把数据从用户空间拷贝到缓冲区,进程2再从内核缓冲区把数据读走,这种机制称为进程间通信(IPC,InterProcess Communication)
- 管道是一种最基本的IPC机制,由pipe函数创建,有以下限制
- 两个进程通过一个管道只能实现单向通信,如果是子进程写父进程读,需要开另一个管道
- 管道的读写端通过打开文件描述符传递,需通过fork传递文件描述符
- 管道的4种特殊情况
- 所有指向管道写端的文件描述符都关闭了
- 有指向管道写端的文件描述符没关闭
- 所有指向管道读端的文件描述符都关闭了
- 有指向管道读端的文件描述符没关闭
- 其他IPC机制:FIFO、Unix Domain Socket(目前使用最广泛),利用文件系统中的特殊文件来标识IPC通道
Shell脚本
如何执行命令
- 解释执行用户的命令,输入一条,解释执行一条,执行方式有交互式(Interactive)和批处理(Batch)(用户事先写一个Shell脚本(Script),Shell一次执行完)两种
- 用户在命令行输入命令后,Shell会fork并exec该命令,但内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程
基本语法
- 变量:由大写字母加下划线组成,分环境变量和本地变量(只存在于当前Shell进程)
- 文件名代换(Globbing):用于匹配的字符称为通配符(Wildcard)
- 命令代换:``或$()中的是一条命令
- 算数代换:$(())中的Shell变量取值将转换成整数
- 转义字符:\用于去除紧跟其后的单个字符的特殊意义
- 单引号、双引号:保持引号内所有字符的字面值
bash启动脚本
- 可以把环境变量和alias、umask设置放在启动脚本中,每次启动Shell时都生效
- bash的启动方式
- 作为交互登录Shell启动,或使用--login参数启动
- 交互非登录Shel启动
- 非交互启动
- 以sh命令启动
- Shell脚本语法
- 条件测试:test 或 [
- if/then/elif/else/fi
- case/esac
- for/do/done
- while/do/done
- 位置参数和特殊变量
- 函数
- Shell脚本的调试方式
正则表达式
引言
- 正则表达式:规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普通字符串一起表示一个模式(Pattern)
- 模式包含的信息:字符类(Character Class)、数量限定符(Quantifier),字符间位置关系
- 应用:验证用户输入(ip、email)格式是否合法
基本语法
常用命令
- grep
- sed:流编辑器(Stream Editor),在Shell脚本中作为过滤器使用,把前一个程序的输出引入sed的输入,经过编辑后转换为另一种格式输出
- awk:以行或列为处理单位
信号
基本概念
- 按下Ctrl-C产生的信号发给前台进程(硬件中断),CPU从用户态切换到内核态处理中断
- 信号相对于进程的控制流程来说是异步的
- kill -l 查看系统定义的信号列表,每个信号有一个标号和一个宏名称,宏定义可在signal.h中找到
- 每个信号都有产生条件和默认的处理动作
产生信号
阻塞信号
- 执行信号的处理动作称为信号递达(Delivery)
- 信号从产生到递达之间的状态称为信号未决(Pending)
- 进程可选择阻塞(Block)某个信号,被阻塞的信号产生时保持在未决状态,直到进程解除阻塞,才执行递达动作
捕捉信号
- 信号处理动作是用户自定义函数(signal handler),信号递达时调用这个函数,返回后自动执行系统调用sigreturn再次进入内核态,没有新的信号递达,返回main的上下文继续执行
![]()
终端、作业控制与守护进程
终端
- 串口终端:嵌入式开发中,目标板的每个串口对应一个终端设备
- 虚拟终端(Virtual Terminal):
/dev/tty1
~/dev/tty6
- 终端缓冲:终端设备的输入/输出缓冲队列
- 终端登录:内核中处理终端设备的模块包括硬件驱动程序和线路规程(Line Discipline)
- 网络终端/图形终端(窗口):数目不限,通过伪终端(Pseudo TTY)实现,一套伪终端由一个主设备(PTY Master,相当于键盘和显示器)和一个从设备(PTY Slave)组成
![]()
![]()
作业控制(Job Control):
- 作业(Job)指进程组(Process Group),Shell可以同时运行一个前台作业和多个后台作业
- Session:拥有相同控制终端的一组进程
![]()
守护进程(Daemon)
- Linux中的系统服务进程,没有控制终端,不能和用户交互,不受用户登录和注销的影响一直运行
线程
线程的概念
- 在一个进程中同时执行多个控制流程,如一个图形界面的下载软件,要一边和用户交互,等待和处理用户的鼠标键盘事件,一边同时下载多个文件,等待和处理从多个网络主机发来的数据
- 多任务的“等待-处理”循环可以用多线程实现
- 同一进程的多个线程共享同一地址空间
线程控制
线程间同步
- 互斥锁(Mutex, Mutual Exclusive Lock):代表资源的可用数量,非0即1,获得锁的线程可以完成“读-修改-写”的操作,然后释放锁给其他线程,没有锁的线程只能等待而不能访问共享数据,保证了“读-修改-写”是原子操作(要么都执行,要么都不执行),不会执行到中间被打断,也不会在其他处理器上并行这个操作
- 死锁(Deadlock)
- 条件变量(Condition Variable)
- 信号量(Semaphore):可用的资源数量,可大于1
- 其他线程间同步机制
TCP/IP协议基础
TCP/IP协议栈与数据包封装
- 数据包名称:传输层--段(segment),网络层--数据报(datagram),链路层--帧(frame)
![]()
![]()
- 以太网帧格式
- ARP数据报格式
- IP数据报格式
- IP地址与路由
- 使用私有IP地址的主机可通过代理服务器或NAT(网络地址转换)链接到Internet
- 本机回环测试(loop back)
![]()
![]()
socket编程
- 预备知识
- 基于TCP协议的网络程序
- select:网络程序中的一个系统调用,可同时监听多个阻塞的文件描述符(如多个网络连接),哪个有数据就先处理哪个,从而不需fork和多进程就可实现并发服务的server
- 基于UDP协议的网络程序
- UNIX Domain Socket IPC
- 简单的Web服务器
![]()
参考
Linux C编程一站式学习
http://docs.linuxtone.org/ebooks/C&CPP/c/
IBM教程
https://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/index.html
硬连接和软连接
https://blog.csdn.net/Y_Hanxiao/article/details/83986797
https://www.cnblogs.com/diantong/p/10507132.html