20135327郭皓——信息安全系统设计基础第十二周学习总结
2015-11-28 17:35
363 查看
第十二周(11.23-11.29):
PS:并不知道为什么只找到一些资料,我觉得应该是内存访问出错或者非法内存访问
对于exec函数:
在Linux中要使用exec函数族。系统调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。exec函数族当然不止一个,但它们大致相同,在 Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp。一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。若是想启动另一程序的执行但自己仍想继续运行的话,那就得结合fork与exec的使用。
对于fork函数:
fork函数启动一个新的进程,前面我们说过,这个进程几乎是当前进程的一个拷贝:子进程和父进程使用相同的代码段;子进程复制父进程的堆栈段和数据段。这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。
系统如何来区分它们呢?这是由函数的返回值来决定的。对于父进程, fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零。在操作系统中,我们用ps函数就可以看到不同的进程号,对父进程而言,它的进程号是由比它更低层的系统调用赋予的,而对于子进程而言,它的进程号即是fork函数对父进程的返回值。在程序设计中,父进程和子进程都要调用函数fork()下面的代码,而我们就是利用fork()函数对父子进程的不同返回值用if...else...语句来实现让父子进程完成不同的功能。
以上内容多是出自网络,但对我的帮助很大。
学习计时:共6小时 读书: 代码: 作业: 博客: |
一、学习目标 |
掌握进程控制 掌握信号处理的方法 掌握管道和fifo进行进程间通信的方法 |
二、学习资源 |
编译、运行、阅读、理解process.tar.gz压缩包中的代码 |
实验代码
代码说明均在代码里面
exec1
#include <stdio.h> #include <unistd.h> int main() { /* 执行ls -l命令 */ char *arglist[3]; arglist[0] = "ls"; arglist[1] = "-l"; arglist[2] = 0 ;//NULL printf("* * * About to exec ls -l\n"); execvp( "ls" , arglist );//进程控制函数,根据文件名找到对饮的可执行函数,并用它来取代调用进程的内容 printf("* * * ls is done. bye"); return 0; }
exec2
#include <stdio.h> #include <unistd.h> /* 和exec1一样,只是execvp第一个参数被替换成数组的首元素 */ int main() { char *arglist[3]; arglist[0] = "ls"; arglist[1] = "-l"; arglist[2] = 0 ; printf("* * * About to exec ls -l\n"); execvp( arglist[0] , arglist ); printf("* * * ls is done. bye\n"); }
exec3
#include <stdio.h> #include <unistd.h> int main() { /* 和exce1一样 */ char *arglist[3]; char *myenv[3]; myenv[0] = "PATH=:/bin:"; myenv[1] = NULL; arglist[0] = "ls"; arglist[1] = "-l"; arglist[2] = 0 ; printf("* * * About to exec ls -l\n"); // execv( "/bin/ls" , arglist ); // execvp( "ls" , arglist ); // execvpe("ls" , arglist, myenv); /* 从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件. 然后将第二个以后的参数当做该文件的argv[0]、argv[1],最后一个参数必须用空指针(NULL)作结束。 */ execlp("ls", "ls", "-l", NULL); printf("* * * ls is done. bye\n"); }
forkdemo1
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { /* fork()会产生一个和父进程一样的子进程 父进程的fork()返回子进程的ID 子进程的fork()返回0 */ int ret_from_fork, mypid; mypid = getpid(); printf("Before: my pid is %d\n", mypid); ret_from_fork = fork(); sleep(1); printf("After: my pid is %d, fork() said %d\n", getpid(), ret_from_fork); return 0; }
forkdemo2
#include <stdio.h> #include <unistd.h> int main() { /* 这里创建了两个fork(),故有一个父进程 三个子进程 子进程只能打印第二个printf */ printf("before:my pid is %d\n", getpid() ); fork(); fork(); printf("aftre:my pid is %d\n", getpid() ); return 0; }
forkdemo3
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { /* 打印父进程和子进程的ID */ int fork_rv; printf("Before: my pid is %d\n", getpid()); fork_rv = fork(); /* create new process */ if ( fork_rv == -1 ) /* check for error */ perror("fork"); else if ( fork_rv == 0 ){ printf("I am the child. my pid=%d\n", getpid()); exit(0); } else{ printf("I am the parent. my child is %d\n", fork_rv); exit(0); } return 0; }
forkdemo4
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { /* 通过getppid查看父进程ID */ int fork_rv; printf("Before: my pid is %d\n", getpid()); fork_rv = fork(); /* create new process */ if ( fork_rv == -1 ) /* check for error */ perror("fork"); else if ( fork_rv == 0 ){ printf("I am the child. my pid=%d\n", getpid()); printf("parent pid= %d, my pid=%d\n", getppid(), getpid()); exit(0); } else{ printf("I am the parent. my child is %d\n", fork_rv); sleep(10); exit(0); } return 0; }
forkgdb
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int gi=0; /* 由于sleep的存在,父进程在si会停1秒。而子进程会开始,在li之后又会停止,父进程继续运行,如此循环 */ int main() { int li=0; static int si=0; int i=0; pid_t pid = fork(); if(pid == -1){ exit(-1); } else if(pid == 0){ for(i=0; i<5; i++){ printf("child li:%d\n", li++); sleep(1); printf("child gi:%d\n", gi++); printf("child si:%d\n", si++); } exit(0); } else{ for(i=0; i<5; i++){ printf("parent li:%d\n", li++); printf("parent gi:%d\n", gi++); sleep(1); printf("parent si:%d\n", si++); } exit(0); } return 0; }
psh1
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define MAXARGS 20 #define ARGLEN 100 /* 调用execvp函数,通过调用数组第一位为文件,数组作为可执行函数 */ int execute( char *arglist[] ) { execvp(arglist[0], arglist); perror("execvp failed"); exit(1); } char * makestring( char *buf ) { char *cp; buf[strlen(buf)-1] = '\0'; cp = malloc( strlen(buf)+1 ); if ( cp == NULL ){ fprintf(stderr,"no memory\n"); exit(1); } strcpy(cp, buf); return cp; } int main() { char *arglist[MAXARGS+1]; int numargs; char argbuf[ARGLEN]; numargs = 0; while ( numargs < MAXARGS ) { printf("Arg[%d]? ", numargs); if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' ) arglist[numargs++] = makestring(argbuf); else { if ( numargs > 0 ){ arglist[numargs]=NULL; execute( arglist ); numargs = 0; } } } return 0; }
psh2
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <signal.h> #define MAXARGS 20 #define ARGLEN 100 /* 和psh1一样,但加入了fork()所以会不断地从头开始运行 */ char *makestring( char *buf ) { char *cp; buf[strlen(buf)-1] = '\0'; cp = malloc( strlen(buf)+1 ); if ( cp == NULL ){ fprintf(stderr,"no memory\n"); exit(1); } strcpy(cp, buf); return cp; } void execute( char *arglist[] ) { int pid,exitstatus; pid = fork(); switch( pid ){ case -1: perror("fork failed"); exit(1); case 0: execvp(arglist[0], arglist); perror("execvp failed"); exit(1); default: while( wait(&exitstatus) != pid ) ; printf("child exited with status %d,%d\n", exitstatus>>8, exitstatus&0377); } } int main() { char *arglist[MAXARGS+1]; int numargs; char argbuf[ARGLEN]; numargs = 0; while ( numargs < MAXARGS ) { printf("Arg[%d]? ", numargs); if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' ) arglist[numargs++] = makestring(argbuf); else { if ( numargs > 0 ){ arglist[numargs]=NULL; execute( arglist ); numargs = 0; } } } return 0; }
testbuf1
#include <stdio.h> #include <stdlib.h> int main() { printf("hello"); fflush(stdout);//强制输出命令 while(1); }
testbuf2
#include <stdio.h> int main() /*打印hello*/ { printf("hello\n"); while(1); }
testbuf3
#include <stdio.h> int main() { fprintf(stdout, "1234", 5);//标准输出,将在缓冲流参数其打印到屏幕上 fprintf(stderr, "abcd", 4);//标准错误,将后面的参数和错误直接打印到屏幕上 }
testpid
#include <stdio.h> #include <unistd.h> #include <sys/types.h> /* 打印父进程ID,如果没有父进程则打印当前程序进程ID */ int main() { printf("my pid: %d \n", getpid()); printf("my parent's pid: %d \n", getppid()); return 0; }
testpp
#include <stdio.h> #include <stdlib.h> int main() { char **pp; pp[0] = malloc(20);//malloc 向系统申请分配指定size个字节的内存空间。 return 0; }
PS:并不知道为什么只找到一些资料,我觉得应该是内存访问出错或者非法内存访问
testsystem
#include <stdlib.h> /* 发出两个命令,命令存在数组中 */ int main ( int argc, char *argv[] ) { system(argv[1]); system(argv[2]); return EXIT_SUCCESS; } /* ---------- end of function main ---------- */
waitdemo1
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #define DELAY 4 /* 父进程执行parent_code时,因为wait函数会等待子进程运行完毕后再运行 */ void child_code(int delay) { printf("child %d here. will sleep for %d seconds\n", getpid(), delay); sleep(delay); printf("child done. about to exit\n"); exit(17); } void parent_code(int childpid) { int wait_rv=0; /* return value from wait() */ wait_rv = wait(NULL); printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv); } int main() { int newpid; printf("before: mypid is %d\n", getpid()); if ( (newpid = fork()) == -1 ) perror("fork"); else if ( newpid == 0 ) child_code(DELAY); else parent_code(newpid); return 0; }
waitdemo2
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #define DELAY 10 /* 和waitdemo1一样 但多了子进程的三个状态 */ void child_code(int delay) { printf("child %d here. will sleep for %d seconds\n", getpid(), delay); sleep(delay); printf("child done. about to exit\n"); exit(27); } void parent_code(int childpid) { int wait_rv; int child_status; int high_8, low_7, bit_7; wait_rv = wait(&child_status); printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv); high_8 = child_status >> 8; /* 1111 1111 0000 0000 */ low_7 = child_status & 0x7F; /* 0000 0000 0111 1111 */ bit_7 = child_status & 0x80; /* 0000 0000 1000 0000 */ printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7); } int main() { int newpid; printf("before: mypid is %d\n", getpid()); if ( (newpid = fork()) == -1 ) perror("fork"); else if ( newpid == 0 ) child_code(DELAY); else parent_code(newpid); }
参考资料:百度 深入理解计算机系统.pdf
总结
这18个代码让我深入理解了exec函数和fork函数,同时还有一些其他函数。单总的来说,还是在这两上有很大的学习。对于exec函数:
在Linux中要使用exec函数族。系统调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。exec函数族当然不止一个,但它们大致相同,在 Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp。一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。若是想启动另一程序的执行但自己仍想继续运行的话,那就得结合fork与exec的使用。
对于fork函数:
fork函数启动一个新的进程,前面我们说过,这个进程几乎是当前进程的一个拷贝:子进程和父进程使用相同的代码段;子进程复制父进程的堆栈段和数据段。这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。
系统如何来区分它们呢?这是由函数的返回值来决定的。对于父进程, fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零。在操作系统中,我们用ps函数就可以看到不同的进程号,对父进程而言,它的进程号是由比它更低层的系统调用赋予的,而对于子进程而言,它的进程号即是fork函数对父进程的返回值。在程序设计中,父进程和子进程都要调用函数fork()下面的代码,而我们就是利用fork()函数对父子进程的不同返回值用if...else...语句来实现让父子进程完成不同的功能。
以上内容多是出自网络,但对我的帮助很大。
相关文章推荐
- MBProgressHUD+FastCall
- 华东交通大学2015年ACM“双基”程序设计竞赛
- 十七道海量数据处理面试题与Bit-map详解
- 【Leetcode】Letter Combinations of a Phone Number
- delphi 获取颜色值的RGB
- BNU 1111(dfs+剪枝)
- ViewPager 指示器
- NVIDIA Cuda 7.5 on Ubuntu 14.04 64 bits
- ora-01950 no privileges on tablespasce TESTDATA 错误解决办法
- java 集合 有一个字符串,其中包含中文字符、英文字符和数字字符,请统计和打印出各个字符的个数
- 南大软院大神养成计划第十三天
- 新博客?
- A little runtime excursion
- 新版本的驰骋工作流引擎ccbpm将有那些变化?
- 《中国人的性格》摘要
- [项目基础]WCF初识小结
- NSOperation
- Spring 的扩展机制测试
- 算法兴趣----两个巨大正整数相加
- setAlpha方法 设置透明度