這個系列的博客貼的都是我大二的時候學習Linux系統高級編程時的一些實驗程序,都挺簡單的。
實驗題目:Linux環境下的進程控制
實驗目的:熟悉並掌握Linux環境下進程的相關函數的應用;守護進程的概念、啟動和操作;進程操作程序的編寫。
一、Linux進程控制
設計程序,滿足如下要求:
1、設計一個程序,要求顯示Linux系統分配給此程序的進程號(PID)和它的父進程號(PPID)。
在Linux環境下進程創建時,系統會分配一個唯一的數值給每個進程,這個數值就稱為進程標示符(pid),他的父進程號用ppid表示。
在Linux中獲取當前進程的pid、ppid可以調用getpid()和getppid()函數。
getpid函數說明如下:
所需頭文件 | #include<unsitd.h> |
函數功能 | 取得當前進程的進程號 |
函數原型 | pid_t getpid(void) |
函數傳入值 | 無 |
返回值 | 成功返回當前進程的標識符 |
|
#include<unistd.h> | |
函數功能 | 取得當前進程的父進程號 | |
函數原型 | pid_t getppid(void) | |
函數傳入值 | 無 | |
返回值 | 成功返回當前進程的父進程標識符 |
1 #include<stdio.h> 2 #include<unistd.h> 3 int main() 4 { 5 printf("系統分配的進程號(PID)是:%d\n",getpid()); 6 printf("系統分配的父進程號(PPID)是:%d\n",getppid()); 7 return 0; 8 }
2、設計一個程序,用fork函數創建一個子進程,在子進程中給變量n賦值3,在父進程中給變量n賦值6,fork調用之后父進程和子進程的變量message和n被賦予不同的值,互不影響。
Linux下調用fork()函數可以創建一個新進程,由fork創建的新的進程被稱為子進程。fork()函數調用一次返回兩次,區別是子進程的返回值是0,父進程的返回值是子進程的pid。子進程是父進程的復制品,復制父進程的數據空間,堆棧等。
所需頭文件 | #include <unistd.h> |
功能 | 建立一個新的進程 |
函數原型 | pid_t fork(void) |
傳入值 | 無 |
返回值 | 執行成功在子進程中返回0,在父進程中返回子進程的pid,失敗返回-1
|
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<stdlib.h> 4 #include<unistd.h> 5 int main() 6 { 7 pid_t pid; 8 char *message; 9 int n; 10 pid = fork(); 11 if(pid < 0) 12 { 13 perror("fork failed!\n"); 14 exit(1); 15 } 16 if(pid == 0) 17 { 18 message="This is the child!\n"; 19 n=3; 20 } 21 else 22 { 23 message="This is the parent!\n"; 24 n=6; 25 } 26 for(;n>0;n--) 27 { 28 printf(message); 29 sleep(1); 30 } 31 32 return 0; 33 }
3、分別使用exec函數族中的六個函數執行命令“ifconfig eth0 192.168.110.140”。
#include<stdio.h> #include<stdlib.h> //可以分別注釋掉不同的exec族函數,分別執行以查看效果。 #include<unistd.h> #include<sys/types.h> int main() { char *const argv[]={"ifconfig","eth0","192.168.110.140",NULL}; char *env[]={"PATH=bin:usr/sbin",NULL}; // execl("/sbin/ifconfig","ifconfig","eth0","192.168.110.140",NULL); // execv("/sbin/ifconfig",argv); // execle("/sbin/ifconfig","ifconfig","eth0","192.168.110.140",NULL,env); // execve("/sbin/ifconfig",argv,env); // execlp("ifconfig","ifconfig","eth0","192.168.110.140",NULL); execvp("ifconfig",argv); return 0; }
在系統中創建一個進程的目的是需要該進程完成一定的任務,需要該進程執行他的程序代碼,在Linux系統中可以調用exec函數是程序執行。
系統調用exec有多種使用形式,稱為exec族,他們只是在參數上不同,而功能是相同的。
在exec族里面有6個函數可以用來建立子進程,分別是execl, execcv, execle , execve, execlp, execvp,函數中第5、6個字符l, v, e, p表示函數中國的參數分別用列表傳遞方式,字符傳遞方式,可制定環境變量及路徑自動搜索功能。
所需頭文件 | #include <unistd.h> |
函數原型 | int execl(const char *path,const char *arg, ...) int execv(consr char *path,char const *argv[]) int execle(consr char *path, const char *arg, ... ,char const * envp[]) int execve(consr char *path, char const *argv[],char const * envp[]) int execlp(const char *file,const char *arg, ...) int execvp(const char *file,char *const argv[] ) |
返回值 | -1出錯 |
而事實上,這六個函數中真正的系統調用函數只有execve(),其他的五個都是庫函數,他們最終調用的都是execve這個系統函數。
exec調用舉例如下:
1 char *const ps_argv[] = {"ps","-o", "pid,ppid",NULL}; 2 char *const ps_envp[] = {"PATH = bin:/usr/bin","TERM = console",NULL}; 3 4 execl("bin/ps","ps","-o","pid,ppid",NULL); 5 execv("bin/ps",ps_argv); 6 execle("bin/ps","ps","-o","pid,ppid",NULL,ps_envp); 7 execve("bin/ps",ps_argv,ps_envp); 8 execlp("ps","ps","-o","pid,ppid",NULL); 9 execvp("ps",ps_argv);
二、僵屍進程
1、設計一個程序,要求創建一個子進程,子進程顯示自己的進程號(PID)后暫停一段時間,父進程等待子進程正常結束,打印顯示等待的進程號(PID)和等待的進程退出狀態。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 #include<sys/types.h> 5 #include<sys/wait.h> 6 int main() 7 { 8 pid_t pid,wpid; 9 int status,i; 10 pid =fork(); 11 if(pid ==0) 12 { 13 printf("This is the child,進程號(PID)是:%d\n",getpid()); 14 sleep(5); 15 exit(6); 16 } 17 else 18 { 19 printf("This is the parent,正在等待子進程.....\n"); 20 wpid=wait(&status); 21 i=WEXITSTATUS(status); 22 printf("等待進程的進程號(PID)是:%d,結束狀態:%d\n",wpid,i); 23 } 24 return 0; 25 }
2、要求子進程用sleep等待10秒,父進程用waitpid函數等待子進程正常結束,父進程在等待的時候不阻塞,每1秒在屏幕上輸出一行文字,若發現子進程退出,打印等待進程的進程號(PID)和退出狀態。請編寫一程序進行調試。
#include<stdio.h> #include<sys/types.h> #include<sys/wait.h> #include<stdlib.h> #include<unistd.h> int main() { pid_t pid,wpid; int status; pid=fork(); if(pid==0) { printf("This is the child,進程號(PID)是:%d\n",getpid()); printf("This is the child,Then slepp now!\n"); sleep(10); exit(6); } else { printf("This is the parent!\n"); while(1){ waitpid(pid, &status, WNOHANG); printf("Wait for child.........\n"); if(0 == WIFEXITED(status)) sleep(1); else{ printf("Child is end now!\n"); printf("等待的進程的進程號(PID)是:%d,結束狀態:%d\n",pid,WEXITSTATUS(status)); break; } } } }
三、守護進程
1、
編寫一程序,要求運行后成為守護進程,每隔3秒修改一個本機的IP地址,並在屏幕上顯示IP地址信息。
#include<stdio.h> #include<stdlib.h> #include<time.h> #include<unistd.h> #include<sys/param.h> #include<sys/stat.h> #include<sys/types.h> #include<signal.h> void init_daemon(void) { pid_t child1,child2; int i; child1=fork(); if(child1 >0) exit(0); else if(child1 < 0) { perror("創建子進程失敗!\n"); exit(1); } setsid(); chdir("/mnt/hgfs/zhaoshun"); umask(0); for(i=0;i<NOFILE;++i) close(i); return; } int main() { FILE * fp; char buf1[100],buf2[100]; init_daemon(); if((fp=fopen("ipadd","r"))=NULL) { printf("打開文件出錯!\n"); } while(1) { ifconfig(); system("ifconfig"); sleep(3); } return 0; }