进程替换与基础IO
文章目录
1.进程程序替换原理
因为父进程创建出来的子进程和父进程拥有相同的代码段,所以,子进程看到的代码和父进程是一样的。
当我们想要让子进程执行不同的程序时候,就需要让子进程调用进程程序替换的接口,从而让子进程执行不一样的代码
原理:用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动
例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。简单来说就是替换进程的代码段和数据段,更新堆栈
图解:
2.exec函数簇
1.替换函数:
有六种以exec开头的函数,统称exec函数:
#include <unistd.h>`
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[]);
2.函数解释
- 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
- 如果调用出错则返回-1
- 所以exec函数只有出错的返回值而没有成功的返回值。
3.命名理解
- l(list) : 表示参数采用列表,传递给可执行的程序的命令行参数,第一个参数,需要可执行程序本身,如果需要传递多个参数,则用“,”进行间隔,末尾以NULL结尾
- v(vector) : 参数用数组,传递给可执行的程序的命令行参数,以指针数组的方式进行传递。第一个参数,需要可执行程序本身,多个参数就都放到数组当中,末尾以NULL结尾
- p(path) : 有p自动搜索环境变量PATH,可执行程序,可以带有路径,也可以不带路径
- e(env) : 表示自己维护环境变量,程序员调用该函数的时候,需要自己组织环境变量传递给函数
4.总结:
3.函数之间的区别
只有execve是真正的系统调用函数,其他五个函数最终都调用excve,关系如图:
4.C语言下的文件接口
1.fopen
**FILE *fopen(const char path,const char mode);
- path :带有路径的文件名称,(如果说不带有路径,打开的文件可以是在当前路径下)
- mode :打开文件的方式
- r :只读模式打开
文件流是指向了文件起始位置- r+:以可读可写的方式打开
文件流是指向了文件起始位置- w:当前文件如果存在,则截断(清空文件内容)文件当前文件不存在,则创建一个新文件
- w+:以可读可写的方式打开
当前文件如果存在,则截断(清空文件内容)文件当前文件不存在,则创建一个新文件- a:追加写
如果当前文件不存在,则创建文件
如果当前文件存在,则将文件流指针指向文件末尾进行写。- a+:可以读,也可以追加写
如果文件不存在,则创建文件
读的位置被初始化到文件的头,但是追加的写的时候,从文件的末尾开始追加- 返回值:
成功:返回文件流指针FILE*
失败:返回NULL
2.fwrite
*size_t fwrite(const void*ptr,size_t size,size_t nmemb,FILE stream);
- 参数:
ptr:想往文件当中写什么内容
size:定义往文件当中写的时候,一个块是多大,单位字节;(通常定义为一个字节)
nmemb :期望写多少块
stream:文件流指针- 返回值:成功写入到文件当中的块的个数(成功写入到文件当中的字节数量)
3.fread
size_t fread(void ptr,size_t size,size_t nmemb,FILEstream);
- 参数:
ptr:将从文件当中读到的内容保存到ptr指向的内存空间当中
size:定义从文件当中读的时候,一个块是多大,单位字节;(通常定义为一个字节)
nmemb :期望读多少块
stream:文件流指针- 返回值: 返回成功读入的文件块的个数
4.fseek
int fseek (FILE*stream, long offset,int whence);
- 作用:移动文件流指针的位.置
- 参数:
stream:文件流指针offset :偏移量
whence :将文件流指针便宜到什么位置
SEEK_SET:文件头部
SEEK_CUR:当前文件流指针的位置SEEK_END:文件末尾
返回值:成功:0失败:-1
5.系统调用的文件接口
1.open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
- pathname: 要打开或创建的目标文件
- flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
- 参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写- 返回值:成功:新打开的文件描述符
2.write
*ssize_t write(int fd,const void buf,size_t count) ;
- 参数:
- fd:文件描述符
- buf:将buf指向的内容写到文件当中去
- count:期望写多少字节
- 返回值:返回写入的字节数量
3.read
*ssize_t read(int fd, void buf,size_t count) ;
- 参数:
- fd:文件描述符
- buf:将从文件当中读到的内容写到buf指向的空间当中
- count:期望读多少字节
- 返回值:
返回读到的字节数量
4.lseek
off_t lseek (int fd, off_t offset,int whence) ;
- 参数:
- fd:文件描述符
- offset:偏移量,单位字节
- whence:偏移的位置
- SEEK_SET:文件头部
- SEEK_CUR:当前文件流指针的位置
- SEEK_END:文件末尾
- 返回值:
成功:返回偏移的位置,单位字节失败:-1
6.文件描述符
- 文件描述符:Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.对应的物理设备一般是:键盘,显示器,显示器
- 分配规则:不是固定进行分配,而是按照最小未使用原则进行分配
代码验证:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
close(0);
//close(2);
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}
- 当我们打开文件时,操作系统要创建相应的数据结构来描述目标文件,于是就有了file结构体
- 表示一个已经打开的文件对象,进程执行open系统调用,所以必须是进程和文件关联起来。
- 每个进程都有一个指针*files,指向一张表files_struct,该表最重要的部分包含一个指针数组,每个元素都是一个指向打开文件的指针。
- 本质上文件描述符就是该数组的下标,所以文件描述符对应相应的文件
内核角度如图:
7.重定向
符号:
- 清空重定向:>
- 追加重定向:>>
接口:
- int dup2(int oldrd.int newfd);
- 作用:将newfd的值重定向为oldfd,newfd拷贝oldfd
- 参数:oldfd/newfd均是文件描述符
- 成功:1.关闭newfd
2. 让newfd指向oldfd对应的struct file*结构体 - 失败:1.如果oldfd是一个非法/无效的文件描述符,则重定向失败;newfd没有变化
2.如果oldfd和newfd的值相等,则什么事情都不干
内核角度:
8.静态库与动态库
1.动态库
- 概念:静态库与动态库都是程序代码的集合(二进制文件),调用者只用关注如何使用,不必内部实现
- 动态库:
windows:没有前缀,后缀为dll
Linux:前缀为lib,后缀为.so- 生成:
使用gcc或g++编译器:-fPIC、 -shard
生成动态库的代码不需要包含main函数(程序入口函数)
具体步骤:
1.编写动态库文件
2.哪些方式可以让程序找到动态库:
1.将动态库放到可执行程序的路径下(不推荐)
2.配置LD_LIBRARY_PATH(推荐的常用手段)
动态库的环境变量:LD_LIBRARY_PATH
3.放到系统库的路径下(极力不推荐)
进入~/.bash_profile或者 ~/.bashrc文件中配置环境变量LD_LIBRARY_PATH
3.使用动态库文件,引入动态库对应的头文件
2.静态库
- 静态库:
windows:没有前缀,后缀为.lib
Linux:前缀为lib,后缀为.a- 生成:
第一阶段:使用gcc或g++将源代码编译成为目标程序(.o)
第二阶段,使用ar -rc命令编译目标程序为静态库
ar -rc [ 静态库文件名称] [目标程序]
9.软硬连接的理解
软链接:目标文件的快捷方式(通过名字引用)
生成:ln -s 源文件 软连接文件
1.修改软连接文件,源文件也会被修改
2源文件如果被删除,软连接文件还在的,修改软连接文件。会重新建立源文件,重新建立链接关系,所以在删除源文件的时候,将软链接文件也删掉,防止后患
硬链接:目标文件的替身(通过inode引用)
生成:ln 源文件 硬链接文件