系統與網絡編程
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):程序自殺
int main() { atexit(fun1); atexit(fun2); atexit(fun3); exit(-1);//自殺 printf("hello world\n"); return 0;//實現return 0后要執行的代碼,atexit. }
Paste_Image.png- 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
- 進程的狀態及狀態間的轉化
- 進程的狀態有:就緒態,執行態,阻塞態。
- 就緒→執行
處于就緒狀態的進程,當進程調度程序為之分配了處理機后,該進程便由就緒狀態轉變成執行狀態。 - 執行→就緒
處于執行狀態的進程在其執行過程中,因分配給它的一個時間片已用完而不得不讓出處理機,于是進程從執行狀態轉變成就緒狀態。 - 執行→阻塞
正在執行的進程因等待某種事件發生而無法繼續執行時,便從執行狀態變成阻塞狀態。 - 阻塞→就緒
處于阻塞狀態的進程,若其等待的事件已經發生,于是進程由阻塞狀態轉變為就緒狀態。
- 就緒→執行
- 進程的狀態有:就緒態,執行態,阻塞態。
- 完善目錄拷貝
- 獨立完成模仿終端的代碼
- 通過無名管道,讓兩個子進程間完成相互通信工作