目录
一、课程设计的目的与要求 1
1. 学习 UNIX/LINUX 系统下的多进程创建、控制和通信。 1
二、设计正文 1
1. 任务分析 1
1.1 前台进程应实现的功能如下 1
1.2 后台进程应实现的功能如下: 3
1.3 进程间的协助如图 3 所示: 5
2. 功能实现分析 5
2.1 子进程创建 5
2.2 使用消息队列进行进程间通信 5
2.3 使用命名管道进行进程间通信 6
前台进程读取数据,使用 read 函数,如下 7
后台进程写入数据,使用 write 函数,如下: 7
关闭 FIFO 文件,使用 close 函数,如下: 7
2.4 对输入消息进行处理和转化 8
2.5 执行转化后指令 9
popen 执行结束后,可以通过 fgets 逐行读取执行的结果: 9
三、课程设计总结或结论 10
1. 本次课程设计编写了前台和后台两个进程,并使用了命名管道和消息队列两种进程间通信方式, 实现了 linux 系统上多进程的创建与通信。 10
四、参考文献 10
[1] 宫虎波, Linux 编程从入门到精通. 化学工业出版社, 第一版,2009 年 8 月出版 10
附录 10
4. back.c,其中包含了后台进程的代码 12
一、课程设计的目的与要求
1. 学习 UNIX/LINUX 系统下的多进程创建、控制和通信。
1.1 Linux 上的 bash 和 Windows 中的命令行有很大的不同。但是两者都有完成相似任务的命令,比如 Linux 上 bash 的 ls 命令的功能,类似于 Windows 命令行中的 dir 命令的功能。用 C 语言写一个简单的 Linux 终端软件,接收用户发出的类似于 Windows 命令行中的命令,转换成对应的 Linux 命令加以执行,并将执行的结果回显给用户。比如,用户输入“dir”,进程实际返回“ls”的内容。
1.2 软件包含前、后台两个进程,用户启动前台进程时,前台进程自行启动后台进程。前台进程提供界面,负责接收用户输入,对输入进行转换,并向后台进程发出实际要执行的指令,后台负责执行实际的指令,并将指令执行的结果返回给前台进程,由前台进程在终端显示。本文转载自http://www.biyezuopin.vip/onews.asp?id=15590
二、设计正文
1. 任务分析
1.1 前台进程应实现的功能如下
创建消息队列创建命名管道接受用户输入对输入进行装换
向后台发送实际要执行的指令等待后台返回结果
输出指令执行的的结果
若输入的指令是 exit 则向后台发送 exit 命令删除消息队列
删除命名管道
等待后台进程退出
//
// Created by yutao on 16-10-31.
//
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/msg.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "msg_operation.h"
#include <wait.h>
void main() {
int flag = 1;
int status = -1;
int msgid, filedsc;
char buffer[BUFFER_SIZE];
char *command = NULL;
struct msg_wrapper data;
char *stack[100];
int top, i;
pid_t fpid;
fpid = fork();
if (fpid == 0) {
execl("./back", "back", "", NULL);
perror("background");
exit(errno);
} else if (fpid < 0) {
perror("fork");
exit(errno);
}
//创建消息队列
msgid = msgget((key_t) MESSAGE_ID, 0666 | IPC_CREAT);
if (-1 == msgid) {
perror("create message queue");
exit(errno);
}
//创建FIFO并打开
if (0 != mkfifo(FIFO_NAME, 0777)) {
perror("fifo");
exit(errno);
}
filedsc = open(FIFO_NAME, O_RDONLY);
if(-1==filedsc){
perror("front open FIFO");
exit(errno);
}
while (flag) {
printf(">>");
msg_del(&data);
//读入标准输入
fgets(buffer, BUFFER_SIZE, stdin);
//将输入拆分为各个字符串
top = -1;
command = strtok(buffer, " \n");
while (command != NULL) {
stack[++top] = command;
command = strtok(NULL, " \n");
}
if (top < 0) {
continue;
}
command = stack[0];
//转化命令
if (0 == strcmp(command, "dir")) {
msg_cmd(&data, "ls");
} else if (0 == strcmp(command, "rename")) {
msg_cmd(&data, "mv");
} else if (0 == strcmp(command, "move")) {
msg_cmd(&data, "mv");
} else if (0 == strcmp(command, "del")) {
msg_cmd(&data, "rm");
} else if (0 == strcmp(command, "touch")) {
msg_cmd(&data, "touch");
} else if (0 == strcmp(command, "copy")) {
msg_cmd(&data, "cp");
} else if (0 == strcmp(command, "md")) {
msg_cmd(&data, "mkdir");
}else if (0 == strcmp(command, "cd")) {
if (top == 0) {
msg_cmd(&data, "pwd");
} else {
msg_cmd(&data, "cd");
}
} else if (0 == strcmp(command, "exit")) {
flag = 0;
msg_cmd(&data, "exit");
} else {
continue;
}
if (flag) {
//合成指令
for (i = 1; i <= top; i++) {
msg_add(&data, stack[i]);
}
msg_end(&data);
}
//发送消息
if (-1 == msgsnd(msgid, (void *) &data, BUFFER_SIZE, 0)) {
perror("send message");
exit(errno);
}
if (flag) {
//打开并阻塞读取FIFO数据
read(filedsc, buffer, BUFFER_SIZE);
printf("%s", buffer);
}
}
//删除消息队列
if (msgctl(msgid, IPC_RMID, 0) == -1) {
perror("delete msg");
exit(errno);
}
//关闭,删除FIFO文件
if(-1==close(filedsc)){
perror("front close FIFO");
exit(errno);
}
unlink(FIFO_NAME);
//等待后台进程退出
wait(&status);
//用于显示前后台退出的顺序
printf("foreground exited\n");
}