[Linux] 《Linux C编程一站式学习》Part.3【Linux系统编程】

文件与I/O

  • C标准I/O库函数与Unbuffered I/O函数
    • C标准I/O库函数printf()、putchar()、fputs(),会在用户空间开辟I/O缓冲区
    • 系统函数open()、read()、write()、close()等位于C标准库的I/O缓冲区的底层,也称为无缓冲I\O(Unbuffered I/O)函数
    • 读写常规文件时调用标准库I/O比Unbuffered I/O要快,且不需自己管理I/O缓冲区
    • 读写终端或网络设备等不需要缓冲区,通常直接调用Unbuffered I/O
    • 每个进程在Linux内核中都有一个task_struct结构体来维护进程相关的信息,称为进程描述符(Process Descriptor)
    • task_struct中有一个指针指向files_struct结构体,称为文件描述表,其中每个表项包含一个指向已打开的文件的指针
    • 用户不能直接访问内核中的文件描述表,而只能使用文件描述符表的索引(0、1、2等),称为文件描述符,用int型变量保存
    • 调用open打开一个文件时,内核分配一个文件描述符并返回给用户程序,该文件描述符表项中的指针指向新打开的文件
    • 读写文件时,用户程序把文件描述符传给read或write,内核根据文件描述符找到相应的表项,再通过表项中的指针找到相应文件
    • 程序启动时会自动打开三个文件:标准输入、标准输出和标准错误输出
  • open/close
    • int open(const char *pathname, int flags, ... );
    • 文件权限由open的mode参数和当前进程的umask掩码共同决定
    • int close(int fd);
  • read/write
    • 阻塞(Block):进程调用一个阻塞的函数时,该进程被置于睡眠(Sleep)状态,这是内核调度其他程序进行,直到该进程等待的事件发生了(如网络上接收到数据包)才有可能继续运行
    • 运行(Running):正在被执行或就绪状态(随时都可执行)
    • 轮询(Poll):本来应该阻塞在这里但事实上没有阻塞,而是直接返回错误,调用者应试着再读一次
    • 非阻塞I/O有个缺点,如果所有设备都一直没有数据到达,调用者需要反复查询做无用功,如果阻塞在那里,操作系统可以调度别的进程执行
    • 使用非阻塞I/O时,通常不会在一个while循环中不停查询,而是没延迟议会来查询一下,在延迟等待的时候可以调度其他进程执行,但这样的缺点是有数据到达时可能不能及时处理
    • select(2)函数可以阻塞地同时监视多个设备,还可以设定阻塞等待的超时时间
  • lseek
    • 移动当前读写位置(偏移量)
  • fcntl
    • 文件状态属性(File Status Flag):当前进程如何访问设备或文件,如读、写、追加、非阻塞等
    • 重新设置一个已打开的文件的状态属性,而不必重新open文件
    • Shell重定向语法:在<、>、>>、<>前添加一个数字,该数字就表示在哪个文件描述符上打开文件
    • $ command > /dev/null 2>&1:将命令command的标准输出重定向到/dev/null,然后将该命令可能产生的错误信息(标准错误输出)也重定向到和标准输出(&1,不加&会被解释成文件名)相同的文件,即/dev/null
    • 写在/dev/null文件中的数据不会被显示,即执行命令但不打印正常或错误信息
  • ioctl
    • 传送控制信息,文件或设备本身的属性,如串口波特率、终端窗口大小等
    • read/write读写的数据,是I/O操作的主体,称为in-band数据;不能用read/write读写的数据,称为Out-of-band数据
  • mmap
    • 把磁盘文件的一部分直接映射到内存,对文件的读写可直接用指针而不需通过read/write函数

文件系统

  • 引言
    • 如何呈现给用户一个树状目录结构?如何处理用户的文件和目录操作请求?
    • 如何让树状目录结构实现在磁盘上的线性存储?怎样设计文件系统的存储格式使访问磁盘的效率最高?
    • 各种文件和目录操作在磁盘上的实际效果是什么?
  • ext2文件系统
    • 文件系统中最小的单位是块(Block),ext2文件系统将整个分区划分成若干个同样大小的块组(Block Group),每个块组都由以下部分组成:
      • 超级块(Super Block):描述正而过分区的文件系统信息,如块大小、文件系统版本号
      • 块组描述符表(GDT,Group Descriptor Table):存储一个块组的描述信息,如从哪里开始是inode表,从哪里开始是数据块等。整个分区分成多少个块组就对应有多少个块组描述符
      • 块位图(Block Bitmap):描述整个块组中哪些块已用哪些块空闲
      • inode位图(inode Bitmap):和块位图类似,本身占一个块,其中每个bit表示一个inode是否空闲
      • inode表(inode Table):存储文件的描述信息,如文件类型、权限、大小、创建/修改/访问时间等,即ls -l命令看到的那些信息
      • 数据块:存储文件数据
    • 磁盘的最小读写单位称为扇区(Sector),通常是512字节
    • 数据块寻址
    • 文件和目录操作的系统函数:
      • stat(2):读取文件的inode
      • access(2)
      • chmod(2)
      • chown(2)
      • utime(2)
      • truncate(2)
      • link(2)
      • rename(2)
      • mkdir(2)
      • rmdir(2)
  • 虚拟文件系统(VFS,Virtual File System):Linux内核在各种不同的文件格式之上做了一个抽象层,使得文件、目录、读写访问等概念称为抽象层的概念,因此各种文件系统看起来和用起来都一样
    • Linux的文件系统:网络文件系统、磁盘文件系统、特殊文件系统等
    • VFS作为一个通用文件系统,抽象了文件系统的四个基本概念,文件、目录项、索引节点、挂载点
    • 在Linux中除进程外一切皆是文件
    • VFS的四个基本对象
      • 超级块对象(superblock object):一个已安装的文件系统
      • 索引节点对象(inode object):一个文件
      • 目录项对象(dentry object):一个目录
      • 文件对象(file object):由进程打开文件

    • 每个进程在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号对应一个文件名,普通文件

进程

  • 引言
    • 每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux的PCB是task_struct结构体,主要包括以下信息
      • 进程id:一个非负整数,系统中每个进程有唯一的id
      • 进程的状态:运行、挂起、停止、僵尸等
      • 进程切换时需要保存和恢复的一些CPU寄存器
      • 描述虚拟地址空间的信息
      • 描述控制终端的信息
      • 当前工作目录
      • umask掩码
      • 文件描述符表,包含很多指向file结构体的指针
      • 和信号相关的信息
      • 用户id和组id
      • 控制终端、Session和进程组
      • 进程可以使用的资源上限(Resource Limit)
    • fork:根据一个现有的进程(父进程 Parent Process)复制出一个新的进程(子进程 Child Process)
    • exec:执行新的程序

  • 环境变量
    • 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脚本的调试方式
      • -n
      • -v
      • -x

正则表达式

  • 引言
    • 正则表达式:规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普通字符串一起表示一个模式(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)

 

    • 路由表 
  •  UDP段格式
  • TCP协议

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

猜你喜欢

转载自www.cnblogs.com/cxc1357/p/12378555.html