linux 5day

Linux 5day

 

1.目录操作

目录操作分别为:

获取当前进程目录 修改当前进程目录 打开目录 关闭目录 创建目录 读取目录 创建目录

2.getcwd chdir获取(修改)当前进程的工作目录
 
 #include <unistd.h>
 char *getcwd(char *buf, size_t size);
 功能:获取当前进程的工作目录
 参数:
    buf : 缓冲区,存储当前的工作目录
    size : 缓冲区大小
 返回值:
    成功:buf中保存当前进程工作目录位置
    失败:NULL1.

chdir函数

 #include <unistd.h>
 
 int chdir(const char *path);
 功能:修改当前进程(应用程序)的路径
 参数:
     path:切换的路径
 返回值:
     成功:0
     失败:-1
 int main()
 {
 char u[32];
 memset(u,0,32);
 getcwd(u,80);//获取目录
 printf("buf :%s\n",u);
 //gb
 int ret=-1;
 ret=chdir("/home/deng");//改变目录
 if(ret==-1)
 {
         perror("gect");
         return 1;
 }
 getcwd(u,80);
 printf("buf :%s\n",u);
 return 0;
 }
 
3.目录的打开和关闭

打开

 #include <sys/types.h>
 #include <dirent.h>
 DIR *opendir(const char *name);
 功能:打开一个目录
 参数:
     name:目录名
 返回值:
     成功:返回指向该目录结构体指针
     失败:NULL
 #include <sys/types.h>
 #include <dirent.h>
 int closedir(DIR *dirp);
 功能:关闭目录
 参数:
     dirp:opendir返回的指针
 返回值:
     成功:0
     失败:-1
 int main()
 {
 DIR* dir=NULL;
 dir=opendir("test");//打开目录
 if(dir==NULL)
 {
 perror("jg");
 return 1;
 }
 printf("dkmlcg\n");
 //gbml
 
 closedir(dir);//关闭目录
 return 0;
 }
4.目录的读取
 #include <dirent.h>
 
 struct dirent *readdir(DIR *dirp);
 功能:读取目录
 参数:
     dirp:opendir的返回值
 返回值:
     成功:目录结构体指针
     失败:NULL
 

相关结构体说明:

 
 struct dirent
 {
     ino_t d_ino;                  // 此目录进入点的inode
     off_t d_off;                    // 目录文件开头至此目录进入点的位移
     signed short int d_reclen;      // d_name 的长度, 不包含NULL 字符
     unsigned char d_type;           // d_type 所指的文件类型
     char d_name[256];               // 文件名
 };

d_type文件类型说明:

取值含义
DT_BLK 块设备
DT_CHR 字符设备
DT_DIR 目录
DT_LNK 软链接
DT_FIFO 管道
DT_REG 普通文件
DT_SOCK 套接字
DT_UNKNOWN 未知
5.目录文件读取
 #include<stdio.h>
 #include<unistd.h>
 #include<string.h>
 #include<stdlib.h>
 #include<dirent.h>
 #include<sys/types.h>
 #include<dirent.h>
 int main()
 {
 DIR* dir=NULL;
 dir=opendir("test");
 struct dirent *z=NULL;
 if(dir==NULL)
 {
 perror("jg");
 return 1;
 }
 printf("dkmlcg\n");
 //gbml
 while(1)//循环读取内容
 {
 z=readdir(dir);
 if(NULL==z)
 {
 perror("bc");
 break;
 }
 printf("d_type %hu d_name: %s \n",z->d_type,z->d_name);
 }
 closedir(dir);
 return 0;
 }

6.进程控制

1.wait 与waitpid 子进程结束问题

父进程->子进程完成某项工作 完成后需要释放资源 需要用到wait waitpid

区别wait会阻塞 waitpid不阻塞

1.wait
 #include <sys/types.h>
 #include <sys/wait.h>
 pid_t wait(int *status);
 功能:
     等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收该子进程的资源。
 参数:
     status : 进程退出时的状态信息。
 返回值:
     成功:已经结束子进程的进程号
     失败: -1

调用 wait() 函数的进程会挂起(阻塞),直到它的一个子进程退出或收到一个不能被忽视的信号时才被唤醒(相当于继续往下执行)。

若调用进程没有子进程,该函数立即返回;若它的子进程已经结束,该函数同样会立即返回,并且会回收那个早已结束进程的资源。

如果参数不为空 会把子进程的退出状态信息传递进去

 int main()
 {
 pid_t pid;
 int status;
 pid=fork();
 if(0==pid)
 {
 for(int i=0;i<5;i++)
 {
 printf("1\n");
 sleep(1);
 }
 exit(10);
 }
 
 //堵塞在这里
 wait(&status);
 printf("1hszy\n");
 return 0;
 }

QQ图片20230623231226

状态获取的使用

 wait(&status);
 if(WIFEXITED(status))
 {
 printf("5\n");
 }
