操作系统实践(四/五)

  本次实验课的内容涉及到以下几个方面:
    1.文件的内核实现
    2.标准的输入输出
    3.系统调用dup和pipe

  文件最基本的系统调用是open和close,open一个文件后会返回一个fd,作为这个文件的标识,后续有关于这个文件的操作都使用fd去完成。

1.文件的内核实现

  文件的内核实现中围绕着四个结构体:索引节点、file结构体、文件描述符表、进程控制块。下面介绍下它们各自存储的内容:
  索引节点中保存了文件的大小、文件存放在磁盘的位置、文件的创建时间、修改时间、文件的所有者、文件的访问权限
  file结构体file结构体存了被打开文件的信息、文件对应的索引节点(inode)、文件的当前访问位置、文件的打开模式(只读、只写、可读可写)
  文件描述符表是一个数组,数组的元素类型是指针,指针指向一个file结构体,用于保存被打开的文件。当内核打开文件时,分配一个file结构体表示被打开的文件,将该file结构体指针保存在文件描述符表中
  进程控制块是操作系统表示进程状态的数据结构,存放用于描述进程情况及控制进程运行所需的全部信息(进程标识信息、处理机状态、进程调度信息、打开文件列表,即文件描述符表,记录了该进程打开的文件)

2.标准的输入输出

  标准的输入输出就是指write和read

write(1, buf, sizeof(buf)); // 标准输入,就是键盘输入
read(0, buf, sizeof(buf)); //标准输出,就是终端输出

3.系统调用dup和pipe

   dup(重定向)
在这里插入图片描述  dup就是让一个新的fd去指向一个文件,这样文件就有了两个指向。可以把老fd解放出来,去完成其他操作。
还有一个变形的dup2,完成一样的功能。调用方式不同
在这里插入图片描述
  pipe(管道)
在这里插入图片描述  pipe的实现是基于队列,一端作为输入端,一端作为输出端。整体结构如下:
在这里插入图片描述
  以上就是这次实验课的全部理论学习啦,下面看看作业吧!这次的作业没有关于dup和pipe的内容,是上节课mysys实现的变形。
在这里插入图片描述  源代码如下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>

void mysys(char *command) {

        char *argv[512]; // 这里必须要用动态指针数组,因为execvp最后有一个NULL作为结束标志,静态的二维数组是无法实现的。
        int num = 0;
        char temp[512];
        for (int i=0; command[i]!='\0'; i++) {
                int index = 0;
                while (command[i]!='\0' && command[i] != ' ') {
                        temp[index++] = command[i++];
                }
                temp[index] = '\0';
                if (command[i] == '\0')
                        break;
                argv[num] = (char *)malloc(strlen(temp));
                strcpy(argv[num], temp);
                num++;
        }
        argv[num] = (char *)malloc(strlen(temp));
        strcpy(argv[num], temp);
        num++;
        argv[num] = NULL;
        pid_t  pid;
        if (command == NULL)
                return ;
        if ((pid = fork()) < 0) {

        }
        else if (pid == 0) {
                execvp(argv[0], argv);
                exit(127);
        }
        else {
                sleep(1);
        }
        return ;
}

int main() {
        while (1) {
                write(1, "> ", 3); // 此处可以使用write
                /* printf("> "); 
                 如果这样使用printf是不可以的,printf有输出缓冲区,遇到\n才会统一调用一次write。实现的方式有两种:
                 	1.printf("\n")
                 	2.fflush(stdout);
                */
                // 在底层编程时,使用printf就可以,更方便
                char buf[80];
                int count;
                count = read(0, buf, sizeof(buf));
                // buf[count] = 0; //这个是错的,输入回车后,末尾还会读入一个\n
                buf[count-1] = 0;
                if (strcmp(buf, "exit") == 0)
                        //exit(127)也可以;
                        break;
                mysys(buf);
        }
        return 0;
}

  第四次,打板儿!


  第五次的内容和上次一样的,区别的是作业,就写在一篇里了。
在这里插入图片描述  源代码如下:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>

void mysys(char *command) {

	char *argv[512]; // 这里必须要用动态指针数组,因为execvp最后有一个NULL作为结束标志,静态的二维数组是无法实现的。
	int num = 0;
	char temp[512];
	for (int i=0; command[i]!='\0'; i++) {
		int index = 0;
		while (command[i]!='\0' && command[i] != ' ') {
			temp[index++] = command[i++];
		}
		temp[index] = '\0';
		if (command[i] == '\0')
			break;
		argv[num] = (char *)malloc(strlen(temp));
		strcpy(argv[num], temp);
		num++;
	}
	argv[num] = (char *)malloc(strlen(temp));
	strcpy(argv[num], temp);
	num++;
	argv[num] = NULL;
	
	pid_t  pid;
	if (command == NULL)
		return ;
	if ((pid = fork()) < 0) {

	}
	else if (pid == 0) {
		/*
			思路:对输入命令进行判断,如果是echo再进一步判断有没有重定向标志: >目标文件,如果有按重定向方法写入指定文件,否则按正常echo输出`
		*/
		if (strcmp(argv[0], "echo") == 0) {
			int i, j;
			int tag = 0;
			for (i=0; i<num; i++) {
				for (j=0; argv[i][j] != '\0'; j++) {
					if (argv[i][j] = '>' && argv[i][j+1] != '\0' && i == num-1) {
						tag = 1;
						break;
					}

				}
				if (tag == 1)
					break;
			}
			if (tag == 1) { // tag为1说明存在重定向,下面截取目标文件名及写入内容
				// 截取文件名
				char filename[10];
				int filename_index = 0;
				for (int j=1; argv[i][j]!='\0'; j++) {
					filename[filename_index++] = argv[i][j];
				}
				filename[filename_index] = '\0';
				
				char content[20];
				int content_index = 0;
				
				// 截取内容,已知为echo命令,从5号以后为内容
				for (int k=5; command[k]!='\0'; k++) {
					if (command[k] == '>') {
						content[content_index] = '\0';
						break;
					}
					else 
						content[content_index++] = command[k];
				}
				// 使用重定向方式,将fd改为1
				int fd;
				fd = open(filename, O_CREAT|O_RDWR, 0777);
				dup2(fd, 1); // 函数格式(源,目标)
				write(1, content, sizeof(content));
			}
			else {
                                execvp(argv[0], argv);
			}
		}
		else
			execvp(argv[0], argv); 
			
		exit(127);
	}
	else {
		sleep(1);
	}
	return ;
}

int main() {
	while (1) {
		write(1, "> ", 3); // 此处需要使用write,用printf的话会不输出
		char buf[80];
		int count;
		count = read(0, buf, sizeof(buf));
		// buf[count] = 0; //这个是错的,输入回车后,末尾还会读入一个\n
		buf[count-1] = 0;
		if (strcmp(buf, "exit") == 0)
			break;
		mysys(buf);
	}
	return 0;
}

  这次的作业主要是增加一个要求:echo另外一个内容写入指定文件(之前的echo是输出到屏幕,重定向后将1号指向文件,就不会在上输出了)。但悲催的是:我这份代码能够完成新功能,对于普通功能的echo没用了(呜呜呜),也就是echo a b c没了反应,到现在也没找到问题。如果有人看出来,请在下方评论区留言,感谢!

  上节课老师还让实现pwd,cd,使用execvp无法完成,想了好久都没有结果,但其实是有系统调用的:

char *cwd = getcwd(buff,sizeof(buff)); // pwd,返回值cwd即为结果
chdir(comnd[1]); // cd,comnd为路径

因作者水平有限,如有错误之处,请在下方评论区指正,谢谢!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值