美文网首页上嵌学习笔记
系统与网络编程(进程及进程间通信)

系统与网络编程(进程及进程间通信)

作者: I踏雪寻梅 | 来源:发表于2016-12-01 21:00 被阅读44次

    系统与网络编程

    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

    通信方式

    1. 管道通信


      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

    1. 进程的状态及状态间的转化
      • 进程的状态有:就绪态,执行态,阻塞态。
        1. 就绪→执行
          处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态。
        2. 执行→就绪
          处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态。
        3. 执行→阻塞
          正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。
        4. 阻塞→就绪
          处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。
    2. 完善目录拷贝
    3. 独立完成模仿终端的代码
    4. 通过无名管道,让两个子进程间完成相互通信工作

    相关文章

      网友评论

        本文标题:系统与网络编程(进程及进程间通信)

        本文链接:https://www.haomeiwen.com/subject/oihfmttx.html