zoukankan      html  css  js  c++  java
  • 信息安全系统设计基础第十二周学习总结

    预计时间(10小时)

    运行代码 6小时
    整理笔记 3小时

    实际时间(12小时)

    运行代码 7小时
    整理笔记 3小时

    代码实践

    代码运行及理解

    1、exec1.c

    功能:装入并运行其它程序的函数

     #include <stdio.h>
        #include <unistd.h>
    
        int main()
        {
            char    *arglist[3];
    
            arglist[0] = "ls";
            arglist[1] = "-l";
            arglist[2] = 0 ;//NULL
            printf("* * * About to exec ls -l
    ");
            execvp( "ls" , arglist );//第一个参数传递的是文件名
            printf("* * * ls is done. bye");
    
            return 0;
        }

    运行结果:

    分析:

    根据代码我们知道,执行的指令是:

    ls -l
    开始显示“ * * * About to exec ls -l” 
    执行完之后应该显示“ * * * ls is done. bye”

    然后从上图中,我们可以看到,并没有显示最后一句,这是因为在系统处理器中,在执行execvp( "ls" , arglist );语句时,已经将最后的打印语句覆盖掉了,处理器中并没有这句打印语句,所以最终结果如图所示。

    2.exce2.c

    功能:装入并运行其它程序的函数

      #include <stdio.h>
        #include <unistd.h>
    
        int main()
        {
            char    *arglist[3];
    
            arglist[0] = "ls";
            arglist[1] = "-l";
            arglist[2] = 0 ;
            printf("* * * About to exec ls -l
    ");
            execvp( arglist[0] , arglist );
            printf("* * * ls is done. bye
    ");
        }

    运行结果

    与exec1.c的结果相同(见上两图)

    分析:

    exec2.c的代码运行结果与exec1.c的结果相同,说明两者实现的功能是一样的,但是唯一的区别就在于

    execvp( arglist[0] , arglist ); 
    //将文件名存放在arglist[0]中

    这个语句上,在exec1.c中,这句代码这这样写的:

    execvp( "ls" , arglist );

    也就是把“ls”替换成了“arglist[0]”,所以并不会影响结果。

    3.exec3.c

    功能:装入并运行其它程序的函数

    #include <stdio.h>
        #include <unistd.h>
    
        int main()
        {
            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
    ");
        //  execv( "/bin/ls" , arglist );
        //  execvp( "ls" , arglist );
        //  execvpe("ls" , arglist, myenv);
    
            execlp("ls", "ls", "-l", NULL);
            printf("* * * ls is done. bye
    ");
        }

    运行结果

    我分别把代码中注释的行依次放开,单独运行,结果还是和exec1.c中的结果一样,还是不能执行出最后一条打印语句。

    查看帮助文档

    分析:

    运行结果还是和exec1.c的一样 
    从代码中我们可以看出:

        execv( "/bin/ls" , arglist );
        //第一个参数传递的是路径
        execvp( "ls" , arglist );
        //第一个参数传递的是文件名
        execvpe("ls" , arglist, myenv);
        //比execvp函数,增加了第三个参数:环境变量
        execlp("ls", "ls", "-l", NULL);
        //第一个参数表示文件名,
    

    上面的语句和exec1.c中的语句相同

        execvp( "ls" , arglist );
    

    注意:exce族的区别

    (1):这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。

    (2)规律: 
    ①、不带字母p(表示 path)的exec函数第一个参数必须是程序的相对路径或绝对路径,例如“/bin/ls”或“./a.out”,而不能是“ls”或“a.out”。 
    ②、对于带字母p的函数: 如果参数中包含/,则将其视为路径名。否则视为不带路径的程序名,在PATH环境变量的目录列表中搜索这个程序。 
    ③、带有字母l(表示list)的exec函数要求将新程序的每个命令行参数都当作一个参数传给它,命令行参数的个数是可变的,因此函数原型中有…,…中的最后一个可变参数应该是 NULL,起sentinel的作用。 
    ④、对于带有字母v(表示vector)的函数,则应该先构造一个指向各参数的指针数组,然后将该数组的首地址当作参数传给它,数组中的最后一个指针也应该是NULL,就像main函数的argv参数或者环境变量表一样。

    (3):对于以e(表示environment)结尾的exec函数,可以把一份新的环境变量表传给它,其他exec函数仍使用当前的环境变量表执行新程序。

    (4): 事实上,只有execve是真正的系统调用,其它五个函数最终都调用execve,所以execve在man手册第2节,其它函数在man手册第3节。这些函数之间的关系如下图所示。

    4、forkdemo1.c

    fork函数: :将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1。

    #include    <stdio.h>
        #include    <sys/types.h>
        #include    <unistd.h>
        int main()
        {
            int ret_from_fork, mypid;
            mypid = getpid();              
            printf("Before: my pid is %d
    ", mypid);
            ret_from_fork = fork();
            sleep(1);
            printf("After: my pid is %d, fork() said %d
    ",
                    getpid(), ret_from_fork);
    
            return 0;
        }

    运行结果

    分析:

    从图中可以看出,After打印语句打印了两次,第一次打印的After语句是父进程执行的,因为fork函数的返回值不是0,说明是父进程在执行,第二次打印的After语句是子进程执行的,因为fork函数的返回值是0,而我的id是子进程id。

    5、forkdemo2.c

      #include <stdio.h>
        #include <unistd.h>
    
        int main()
        {
            printf("before:my pid is %d
    ", getpid() );
            fork();
            fork();
            printf("aftre:my pid is %d
    ", getpid() );
    
            return 0;
        }

    运行结果

    分析:

    因为执行了两次fork函数,执行第一次,分出2个线程,执行第二次,之前的两个线程分别分出2个线程,所以一共是四个线程,最终出现4次After语句。

    6、forkdemo3.c

     #include    <stdio.h>
        #include    <stdlib.h>
        #include    <unistd.h>
            int fork_rv;
    
        int main()
        {
    
            printf("Before: my pid is %d
    ", 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 parent. my child is %d
    ", getpid());
    
                exit(0);
            }
            else{
                printf("I am the parent. my child is %d
    ", fork_rv);
                exit(0);
            }
    
            return 0;
        }

    运行结果

    分析:

    fork函数会将一个进程分成两个进程,并且会返回两次,所以如上图所示,我们可以看到,出现了一次“I am the parent. my child is 4954”,又出现了一次“I am the parent. my child is 4954”。这个c文件,还包括了错误处理,提高了代码的健壮性。

    7、forkdemo4.c

     #include    <stdio.h>
        #include    <stdlib.h>
        #include    <unistd.h>
    
        int main()
        {
            int fork_rv;
    
            printf("Before: my pid is %d
    ", 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
    ", getpid());
                printf("parent pid= %d, my pid=%d
    ", getppid(), getpid());
                exit(0);
            }
    
            else{
                printf("I am the parent. my child is %d
    ", fork_rv);
                sleep(10);
                exit(0);
            }
    
            return 0;
        }

    运行结果

    现象:最后一行是10s之后才出现的

    分析:

    这是因为sleep(10)函数,使父进程睡眠10s再执行exit(0)语句。 
    注释掉sleep的结果如图:

    因为,没有sleep的休眠,父进程直接执行exit(0)退出进程,出现了输入命令的提示行;而此时子进程还没有退出,之后子进程执行到exit(0)再退出,然而这次没有出现输入命令的提示行。

    8、forkgdb.c

    #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
    
        int  gi=0;
        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
    ", li++);
                    sleep(1);
                    printf("child gi:%d
    ", gi++);
                    printf("child si:%d
    ", si++);
                }
                exit(0);
    
            }
            else{
                for(i=0; i<5; i++){
                    printf("parent li:%d
    ", li++);
                    printf("parent gi:%d
    ", gi++);
                    sleep(1);
                    printf("parent si:%d
    ", si++);
                }
            exit(0);    
    
            }
            return 0;
        }

    运行结果

    分析:

    开始时,先进入父进程的循环,打印parent li:0和parent gi:0,接着休眠一秒,子进程打印child li:0,休眠一秒,父进程接着打印parent si:0,又休眠,循环往复进行,直到跳出循环,从上图中,我们可以看到,是父进程先结束,退出,出现输入命令的提示行,接着子进程打印完最后两句后,也退出。

    9、psh1.c

    功能:执行用户输入的指令,该指令用数组存储。

     #include    <stdio.h>
        #include    <stdlib.h>
        #include    <string.h>
        #include    <unistd.h>
        #define MAXARGS     20              
        #define ARGLEN      100             
    
        int execute( char *arglist[] )
        {
            execvp(arglist[0], arglist);        
            perror("execvp failed");
            exit(1);
        }
    
        char * makestring( char *buf )
        {
            char    *cp;
    
            buf[strlen(buf)-1] = '';      
            cp = malloc( strlen(buf)+1 );       
            if ( cp == NULL ){          
                fprintf(stderr,"no memory
    ");
                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 != '
    ' )
                    arglist[numargs++] = makestring(argbuf);
                else
                {
                    if ( numargs > 0 ){     
                        arglist[numargs]=NULL;  
                        execute( arglist ); 
                        numargs = 0;        
                    }
                }
            }
            return 0;
        }

    运行结果

    失败的情况一:

    失败的情况二:

    成功的情况:

    分析:

    首先while循环输入命令,并将输入的值转换为字符串型,直到输入回车换行时,调用execute函数,将存储命令的数组作为参数传入,实现执行指令的功能。 
    运行结果中失败的情况,分别显示不同错误的处理方式不同。

    10、psh2.c

    功能:在子进程中执行用户输入的指令,利用wait函数,通过父进程,实现循环输入指令。

     #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             
    
        char *makestring( char *buf )
        {
            char    *cp;
    
            buf[strlen(buf)-1] = '';      
            cp = malloc( strlen(buf)+1 );       
            if ( cp == NULL ){          
                fprintf(stderr,"no memory
    ");
                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
    ",
                            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 != '
    ' )
                    arglist[numargs++] = makestring(argbuf);
                else
                {
                    if ( numargs > 0 ){     
                        arglist[numargs]=NULL;  
                        execute( arglist ); 
                        numargs = 0;        
                    }
                }
            }
            return 0;
        }

    运行结果

    分析:

    这个代码与psh1.c代码最大的区别就在于execute函数。 
    调用wait(&status)等价于调用waitpid(-1.&status,0),当option=0时,waitpid挂起调用进程的执行,直到它的等待集合中的一个子进程终止。只要有一个子进程没有结束,父进程就被挂起。所以当wait返回pid时没说明,子进程都已经结束,即用户输入的指令都已经执行完毕。因为execute函数在大的循环中调用,所以会循环执行下去,除非用户强制退出。 
    另外,当子进程正常执行完用户指令后,子进程的状态为0,若执行指令出错,子进程的状态为1.

    11、testbuf1.c

    功能:打印hello,但没有结束进程,若此时向标准输入设备中输入数据,屏幕上会显示

     #include <stdio.h>
        #include <stdlib.h>
        int main()
        {
            printf("hello");
            fflush(stdout);
            while(1);
        }

    运行结果

    分析:

    打印hello,但没有结束进程,若此时向标准输入设备中输入数据,屏幕上会显示出来。必须用户强制退出,才能退出程序。

    12、testbuf2.c

    功能:同testbuf1.c一样 #include <stdio.h> int main() { printf("hello "); while(1); }

    运行结果

    分析:

    从testbuf1.c和testbuf2.c的运行结果上看,我们可以猜出fflush(stdout);的功能就是打印换行符。

    13、testbuf3.c

    功能:比较打印的差别 #include <stdio.h>

     int main()
        {
            fprintf(stdout, "1234", 5);
            fprintf(stderr, "abcd", 4);
        }

    运行结果

    分析:

    根据结果,我猜测,是因为stderr缓冲区的大小为4,所以,没有‘’,所以它先打印,因为字符串必须有‘’才能结束,所以最终结果如图所示。

    14、testpid.c

    功能:显示进程的id

      #include <stdio.h>
        #include <unistd.h>
    
        #include <sys/types.h>
    
        int main()
        {
            printf("my pid: %d 
    ", getpid());
            printf("my parent's pid: %d 
    ", getppid());
            return 0;
        }

    运行结果

    分析:

    显示进程id和其父进程的id

    15、testpp.c

    功能:

      #include <stdio.h>
        #include <stdlib.h>
        int main()
        {
            char **pp;
            pp[0] = malloc(20);
    
            return 0;
        }

    运行结果

    分析:

    提示段错误。可能是数组越界导致的。我猜测,应该是计算机中的存储字节要大于20。 
    好吧,修改成64后,还是提示段错误。不知道了。。。

    16、testsystem.c

    功能:

     #include    <stdlib.h>
    
        int main ( int argc, char *argv[] )
        {
    
            system(argv[1]);
            system(argv[2]);
            return EXIT_SUCCESS;
        }               /* ----------  end of function main  ---------- */

    运行结果

    分析:

    system函数:发出一个DOS命令 
    用 法: int system(char *command); 
    system函数需加头文件<stdlib.h>后方可调用。 
    最终就是执行用户输入的指令。

    17、waitdemo1.c

    功能:验证父子进程的调用顺序,测试函数sleep、wait在进程调用中的作用。

    #include    <stdio.h>
        #include    <stdlib.h>
        #include    <sys/types.h>
        #include    <sys/wait.h>
        #include    <unistd.h>
    
        #define DELAY   4
    
        void child_code(int delay)
        {
            printf("child %d here. will sleep for %d seconds
    ", getpid(), delay);
            sleep(delay);
            printf("child done. about to exit
    ");
            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
    ", 
                    childpid, wait_rv);
        }
        int main()
        {
            int  newpid;
            printf("before: mypid is %d
    ", getpid());
            if ( (newpid = fork()) == -1 )
                perror("fork");
            else if ( newpid == 0 )
                child_code(DELAY);
            else
                parent_code(newpid);
    
            return 0;
        }

    运行结果

    分析:

    我们可以看到hildcode函数里,调用了sleep函数,这表示执行完printf("child %d here. will sleep for %d seconds ", getpid(), delay);语句后,系统休眠4s继续进行。 
    为什么这里不会让父进程继续进行?本来父子进程时并发执行的,按理说应该子进程休眠,父进程正常执行的,是因为parent
    code函数里的wait_rv = wait(NULL);代码,说明要子程序执行完毕,父进程才能继续往下进行。 
    所以最终结果如上图所示。

    18、waitdemo2.c

    功能:在waitdemo1.c的基础上,设置了状态位。

    #include    <stdio.h>
        #include    <stdlib.h>
        #include    <sys/types.h>
        #include    <sys/wait.h>
        #include    <unistd.h>
    
        #define DELAY   10
    
        void child_code(int delay)
        {
            printf("child %d here. will sleep for %d seconds
    ", getpid(), delay);
            sleep(delay);
            printf("child done. about to exit
    ");
            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
    ", 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
    ", high_8, low_7, bit_7);
        }
    
        int main()
        {
            int  newpid;
    
            printf("before: mypid is %d
    ", getpid());
    
            if ( (newpid = fork()) == -1 )
                perror("fork");
            else if ( newpid == 0 )
                child_code(DELAY);
            else
                parent_code(newpid);
        }

    运行结果

    分析:

    waitdemo2.c和waitdemo1.c最大的不同就是:设置了子进程结束后父进程的状态位。

    19、argtest.c

    功能:

     #include <stdio.h>
        #include <stdlib.h>
        #include "argv.h"
    
        int main(int argc, char *argv[]) {
           char delim[] = " 	";
           int i;
           char **myargv;
           int numtokens;
    
           if (argc != 2) {
              fprintf(stderr, "Usage: %s string
    ", argv[0]);
              return 1;
           }   
           if ((numtokens = makeargv(argv[1], delim, &myargv)) == -1) {
              fprintf(stderr, "Failed to construct an argument array for %s
    ", argv[1]);
              return 1;
           } 
           printf("The argument array contains:
    ");
           for (i = 0; i < numtokens; i++)
              printf("%d:%s
    ", i, myargv[i]);
    
           execvp(myargv[0], myargv);
    
           return 0;
        }

    运行结果

    分析:

    编译运行出错!

    20、freemakeargv.c

    功能:

     #include <stdlib.h>
        #include "argv.h"
    
        void freemakeargv(char **argv) {
           if (argv == NULL)
              return;
           if (*argv != NULL)
              free(*argv);
           free(argv);
        }

    运行结果

    分析:

    21、makeargv.c

    功能:

    #include <errno.h>
        #include <stdlib.h>
        #include <string.h>
        #include "argv.h"
    
        int makeargv(const char *s, const char *delimiters, char ***argvp) {
           int error;
           int i;
           int numtokens;
           const char *snew;
           char *t;
    
           if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) {
              errno = EINVAL;
              return -1;
           }
           *argvp = NULL;                           
           snew = s + strspn(s, delimiters);      
           if ((t = malloc(strlen(snew) + 1)) == NULL) 
              return -1; 
           strcpy(t, snew);               
           numtokens = 0;
           if (strtok(t, delimiters) != NULL)    
              for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ; 
    
           if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
              error = errno;
              free(t);
              errno = error;
              return -1; 
           } 
           if (numtokens == 0) 
              free(t);
           else {
              strcpy(t, snew);
              **argvp = strtok(t, delimiters);
              for (i = 1; i < numtokens; i++)
                  *((*argvp) + i) = strtok(NULL, delimiters);
            } 
            *((*argvp) + numtokens) = NULL;   
            return numtokens;
        }     

    运行结果

    分析:

    编译运行出错!

    22、environ.c

    功能:打印设置环境变量的值

     #include <stdio.h>
        #include <stdlib.h>
    
        int main(void)
        {
            printf("PATH=%s
    ", getenv("PATH"));
            setenv("PATH", "hello", 1);
            printf("PATH=%s
    ", getenv("PATH"));
        #if 0
            printf("PATH=%s
    ", getenv("PATH"));
            setenv("PATH", "hellohello", 0);
            printf("PATH=%s
    ", getenv("PATH"));
    
    
            printf("MY_VER=%s
    ", getenv("MY_VER"));
            setenv("MY_VER", "1.1", 0);
            printf("MY_VER=%s
    ", getenv("MY_VER"));
        #endif
            return 0;
        }

    运行结果

    分析:

    如图所示:先打印了一开始的初始环境变量,接着重新设置环境变量,并打印输出。

    23、environvar.c

    功能:

     #include <stdio.h>
        int main(void)
        {
            extern char **environ;
            int i;
            for(i = 0; environ[i] != NULL; i++)
                printf("%s
    ", environ[i]);
    
            return 0;
        }

    运行结果

    分析:

    将外部变量environ的内容打印出来,也就是把系统相关宏值,打印出来。

    24、consumer.c

    功能:判断是否打开文件流,并判断是否正常打开文件。

    #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <fcntl.h>
        #include <limits.h>
        #include <sys/types.h>
        #include <sys/stat.h>
    
        #define FIFO_NAME "/tmp/myfifo"
        #define BUFFER_SIZE PIPE_BUF
    
    
        int main()
        {
            int pipe_fd;
            int res;
    
            int open_mode = O_RDONLY;
            char buffer[BUFFER_SIZE + 1];
            int bytes = 0;
    
            memset(buffer, 0, sizeof(buffer));
    
            printf("Process %d opeining FIFO O_RDONLY 
    ", getpid());
            pipe_fd = open(FIFO_NAME, open_mode);//判断打开文件是否成功
            printf("Process %d result %d
    ", getpid(), pipe_fd);
    
            if (pipe_fd != -1) {
                do {
                    res = read(pipe_fd, buffer, BUFFER_SIZE);
                    bytes += res;
                } while (res > 0);
                close(pipe_fd);
            } else {
                exit(EXIT_FAILURE);
            }
    
            printf("Process %d finished, %d bytes read
    ", getpid(), bytes);
            exit(EXIT_SUCCESS);
        }

    运行结果

    分析:

    输出打开文件流的进程号,以及打开文件进程号,并返回打开文件的结果。并且可以输入消息。

    25、producer.c

    #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <fcntl.h>
        #include <limits.h>
        #include <sys/types.h>
        #include <sys/stat.h>
    
        #define FIFO_NAME "/tmp/myfifo"
        #define BUFFER_SIZE PIPE_BUF
        #define TEN_MEG (1024 * 1024 * 10)
    
        int main()
        {
            int pipe_fd;
            int res;
            int open_mode = O_WRONLY;
    
            int bytes = 0;
            char buffer[BUFFER_SIZE + 1];
    
            if (access(FIFO_NAME, F_OK) == -1) {
                res = mkfifo(FIFO_NAME, 0777);
                if (res != 0) {
                    fprintf(stderr, "Could not create fifo %s 
    ",
                        FIFO_NAME);
                    exit(EXIT_FAILURE);
                }
            }
    
            printf("Process %d opening FIFO O_WRONLY
    ", getpid());
            pipe_fd = open(FIFO_NAME, open_mode);
            printf("Process %d result %d
    ", getpid(), pipe_fd);//该句无法被打印
    
            if (pipe_fd != -1) {
                while (bytes < TEN_MEG) {
                    res = write(pipe_fd, buffer, BUFFER_SIZE);
                    if (res == -1) {
                        fprintf(stderr, "Write error on pipe
    ");
                        exit(EXIT_FAILURE);
                    }
                    bytes += res;
                }
                close(pipe_fd);
            } else {
                exit(EXIT_FAILURE);
            }
    
            printf("Process %d finish
    ", getpid());
            exit(EXIT_SUCCESS);
        }

    运行结果

    26、testmf.c

     #include  <stdio.h>
        #include  <stdlib.h>
        #include  <sys/types.h>
        #include  <sys/stat.h>
    
        int main()
        {
            int res = mkfifo("/tmp/myfifo", 0777);
            if (res == 0) {
                printf("FIFO created 
    ");
            }
            exit(EXIT_SUCCESS);
        }

    运行结果

    分析:

    结果如上图,说明创建失败了。

    27、listargs.c

    功能:打印指令

     #include    <stdio.h>
    
        main( int ac, char *av[] )
        {
            int i;
    
            printf("Number of args: %d, Args are:
    ", ac);
            for(i=0;i<ac;i++)
                printf("args[%d] %s
    ", i, av[i]);
    
            fprintf(stderr,"This message is sent to stderr.
    ");
        }

    运行结果

    分析:

    打印用户输入的指令,输出相关信息。

    28、pipe.c

    功能:实现管道的功能

     #include    <stdio.h>
        #include    <stdlib.h>
        #include    <unistd.h>
    
        #define oops(m,x)   { perror(m); exit(x); }
    
        int main(int ac, char **av)
        {
            int thepipe[2],         
                newfd,              
                pid;                
    
            if ( ac != 3 ){
                fprintf(stderr, "usage: pipe cmd1 cmd2
    ");
                exit(1);
            }
            if ( pipe( thepipe ) == -1 )        
                oops("Cannot get a pipe", 1);
    
            if ( (pid = fork()) == -1 )         
                oops("Cannot fork", 2);
    
            if ( pid > 0 ){         
                close(thepipe[1]);  
    
                if ( dup2(thepipe[0], 0) == -1 )
                    oops("could not redirect stdin",3);
    
                close(thepipe[0]);  
                execlp( av[2], av[2], NULL);
                oops(av[2], 4);
            }
    
            close(thepipe[0]);      
    
            if ( dup2(thepipe[1], 1) == -1 )
                oops("could not redirect stdout", 4);
    
            close(thepipe[1]);      
            execlp( av[1], av[1], NULL);
            oops(av[1], 5);
        }

    运行结果

    分析:

    相当于管道的作用

    29、pipedemo.c

    功能:将输入输出用管道连接

     #include    <stdio.h>
        #include    <stdlib.h>
        #include    <string.h>
        #include    <unistd.h>
    
        int main()
        {
            int len, i, apipe[2];   
            char    buf[BUFSIZ];        
    
            if ( pipe ( apipe ) == -1 ){
                perror("could not make pipe");
                exit(1);
            }
            printf("Got a pipe! It is file descriptors: { %d %d }
    ", 
                                    apipe[0], apipe[1]);
    
    
            while ( fgets(buf, BUFSIZ, stdin) ){
                len = strlen( buf );
                if (  write( apipe[1], buf, len) != len ){  
                    perror("writing to pipe");      
                    break;                  
                }
                for ( i = 0 ; i<len ; i++ )                     
                    buf[i] = 'X' ;
                len = read( apipe[0], buf, BUFSIZ ) ;       
                if ( len == -1 ){               
                    perror("reading from pipe");        
                    break;
                }
                if ( write( 1 , buf, len ) != len ){        
                    perror("writing to stdout");        
                    break;                  
                }
            }
        }

    运行结果

    分析:

    我猜测是打开文件,将从标准输入中输入的数据打印到标准输出上,需要强制退出。

    30、pipedemo2.c

    功能:

    #include    <stdio.h>
        #include    <stdlib.h>
        #include    <string.h>
        #include    <unistd.h>
    
    
        #define CHILD_MESS  "I want a cookie
    "
        #define PAR_MESS    "testing..
    "
        #define oops(m,x)   { perror(m); exit(x); }
    
        main()
        {
            int pipefd[2];      
            int len;            
            char    buf[BUFSIZ];        
            int read_len;
    
            if ( pipe( pipefd ) == -1 )
                oops("cannot get a pipe", 1);
    
            switch( fork() ){
                case -1:
                    oops("cannot fork", 2);
    
                case 0:         
                    len = strlen(CHILD_MESS);
                    while ( 1 ){
                        if (write( pipefd[1], CHILD_MESS, len) != len )
                            oops("write", 3);
                        sleep(5);
                    }
    
                default:        
                    len = strlen( PAR_MESS );
                    while ( 1 ){
                        if ( write( pipefd[1], PAR_MESS, len)!=len )
                            oops("write", 4);
                        sleep(1);
                        read_len = read( pipefd[0], buf, BUFSIZ );
                        if ( read_len <= 0 )
                            break;
                        write( 1 , buf, read_len );
                    }
            }
        }

    运行结果

    分析:

    从上图中我们可以分析出:fork函数执行后,进程先执行父进程,父进程休眠1s,接着子进程运行;子进程打印"I want a cookie",接着休眠5s,父进程接着打印,所以出现4次testing..之后又出现子进程的打印语句。

    31、stdinredir1.c

    #include    <stdio.h>
        #include    <fcntl.h>
    
        int main()
        {
            int fd ;
            char    line[100];
    
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
    
            close(0);
            fd = open("/etc/passwd", O_RDONLY);
            if ( fd != 0 ){
                fprintf(stderr,"Could not open data as fd 0
    ");
                exit(1);
            }
    
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
        }

    运行结果

    分析:

    如上图所示:先从标准输入输入3行信息,接着分别打印这三行信息,执行打开文件语句,若打开正常,则从文件中读取前三行信息。

    32、stdinredir2.c

    #include    <stdio.h>
        #include    <stdlib.h>
        #include    <fcntl.h>
    
        //#define   CLOSE_DUP       
        //#define   USE_DUP2    
    
        main()
        {
            int fd ;
            int newfd;
            char    line[100];
    
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
    
            fd = open("data", O_RDONLY);    
        #ifdef CLOSE_DUP
            close(0);
            newfd = dup(fd);        
        #else
            newfd = dup2(fd,0);     
        #endif
            if ( newfd != 0 ){
                fprintf(stderr,"Could not duplicate fd to 0
    ");
                exit(1);
            }
            close(fd);          
    
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
            fgets( line, 100, stdin ); printf("%s", line );
        }

    运行结果

    分析:

    上图结果表示打开文件失败的情况。

    33、testtty.c

    #include <unistd.h>
    
        int main()
        {
            char *buf = "abcde
    ";
            write(0, buf, 6);
        }

    运行结果

    分析:

    将缓冲区中的内容打印出来

    34、whotofile.c

    #include    <stdio.h>
        #include    <stdlib.h>
        #include    <unistd.h>
    
        int main()
        {
            int pid ;
            int fd;
    
            printf("About to run who into a file
    ");
    
            if( (pid = fork() ) == -1 ){
                perror("fork"); exit(1);
            }
            if ( pid == 0 ){
                close(1);               /* close, */
                fd = creat( "userlist", 0644 );     /* then open */
                execlp( "who", "who", NULL );       /* and run  */
                perror("execlp");
                exit(1);
            }
            if ( pid != 0 ){
                wait(NULL);
                printf("Done running who.  results in userlist
    ");
            }
    
            return 0;
        }

    运行结果

    分析:

    定义函数:int close(int fd); 
    函数说明:当使用完文件后若已不再需要则可使用 close()关闭该文件, 二close()会让数据写回磁盘, 并释放该文件所占用的资源. 参数fd 为先前由open()或creat()所返回的文件描述词. 
    返回值:若文件顺利关闭则返回0, 发生错误时返回-1. 
    从结果中我们可以看出,没有子进程的执行,我们知道fork函数会产生2个返回,所以子进程是一定有的,close(1)关闭了子进程的标准输出,所以之后的执行都无法打印出来。

    35、sigactdemo.c

     #include    <stdio.h>
        #include    <unistd.h>
        #include    <signal.h>
        #define INPUTLEN    100
        void inthandler();  
        int main()
        {
            struct sigaction newhandler;    
            sigset_t blocked;   
            char x[INPUTLEN];
            newhandler.sa_handler = inthandler; 
            newhandler.sa_flags = SA_RESTART|SA_NODEFER
                |SA_RESETHAND;  
            sigemptyset(&blocked);  
            sigaddset(&blocked, SIGQUIT);   
            newhandler.sa_mask = blocked;   
            if (sigaction(SIGINT, &newhandler, NULL) == -1)
                perror("sigaction");
            else
                while (1) {
                    fgets(x, INPUTLEN, stdin);
                    printf("input: %s", x);
                }
            return 0;
        }
        void inthandler(int s)
        {
            printf("Called with signal %d
    ", s);
            sleep(s * 4);
            printf("done handling signal %d
    ", s);
        }

    运行结果

    分析:

    从上图的结果中我们可以看到,该代码的功能是,将标准输入的信息打印到标准输出上,需要强制退出结束进程。

    36、sigactdemo2.c

    #include <unistd.h>
        #include <signal.h>
        #include <stdio.h>
    
        void sig_alrm( int signo )
        {
            /*do nothing*/
        }
    
        unsigned int mysleep(unsigned int nsecs)
        {
            struct sigaction newact, oldact;
            unsigned int unslept;
    
            newact.sa_handler = sig_alrm;
            sigemptyset( &newact.sa_mask );
            newact.sa_flags = 0;
            sigaction( SIGALRM, &newact, &oldact );
    
            alarm( nsecs );
            pause();
    
            unslept = alarm ( 0 );
            sigaction( SIGALRM, &oldact, NULL );
    
            return unslept;
        }
    
        int main( void )
        {
            while( 1 )
            {
                mysleep( 2 );
                printf( "Two seconds passed
    " );
            }
    
            return 0;
        }

    运行结果

    分析:

    从上图中可以看出,该代码的功能是每2s打印"Two seconds passed"。

    37、sigdemo1.c

    #include    <stdio.h>
        #include    <signal.h>
        void    f(int);         
        int main()
        {
            int i;
            signal( SIGINT, f );        
            for(i=0; i<5; i++ ){        
                printf("hello
    ");
                sleep(2);
            }
    
            return 0;
        }
    
        void f(int signum)          
        {
            printf("OUCH!
    ");
        }

    运行结果

    分析:

    每隔2s打印一次hello。

    38、sigdemo2.c

     #include    <stdio.h>
        #include    <signal.h>
    
        main()
        {
            signal( SIGINT, SIG_IGN );
    
            printf("you can't stop me!
    ");
            while( 1 )
            {
                sleep(1);
                printf("haha
    ");
            }
        }

    运行结果

    分析:

    每隔1s打印一次"haha"。

    39、sigdemo3.c

     #include    <stdio.h>
        #include    <string.h>
        #include    <signal.h>
        #include    <unistd.h>
    
        #define INPUTLEN    100
    
        int main(int argc, char *argv[])
        {
            void inthandler(int);
            void quithandler(int);
            char input[INPUTLEN];
            int nchars;
    
            signal(SIGINT, inthandler);//^C 
            signal(SIGQUIT, quithandler);//^
    
            do {
                printf("
    Type a message
    ");
                nchars = read(0, input, (INPUTLEN - 1));
                if (nchars == -1)
                    perror("read returned an error");
                else {
                    input[nchars] = '';
                    printf("You typed: %s", input);
                }
            }
            while (strncmp(input, "quit", 4) != 0);
            return 0;
        }
    
        void inthandler(int s)
        {
            printf(" Received signal %d .. waiting
    ", s);
            sleep(2);
            printf("  Leaving inthandler 
    ");
        }
    
        void quithandler(int s)
        {
            printf(" Received signal %d .. waiting
    ", s);
            sleep(3);
            printf("  Leaving quithandler 
    ");
        }

    运行结果

    分析:

    从上图看出,我们从标准输入输入消息,在标准输出上打印出来。

    遇到的问题

    1、不是说fork函数,产生的两个线程的执行顺序是不确定的,为什么我多次执行,都是先显示父进程的,如图所示

    2、testpp.c代码老是提示段错误,不知道什么原因,开始我猜测是数组越界,我把malloc函数的值改大了,还是提示段错误? 
    3、argv文件夹下的c文件都不能正常编译运行,例如,argtest.c编译出现错误,如图所示。

    参考资料

    1、关于execl(),execlp(),execle(),execv(),execvp(),execvp(),execve()原语的区别: http://www.2cto.com/kf/201409/334500.html

     

  • 相关阅读:
    解决阿里云服务器磁盘报警
    linux服务器启动报错UNEXPECTED INCONSISTENCY解决方法
    记一次gitlab添加用户收不到邮件的解决办法
    php7安装redis拓展
    centos6.5安装部署zabbix监控服务端和客户端
    centos-6.5安装部署LNMP环境
    centos6.5编译安装php7
    centos6.5新增加硬盘挂载并实现开机自动挂载
    简单快速部署samba服务器
    第177天:常用正则表达式(最全)
  • 原文地址:https://www.cnblogs.com/java-stx/p/4999488.html
Copyright © 2011-2022 走看看