这个系列的博客贴的都是我大二的时候学习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;
}