zoukankan      html  css  js  c++  java
  • 20165329 mybash的实现

    20165329 mybash的实现

    实验要求

    • 使用fork,exec,wait实现mybash
    • 写出伪代码,产品代码和测试代码
    • 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)

    使用fork,exec,wait实现mybash

    fork

    首先用man命令查看fork的使用方法

    • 其功能

    通过复制调用fork的进程创建一个新进程。

    • 返回值

    创建子进程成功时,fork在父进程中返回子进程的pid,在子进程中返回0。失败时,在父进程中返回-1,无子进程被创建,相应的错误在errno中设置。

    • [fork创建子进程代码]

      #include <unistd.h>
      #include <stdio.h>
      #include <stdlib.h>
      int main(void)
      {
      char *msg;
      int n;
      pid_t pid;
      pid = fork();
      if (pid < 0) {
      perror("fork failed");
      exit(1);
      }
      if (pid == 0) {
      msg = "This is in child progress ";
      n = 6;
      } else {
      msg = "This is in parent progress ";
      n = 3;
      }
      for (; n > 0; --n) {
      printf("%s", msg);
      //sleep(1);
      }
      return 0;
      }

    • fork创建子进程代码

    将代码中加入sleep(1)重新编译并运行程序得到运行结果:

    其不同的原因为当程序执行fork()语句后就又多出了一个进程,进程的运行符合“多个进程的运行方式”。

    exec()

    首先用man命令查看exec的使用方法

    • 其功能

    当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。

    • 返回值

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

    • exec_call.c

              #include <stdio.h>

     

              int main(void)

     

              {

     

              printf("hello, world ");

     

              return 0;

              }

    • exec_test.c

      #include <unistd.h>
      #include <stdio.h>
      int main(void)
      {
      char *const argv[] ={"exec_call", NULL};
      execv("./exec_call", argv);
      printf(“here here ”);
      return 0;
      }

    • 验证exec功能代码

    当进程调用execv函数时,该进程的用户空间代码和数据完全被exec_call替换,从exec_call的启动例程开始执行。调用execv进程后面的代码没有被执行。所以出现了错误。

    • 解决方法

    在“fork创建子进程代码”中加入execv函数,改进的函数pro_control3.c:

    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
    char *msg;
    int n;
    pid_t pid;
    pid = fork();
    if (pid < 0) {
    perror("fork failed");
    exit(1);
    }
    if (pid == 0) {
    msg = "This is in child progress ";
    n = 6;
    char *const argv[] ={"exec_call", NULL};
    execv("./exec_call", argv);
    }
    else {
    msg = "This is in parent progress ";
    n = 3;
    }
    for (; n > 0; --n) {
    printf("%s", msg);
    //sleep(1);
    }
    return 0;
    }

    wait

    首先用man命令查看wait的使用方法

    • 功能

    对于一个已经终止的子进程,用wait能够让系统释放与子进程相关的资源;如果不用wait则终止的进程会变为僵尸进程。

    • 返回值

    若调用成功则返回清理掉的子进程id,若调用出错则返回-1。

    mybash代码

    • 伪代码
    1. 对用户输入的命令进行解析
    2. 检查用户输入的命令是否为内置的Linux命令
    3. 构造argv向量
    • mybash.c代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <wait.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAX 128
    void eval (char *cmdline); //对用户输入的命令进行解析
    int parseline (char *buf, char **argv);
    int builtin_command(char **argv);
    int main()
    {
    char cmdline[MAX];
    while(1){
    printf("> ");
    fgets(cmdline,MAX,stdin);
    if(feof(stdin))
    {
    printf("error");
    exit(0);
    }
    eval(cmdline);
    }
    }
    void eval(char *cmdline)
    {
    char *argv[MAX];
    char buf[MAX];
    int bg;
    pid_t pid;
    char *envp[]={0,NULL};
    strcpy(buf,cmdline);
    bg = parseline(buf,argv);//解析以空格分隔的命令行参数,填入argv数组中
    if(argv[0]==NULL)
    return;
    if(!builtin_command(argv)) //调用此函数检查用户输入的命令是否为内置的Linux命令,是则执行并返回1,不是则返回0
    {
    if((pid=fork()) == 0)
    {
    if(execve(argv[0],argv,envp) < 0) {
    printf("%s : Command not found. ",argv[0]);
    exit(0);
    }
    }
    if(!bg){
    int status;
    if(waitpid(-1,&status,0) < 0) //相当于调用wait函数
    printf("waitfg: waitpid error!");
    }
    else
    printf("%d %s",pid, cmdline);
    return;
    }
    }
    int builtin_command(char **argv)
    {
    if(!strcmp(argv[0], "quit"))
    exit(0);
    if(!strcmp(argv[0],"&"))
    return 1;
    return 0;
    }
    int parseline(char *buf,char **argv)//解析以空格分隔的命令行参数,并构造最终传给execve函数的argv向量
    {
    char *delim;
    int argc;
    int bg;
    buf[strlen(buf)-1]=' ';
    while(*buf && (*buf == ' '))
    buf++;
    argc=0;
    while( (delim = strchr(buf,' '))){ //从字符串buf中寻找空格字符第一次出现的位置
    argv[argc++] = buf;
    *delim= '';
    buf = delim + 1;
    while(*buf && (*buf == ' '))
    buf++;
    }
    argv[argc] = NULL;
    if(argc == 0)
    return 1;
    if((bg=(*argv[argc-1] == '&')) != 0)
    argv[--argc] = NULL;
    return bg;
    }

    • 结果

    实验中的问题

    实现mybash功能一开始没有加/bin,ls不能用,后面发现在前面加上“/bin”就可以了。

    感想

    本题根据网上搜索查询然后慢慢的一步一步做,深有体会,自己学的很多不足,以后的努力学好每一个知识点。

  • 相关阅读:
    DHCP服务的配置(linux)
    LVM逻辑卷
    python的元素列表
    DOS和DDOS你知道多少?
    DOS与DDOS攻击的原理与防范之法
    常见HTTP状态代码,http报错代码翻译
    TCP和UDP优缺点
    DLL何时需共享内存管理器
    Delphi 指针大全
    Delphi编写DLL(以及静态和动态方式调用)
  • 原文地址:https://www.cnblogs.com/hjwzzj/p/9998969.html
Copyright © 2011-2022 走看看