《Linux系统编程》
《Linux系统编程》 |
|
YanlzLinux_APU_V01_1.0 |
严立钻 |
|
2020.02.03 |
|
|
|
|
|
|
|
##《Linux系统编程》发布说明:
++++“Linux系统编程”:是对“Linux系统编程”的综合探索;开发Linux环境下的应用程序时,需要使用大量的Linux函数;这些函数有的属于Linux操作系统的API,有的属于C语言的标准库函数;
++++“Linux系统编程”:定位在一个科普类知识,了解Linux环境下的应用程序开发!
@@提示:有些博客可能只是开了头,如果感兴趣的同学,可以“点赞”或“评论区留言”,只要关注的同学多了,那就会继续完善哟!(“++==”,表示没有写完的,如果关注度不高就不完善了;“++ok++”,表示此篇博客已经完成,是阶段性完整的!)
$$$$博客溯源:
++++【C/C++函数与算法(C库独立篇)】:https://blog.csdn.net/VRunSoftYanlz/article/details/104026090
++++【C/C++函数与算法(C++库独立篇)】:https://blog.csdn.net/VRunSoftYanlz/article/details/104062275
++++【C/C++函数与算法(算法独立篇)】:https://blog.csdn.net/VRunSoftYanlz/article/details/104062527
++++【C/C++函数与算法(Linux C独立篇)】:https://blog.csdn.net/VRunSoftYanlz/article/details/104076473
++++【Linux系统编程】分类:https://blog.csdn.net/vrunsoftyanlz/category_9694767.html
++++【C++C铸就生存利器】分类:https://blog.csdn.net/vrunsoftyanlz/category_9325802.html
++++【人工智能AI2026】分类:https://blog.csdn.net/vrunsoftyanlz/category_9212024.html
++++【立钻哥哥CSDN空间】:https://blog.csdn.net/VRunSoftYanlz/
++++VR云游戏=Unity+SteamVR+云技术+5G+AI;(说明:AI人工智能不是我们的主要研究技术,只是了解一下,领略一下有风的感觉!但是,VR是我们的研究重点)
##《Linux系统编程》目录
#第一篇:Linux系统编程
#第二篇:Linux系统下的C开发
#第三篇:Linux网络编程
#第四篇:Linux内核驱动
#第五篇:立钻哥哥带您Linux系统编程
#第一篇:Linux系统编程
#第一篇:Linux系统编程 |
#第一篇:Linux系统编程
++++立钻哥哥:程序是一个精确说明如何进行计算的指令序列;编写程序可以说就是这样一个过程:把复杂的任务分解成子任务,把子任务再分解成更简单的任务,层层分解,直到最后简单到可以用指令来完成;
++++A1、文件与I/O
++++A2、文件系统
++++A3、进程
++++A4、Shell脚本
++++A5、正则表达式
++++A6、信号
++++A7、终端、作业控制与守护进程
++++A8、线程
++++A9、TCP/IP协议基础
++++A10、Socket编程
++++A11、立钻哥哥带您Linux系统编程
++A1、文件与I/O
++A1、文件与I/O |
++A1、文件与I/O
++++立钻哥哥:学习Linux系统函数,这些函数的用法必须结合Linux内核的工作原理来理解,因为系统函数正是内核提供给应用程序的接口,而要理解内核的工作原理,必须熟练掌握C语言,因为内核也是用C语言写的,在描述内核工作原理时必然要用到“指针”、“结构体”、“链表”等来组织;
++++[文件描述符]:是文件描述符表的索引(0、1、2、3),用int型变量来保存;当调用open打开一个现有文件或创建一个新文件时,内核分配一个新的文件描述符并返回给进程,当读写该文件时,文件描述符被作为参数传给read或write;
#define STDIN_FILENO 0#define STDOUT_FILENO 1#define STDERR_FILENO 2 |
++open
++++立钻哥哥:open函数可以打开或创建一个文件;
int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode); |
++close
++++立钻哥哥:close函数关闭一个已打开文件;
int close(int fd); |
++read/write
++++立钻哥哥:read函数从打开的设备或文件中读取数据;write函数向打开的设备或文件中写数据;
ssize_t read(int fd, void *buf, size_t count);ssize_t write(int fd, const void *buf, size_t count); |
|
#include <unistd.h> #include <stdlib.h>
int main(void){ char buf[10]; int n;
n = read(STDIN_FILENO, buf, 10); if(n < 0){ perror(“立钻哥哥:read STDIN_FILENO”); exit(1); } write(STDOUT_FILENO, buf, n);
return 0; } |
++lseek
++++立钻哥哥:lseek和标准IO库的fseek函数类似,可以移动当前读写位置(或者叫偏移量);
off_t lseek(int fd, off_t offset, int whence);
|
|
off_t currpos; currpos = lseek(fd, 0, SEEK_CUR); |
++fcntl
++++立钻哥哥:可以用fcntl函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为File Status Flag),而不必重新open文件;
int fcntl(int fd, int cmd);int fcntl(int fd, int cmd, long arg);int fcntl(int fd, int cmd, struct flock *lock); |
++ioctl
++++立钻哥哥:ioctl用于向设备发控制和配置命令,有些命令也需要读写一些数据,但这些数据是不能用read/write读写的,称为Out-of-band数据;
int ioctl(int d, int request, ...); |
++mmap
++++立钻哥哥:mmap可以把磁盘文件的一部分直接映射到内存,这样文件中的位置直接就有对应的内存地址,对文件的读写可以直接用指针来做而不需要read/write函数;
void *mmap(void *addr, size_t len, int prot, int flag, int filedes, off_t off);int munmap(void *addr, size_t len); |
++A2、文件系统
++A2、文件系统 |
++A2、文件系统
++++立钻哥哥:文件系统在内核中是如何实现的?如何呈现给用户一个树状的目录结构?如何处理用户的文件和目录操作请求?磁盘是一种顺序的存储介质,一个树状的目录结构如何扯成一条线存到磁盘上?怎样设计文件系统的存储格式使访问磁盘的效率最高?各种文件和目录操作在磁盘上实际效果是什么?
++++Linux支持各种各样的文件系统格式:ext2、ext3、reiserfs、FAT、NTFS、iso9660等,不同的磁盘分区、光盘或其它存储设备都有不同的文件系统格式,然后这些文件系统都可以mount到某个目录下;
++ext2文件系统
++++立钻哥哥:一个磁盘可以划分成多个分区,每个分区必须先格式化工具格式化成某种格式的文件系统,然后才能存储文件,格式化的过程会在磁盘上写一些管理存储布局的信息;文件系统中存储的最小单位是块(Block),一个块究竟多大是在格式化时确定的;启动块是由PC标准规定的,用来存储磁盘分区信息和启动信息,任何文件系统都不能使用启动块;启动块之后才是ext2文件系统的开始,ext2文件系统将整个分区划成若干个同样大小的块组(Block Group),每个块组都由:超级块(Super Block)、块组描述符表(GDT,Group Descriptor Table)、块位图(Block Bitmap)、inode位图(inode Bitmap)、inode表(inode Table)、数据块等部分组成;
++++[超级块(Super Block)]:描述整个分区的文件系统信息,例如块大小、文件系统版本号、上次mount的时间等等;超级块在每个块组的开头都有一份拷贝;
++++[块组描述符表(GDT,Group Descriptor Table)]:由很多块组描述符组成,整个分区分成多少个块组就对应有多少个块组描述符;
++++[块位图(Block Bitmap)]:是用来描述整个块组中哪些块已用哪些块空闲的,它本身占一个块,其中的每个bit代表本块组中的一个块,这个bit为1表示该块已用,这个bit为0表示该块空闲可用;
++++[inode位图(inode Bitmap)]:和块位图类似,本身占一个块,其中每个bit表示一个inode是否空闲可用;
++++[inode表(inode Table)]:inode表占多少个块在格式化时就要决定并写入块组描述符中;
++++[数据块]:对于常规文件,文件的数据存储在数据块中;
++VFS(Virtual Filesystem,虚拟文件系统)
++++立钻哥哥:Linux内核在各种不同的文件系统格式之上做了一个抽象层,使得文件、目录、读写访问等概念成为抽象层的概念,因此各种文件系统看起来用起来都一样,这个抽象层称为虚拟文件系统(VFS,Virtual Filesystem);
++++每个进程在PCB(Process Control Block)中都保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体;
++A3、进程
++A3、进程 |
++A3、进程
++++立钻哥哥:每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linux内核的进程控制块是task_struct结构体;
++++[fork和exec]:是两个重要的系统调用;fork的作用是根据一个现有的进程复制出一个新进程,原来的进程称为父进程(Parent Process),新进程称为子进程(Child Process);系统中同时运行着很多进程,这些进程都是从最初只有一个进程开始一个一个复制出来的;
++exit和_exit函数
++++立钻哥哥:exit和_exit函数用于终止一个进程;
void exit(int status);void _exit(int status); |
++fork
++++立钻哥哥:fork用来创建新进程;
pid_t fork(void); |
++exec函数族
++++立钻哥哥:用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序;当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行;调用exec并不创建新进程,所以调用exec前后该进程的id并未改变;
int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg, ..., char *const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execve(const char *path, char *const argv[], char *const envp[]); |
++wait和waitpid
++++立钻哥哥:一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个;这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程;
++++如果一个进程已经终止,但是它的父进程尚未调用wait或waitpid对它进行清理,这时的进程状态称为僵尸(Zombie)进程;任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了;
pid_t wait(int *status);pid_t waitpid(pit_t pid, int *status, int options); |
++进程间通信
++++立钻哥哥:每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷贝到内核缓冲区,进程2再从内核缓冲区把数据独奏,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication);
++++[管道]:管道是一种最基本的IPC机制,由pipe函数创建;
int pipe(int filedes[2]); |
++A4、Shell脚本
++A4、Shell脚本 |
--_--VRunSoft:lovezuanzuan--_--