知识点

1.发送信号杀死进程 kill -9 进程号 信号是9

a

2.暂停和挂起 kill-19 kill-18 暂停和挂起

2.waitpid
 #include <sys/types.h>
 #include <sys/wait.h>
 id_t waitpid(pid_t pid, int *status, int options);
 
 功能:
     等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。
 参数:
     pid : 参数 pid 的值有以下几种类型:
      pid > 0  等待进程 ID 等于 pid 的子进程。
       pid = 0  等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid 不会等待它。
       pid = -1 等待任一子进程,此时 waitpid wait 作用一样。
       pid < -1 等待指定进程组中的任何子进程,这个进程组的 ID 等于 pid 的绝对值。
     status : 进程退出时的状态信息。和 wait() 用法一样。
     options : options 提供了一些额外的选项来控制 waitpid()
             0:同 wait(),阻塞父进程,等待子进程退出。
             WNOHANG:没有任何已经结束的子进程,则立即返回。
             WUNTRACED:如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态。(由于涉及到一些跟踪调试方面的知识,加之极少用到)                
 返回值:
     waitpid() 的返回值比 wait() 稍微复杂一些,一共有 3 种情况:
 
         1) 当正常返回的时候,waitpid() 返回收集到的已经回收子进程的进程号;
 
         2) 如果设置了选项 WNOHANG,而调用中 waitpid() 发现没有已退出的子进程可等待,则返回 0
 
         3) 如果调用中出错,则返回-1,这时 errno 会被设置成相应的值以指示错误所在,如:当 pid 所对应的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid() 就会出错返回,这时 errno 被设置为 ECHILD;
 waitpid(-1,&status,WNOHANG);

 

2.孤儿进程

父进程结束运行 但是子进程还在运行

内核就把孤儿进程的父进程设置为 init ,而 init 进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表党和政府出面处理它的一切善后工作。

3.僵尸进程

父进程卡着 子进程exit退出 但是没有用wait回收

如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。

4.进程替换

如果我们本来就运行着一个程序(进程),我们如何在这个进程内部启动一个外部程序,由内核将这个外部程序读入内存,使其执行起来成为一个进程呢?这里我们通过 exec 函数族实现。

 
 #include <unistd.h>
 extern char **environ;
 
 int execl(const char *path, const char *arg, .../* (char *) NULL */);
 int execlp(const char *file, const char *arg, ... /* (char *) NULL */);
 int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */);
 int execv(const char *path, char *const argv[]);
 int execvp(const char *file, char *const argv[]);
 int execvpe(const char *file, char *const argv[], char *const envp[]);
 
 int execve(const char *filename, char *const argv[], char *const envp[]);

只有execve()是真正的系统调用->其他都是在基础上进行封装的

exec 函数族的作用是根据指定的文件名或目录名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。

1527922959390

exec 函数族使用说明

exec 函数族的 6 个函数看起来似乎很复杂,但实际上无论是作用还是用法都非常相似,只有很微小的差别。

1527923035885 补充说明:

l(list)参数地址列表,以空指针结尾
v(vector) 存有各参数地址的指针数组的地址
p(path) 按 PATH 环境变量指定的目录搜索可执行文件
e(environment) 存有环境变量字符串地址的指针数组的地址

exec 函数族与一般的函数不同,exec 函数族中的函数执行成功后不会返回,而且,exec 函数族下面的代码执行不到。只有调用失败了,它们才会返回 -1,失败后从原程序的调用点接着往下执行。

img

测试案例

execlp

 execlp("ls","ls","-l","/home",NULL);

execl

 execl("/bin/ls","ls","-l","/home",NULL);//可执行文件路径 可执行名字 参数 占位参数

无需掌握

 int execv(const char *path, char *const argv[]);
 char* argv[]={"ls","-l","/home",NULL};
 execvp("/bin/ls",argv);
 //---------------------------------------------
 int execvp(const char *file, char *const argv[]);
 char* argv[]={"ls","-l","/home",NULL};
 execvp("ls",argv);

环境遍历包含

 int execvpe(const char *file, char *const argv[], char *const envp[]);
 
 #define _GNU_SOURCE
 char* argv[]={"ls","-l","/home",NULL};
 char* en[]={"ADDR=BEIJING",NULL};
 execvpe("ls",argv,en);
 
 int execve(const char *filename, char *const argv[], char *const envp[]);
 
 char* argv[]={"ls","-l","/home",NULL};
 char* en[]={"ADDR=BEIJING",NULL};
 execve("/bin/ls",argv,en);
 
 int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */);
 
 char* argv[]={"ls","-l","/home",NULL};
 char* en[]={"ADDR=BEIJING",NULL};
 execle("/bin/ls","ls","-l","/home",NULL,argv);


posted @ 2023-06-18 16:52  大橘|博客  阅读(23)  评论(1)    收藏  举报