系统与网络编程
exec的使用
找一个函数:find /usr gedit
- execl 使用
- 调用系统ls
- int execl(const char *path, const char *arg, ...);
#include <unistd.h> #include <stdio.h> int main() { int ret=-1; //int execl(const char *path, const char *arg, ...); //第一个参数:可执行文件的路径 //之后的参数: ret=execl("/bin/ls","ls","/usr/include","-l",NULL); return 0; } 可查看目标路径下的文件,功能同ls
- 调用目标./test
ret=execl("./test","test",NULL);
- 调用系统gedit打开文件
ret=execl("/usr/bin/gedit","gedit","exec.c",NULL);
- execlp使用
- int execlp(const char *file, const char *arg, ...);
- 可以不指定需要执行文件的路径,启动该执行文件时到系统默认路径下去找该执行文件。若找到了则执行,否则出错返回。
- 直接调用系统gedit打开文件
#include <unistd.h> #include <stdio.h> int main() { int ret=-1; ret=execlp("gedit","gedit","exec.c",NULL); }
- 调用没有的文件
ret=execlp("myText","myTest",NULL); printf("ret=%d\n",ret); if(ret==-1) { perror("execlp"); return -1; } //no such file or directory
- execv使用
//int execv(const char *path, char *const argv[]); #include <unistd.h> #include <stdio.h> int main() { int ret=-1; char *const argv[]={"ls","/usr/include","-l",NULL}; ret=execv("/bin/ls",argv); return 0; }
- execvp
// int execvp(const char *file, char *const argv[]); #include <unistd.h> #include <stdio.h> int main() { int ret=-1; char *const argv[]={"gedit","exec.c",NULL}; ret=execvp("gedit",argv); return 0; }
- 实现如终端下后台运行操作
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
pid_t pid=-1;
pid=fork();
if(pid>0)//parent
{
while(1)
{
printf("this is parent\n");
sleep(1);
}
}
else if (pid==0)
{
execv(argv[1],argv+1);//第三个开始都是它的参数
//./a.out /bin/ls /usr/include -l
int ret=-1;
if(ret==-1)
{
perror("execv");
return -1;
}
}
return 0;
}
Paste_Image.png
Paste_Image.png
- 终端模拟
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
char *getInput(char *argv[])//从终端接受字符
{
int i=0;
int ret=-1;
char *pData=NULL;
pData=(char *)malloc(64);
while(EOF!=scanf("%s",pData))//
{
argv[i]=pData;
pData=(char *)malloc(64);
i++;
}
free(pData);
argv[i]=NULL;
return NULL;
}
void showArgv(char *argv[])
{
int i=0;
while (argv[i]!=NULL)
{
printf("%s\n",argv[i]);
i++;
}
}
int main(void)
{
char *argv[32]={NULL};
while(1)
{
printf("myTermal@suhui$:");
getInput(argv);
pid_t pid=-1;
pid=fork();
if(pid>0)
{
wait(NULL);
}
else if(pid==0)
{
pid_t pid2=fork();
if(pid2==0)
{
int ret=-1;
ret=execvp(argv[0],argv);
if(ret==-1)
{
perror("execvp");
return -1;
}
}
return 0;
}
}
#if 0
if(pid>0)//parent
{
while(1)
{
printf("MyTermal:");
getInPut(argv);//循环输入
pid_t pid2=-1;
pid2=fork();//循环创建子进程
if(pid2==0)
{
int ret=-1;
ret=execv(argv[0],argv);
}
}
}
else if (pid==0)
{
execv(argv[1],argv+1);//第三个开始都是它的参数
//./a.out /bin/ls /usr/include -l
int ret=-1;
if(ret==-1)
{
perror("execv");
return -1;
}
}
return 0;
#endif
}
- 进程的自杀
- return 0 后继续执行用atexit
- 进程正常结束时首先在用户态做一些善后工作,然后进入内核层做一些善后工作
#include <stdio.h> #include <stdlib.h> void fun1() { printf("fun1....\n"); } void fun2() { printf("fun2....\n"); } void fun3() { printf("fun3....\n"); } int main() { atexit(fun1); atexit(fun2); atexit(fun3); printf("hello world\n"); return 0;//实现return 0后要执行的代码,atexit. }
-
atexit注册函数会在进程正常结束后被执行,执行的顺序与注册顺序相反
Paste_Image.png - exit(-1):程序自杀
Paste_Image.pngint main() { atexit(fun1); atexit(fun2); atexit(fun3); exit(-1);//自杀 printf("hello world\n"); return 0;//实现return 0后要执行的代码,atexit. }
- abort:程序非正常结束
int main() { atexit(fun1); atexit(fun2); atexit(fun3); abort(); printf("hello world\n"); return 0;//实现return 0后要执行的代码,atexit. }
- _exit():直接进入内核做善后工作
int main() { atexit(fun1); atexit(fun2); atexit(fun3); _exit(); printf("hello world\n"); return 0;//实现return 0后要执行的代码,atexit. }
进程间通信
- ipc:interprocess communication
通信方式
-
管道通信
Paste_Image.png- 无名管道:通过pipe创建出来的管道,只能在父子进程或子进程间使用,创建该管道的进程一旦结束,则该无名管道也会销毁
#include <unistd.h>//pipe #include <stdio.h> #include <string.h> //通过pipe创建的管道属于无名管道 //只能在父子进程或子进程间使用 //创建该管道的进程一旦结束,则该无名管道也会销毁 int main() { int pipefd[2]={-1};//管道文件描述符 int ret=-1; ret=pipe(pipefd);//创建的管道是位于内核空间的,管道两端的描述符存储到pipe数组 //pipefd[0]表示数据流出段,可以从此端读取数据 //pipefd[1]表示数据进入段,可以从此端写入数据 if(ret==-1)//创建管道失败 { perror("pipe"); return -1; } //创建一个进程 pid_t pid=-1; //管道的创建是创建在内核中,不属于独立进程 //fork产生的子进程是不会再创建一个管道 //只是对管道文件进行了一次拷贝 pid=fork(); if(pid>0)//parent { int iSign=0; char caBuf[32]={'\0'}; while(1) { memset(caBuf,'\0',sizeof(caBuf)); if(iSign==0) { printf("parent input data\n"); scanf("%s",caBuf); write(pipefd[1],caBuf,sizeof(caBuf)); iSign=1; sleep(1); } else if(iSign==1) { read(pipefd[0],caBuf,sizeof(caBuf)); printf("child says:%s\n",caBuf); iSign=0; } } } else if(pid==0)//child { int iSign=1; char caBuf[64]={'\0'}; while(1) { memset(caBuf,'\0',sizeof(caBuf)); if(iSign==1) { read(pipefd[0],caBuf,sizeof(caBuf)); printf("parent says:%s\n",caBuf); iSign=0; } else if(iSign==0) { printf("child input data\n"); scanf("%s",caBuf); write(pipefd[1],caBuf,sizeof(caBuf)); iSign=1; sleep(1); } } } else if(pid==-1)//fork failed { perror("fork"); return -1; } return 0; }
- 命名管道:
- 父进程输出关闭子进程的输出,打开输入。子进程输出关闭父进程的输出,打开输入。
homework
- 进程的状态及状态间的转化
- 进程的状态有:就绪态,执行态,阻塞态。
- 就绪→执行
处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态。 - 执行→就绪
处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态。 - 执行→阻塞
正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。 - 阻塞→就绪
处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。
- 就绪→执行
- 进程的状态有:就绪态,执行态,阻塞态。
- 完善目录拷贝
- 独立完成模仿终端的代码
- 通过无名管道,让两个子进程间完成相互通信工作
网友评论