sleep实验
实验目标
sleep 10 停止10s
知识点
atoi将字符串转换为int
通关代码
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
if (argc ==1)
{
fprintf(2,"error\n");
}
int t = atoi(argv[1]);
sleep(t);
exit(0);
}
pingpong实验
实验目标
实现父子进程的通信
知识点
1.getpid可以获取当前进程的id
2.pipe(p[2])会将两个文件描述符保存到p[2]中,
一个管道可被写入多次,内容不会被覆盖,可分多次读出。管道是全双工的。
通关代码
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
char buf[512];
int
main(int argc, char *argv[])
{
int p[2];
int p2[2];
pipe(p);
pipe(p2);
int pid = fork();
if(pid==0) {
close(p[1]);
close(p2[0]);
read(p[0],buf,2);//接受pid
fprintf(1,"%s",buf);
close(p[0]);
fprintf(1,"%d: received ping\n",getpid());//打印接收到的pid
write(p2[1],"s",1);
close(p2[1]);
} else {
close(p2[0]);
close(p[0]);
write(p[1],"a",1);
write(p[1],"b",1);
close(p[1]);
pid = wait(0);
read(p2[0],buf,1);
fprintf(1,"%d: received pong\n",getpid());//打印接收到的pid
close(p2[0]);
}
exit(0);
}
primes实验
实验目标
使用素数筛法找出2~35中的素数。
知识点
1.父进程写数字进管道
write(fd[WRITEEND],&numbers[i],sizeof(numbers[i]));
注意write的第二个参数是传入地址,第三个参数是传入该参数的字节数
2.子进程从管道读
while(read(fd[READEND],&temp,sizeof(temp))!=0)
读到的第一个数为素数,后面读到的数逐一除以该素数,若不整除则更新到number数组中。
3. 使用while循环控制子进程的创建,index=0时,只剩下最后一个元素,停止创建子进程。
4. 注意:fork之后,子进程也会有相同的管道和文件描述符,需要关掉用完的管道,exec不会覆盖文件描述符。
通关代码
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
char buf[512];
#define READEND 0
#define WRITEEND 1
int
main(int argc, char *argv[])
{
int numbers[36];
int index = 0;
int fd[2];
for(int i = 2;i<=35;i++)
{
numbers[index++]=i;
}
while(index>0)
{
pipe(fd);
int pid = fork();
if(pid>0)
{
close(fd[READEND]);
for(int i=0;i<index;i++)
{
write(fd[WRITEEND],&numbers[i],sizeof(numbers[i]));
}
close(fd[WRITEEND]);
wait(0);
exit(0);
}
else if(pid==0)
{
close(fd[WRITEEND]);
index=-1;
int temp,prime=0;
while(read(fd[READEND],&temp,sizeof(temp))!=0)
{
if(index<0)
{
prime=temp;
index++;
}
else
{
if(temp%prime!=0)numbers[index++]=temp;
}
}
printf("prime %d\n", prime);
close(fd[READEND]);
}
}
exit(0);
}
find实验
实验目标
find . b
寻找该目录下所有叫b的文件并打印出来
知识点
1.stat是文件信息的结构体
可以根据type区分是目录还是具体文件(linux中目录也是文件)
2.fstat(fd, &st)可以将fd文件描述符(int类型)指向的文件的stat结构体信息赋值到st中。
3.
// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14
struct dirent {
ushort inum;
char name[DIRSIZ];
};
fd为目录的文件描述符
可通过以下代码读取该目录下的文件
struct dirent de;
while(read(fd, &de, sizeof(de)) == sizeof(de))
可通过以下代码筛选该目录下的文件
if(de.inum == 0 ||
strcmp(de.name, ".")==0 ||
strcmp(de.name, "..")==0)
4.stat(path, &st) ,其中path为char*,表示某文件的路径,st为stat结构体.将该文件的stat结构体信息赋值到st中。
5.fmtname(./a.txt)将path后面的文件名a.txt输出
6. memmove(p, de.name, DIRSIZ);
将de.name所指向地址的前DIRSIZ个字节拷贝到p所指向的地址中。
7.主要char*作为字符串时,末尾要有0.
通关代码
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
char*
fmtname(char *path)
{
static char buf[DIRSIZ+1];
char *p;
// Find first character after last slash.
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name.
if(strlen(p) >= DIRSIZ)
return p;
memmove(buf, p, strlen(p));
buf[strlen(p)] = 0;
return buf;
}
void
find(char *path,char *fileName)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path);
return;
}
if(fstat(fd, &st) < 0){
fprintf(2, "ls: cannot stat %s\n", path);
close(fd);
return;
}
switch(st.type){
case T_FILE:
//printf("filename:%s\n",fmtname(path));
//printf("filename:%s\n",fileName);
//printf("cmp:%d\n",strcmp(fmtname(path),fileName));
if(strcmp(fmtname(path),fileName) == 0)
printf("%s\n",path);
break;
case T_DIR:
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("ls: path too long\n");
break;
}
strcpy(buf, path);
p = buf+strlen(buf);
*p++ = '/';
while(read(fd, &de, sizeof(de)) == sizeof(de)){
if(de.inum == 0 || strcmp(de.name, ".")==0 || strcmp(de.name, "..")==0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if(stat(buf, &st) < 0){
printf("ls: cannot stat %s\n", buf);
continue;
}
find(buf,fileName);
//printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
}
break;
}
close(fd);
}
int
main(int argc, char *argv[])
{
find(argv[1],argv[2]);
exit(0);
return 0;
}
xargs实验
基础知识
- shell中的 ‘|‘ 是将标准输出转换为标准输入
- linux中的xargs命令是将标准输入转换为shell命令行参数(http://www.ruanyifeng.com/blog/2019/08/xargs-tutorial.html)
实验目标
实现xargs命令。
知识点
-
char *arg = (char *)malloc(sizeof(line));
申请char的内存
2. exec(filename,params),其中param的第一个参数为命令名称,最后一个参数是0
- 一个字符一个字符的读取,遇到换行或空格则为一个word.
- 命令行一行最长4095bytes
- read(0,line,1024)返回的是读取到的字节长度
- free(arg)会把内存空间的内容也删掉。
通关代码
#include "kernel/types.h"
#include "kernel/param.h"
#include "user/user.h"
int main(int argc,char *argv[])
{
char line[1024];
char* params[MAXARG];
int index = 0;
for(int i=1;i<argc;i++) params[index++]=argv[i];
int n = 0;
char *cmd = argv[1];
while((n=read(0,line,1024))>0)
{
if(fork()==0)
{
char *arg = (char *)malloc(sizeof(line));
int arg_index = 0;
for(int i=0;i<n;i++)
{
if(line[i]==' '||line[i]=='\n')
{
arg[arg_index]=0;
arg_index = 0;
params[index++]=arg;
//free(arg);
arg = (char *)malloc(sizeof(line));
}
else
{
arg[arg_index++]=line[i];
}
}
params[index] = 0;
exec(cmd,params);
}
else
{
wait(0);
}
}
return 0;
}