操作系统实验四、五:匿名和命名管道通信

目录

一、实验内容

二、实验环境

三、相关知识

1.管道

2.Linux函数

(1)、匿名管道

(2)、命名管道

四、源代码

1、匿名管道通信

2、命名管道通信

五、执行结果

一、实验内容

 1、学习使用匿名管道在两个进程间建立通信。分别建立名为 Parent 的单文档应用程序和 Child 的单文档应用程序作为父子进程,由父进程创建一个匿名管道,实现父子进程向匿名管道写入和读取数据。

2、 学习使用命名管道在多进程间建立通信。建立父子进程,由父进程创建一个命名管道,由子进程向命名管道写入数据,由父进程从命名管道读取数据。

二、实验环境

Linux操作系统

三、相关知识

1.管道

管道(pipe)通信是一种共享文件模式,它基于文件系统,连接于两个通信进程之间,以先进先出的方式实现消息的单向传送。管道是一个特殊文件,在内核中通过文件描述符表示。

1、匿名管道:也叫无名管道。只能用于亲缘关系的进程线通信,如父子进程,兄弟进程。

2、有名管道:有名管道(FIFO),也叫命名管道、FIFO文件,它提供了一个路径名与之关联,以 FIFO 的文件形式存在于文件系统中,并且其打开方式与打开一个普通文件是一样的,这样即使与 FIFO 的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过 FIFO 相互通信,因此,通过 FIFO 不相关的进程也能交换数据。

2.Linux函数

(1)、匿名管道

①、匿名管道创建函数:pipe()

头文件:#include <unistd.h>

函数原型:int pipe(int pipefd[2]);

功能:创建一个匿名管道,用来进程间通信。

参数:int pipefd[2]   这个数组是一个传出参数。

      pipefd[0]: 对应的是管道的读端

      pipefd[1]:对应的是管道的写端

返回值:成功0;失败 -1

②、I/O函数:

close(int fd):关闭管道

readint fd , const void *buf , size_t length

write(int fd , const void *buf , size_t length);

其中参数fd是有效文件描述符,参数buf为指向缓冲区的指针,length为缓冲区的大小(以字节为单位)。函数read()实现从文件描述符fd所指定的文件中读取length个字节到buf所向的缓冲区中,返回值为实际读取的字节数。函数write实现把length个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数。

(2)、命名管道

(1)、主要用到的函数:

①、mkfifo()创建有名管道函数

函数原型及头文件:

#include <sys/types.h>

#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

参数: pathname,表示要创建的命名管道文件。若pathname以路径的方式给出,则将命名管道文件创建在pathname路径下。若pathname以文件名的方式给出,则将命名管道文件默认创建在当前路径下。

            mode,表示创建命名管道文件的默认权限。但实际上创建出来文件的权限值还会受到umask(文件默认掩码)的影响,实际创建出来文件的权限为:mode&(~umask)。umask的默认值一般为0002,当我们设置mode值为0666时实际创建出来文件的权限为0664。若想创建出来命名管道文件的权限值不受umask的影响,则需要在创建文件前使用umask函数将文件默认掩码设置为0。

umask(0); //将文件默认掩码设置为0

返回值:命名管道创建成功,返回0。

命名管道创建失败,返回-1。

      ②、open()、close()、write()、read()文件操作函数

open():

函数原型及头文件:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname,int flags)

功能描述:用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。

参数:pathname:被打开的文件名(可包括路径名如"dev/ttyS0")

flags:文件打开方式,有:

O_RDONLY:以只读方式打开文件

O_WRONLY:以只写方式打开文件

O_RDWR:以读写方式打开文件

O_CREAT:如果改文件不存在,就创建一个新的文件,并用第三个参数为其设置权限

close():

函数原型及头文件:

#include <unistd.h>

int close(int fd)

功能描述:用于关闭一个被打开的的文件。

参数:fd文件描述符

函数返回值:0成功,-1出错

read():

函数原型及头文件:

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

功能描述: 从文件读取数据。

参数:   fd: 将要读取数据的文件描述词。

 buf:指缓冲区,即读取的数据会被放到这个缓冲区中去。

 count: 表示调用一次read操作,应该读多少数量的字符。

返回值:返回所读取的字节数;0(读到EOF);-1(出错)。

write():

函数原型及头文件:

#include <unistd.h>

ssize_t write(int fd, void *buf, size_t count);

功能描述: 向文件写入数据。

返回值:写入文件的字节数(成功);-1(出错)。

四、源代码

1、匿名管道通信

#include <wait.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#define MAX_LINE 80
void main(){
    int fd[2];
    int ret=pipe(fd);//create a pipe,if failed return -1,else return 0
    if(ret==-1){
        perror("pipe");
        exit(-1);
    }
    else{
        pid_t id=fork();//create child process
        if(id==0){//child process
            close(fd[1]);//close the writen end
            sleep(3);//sleep to wait parent process to write
            char rbuf[MAX_LINE]={0};
            read(fd[0],rbuf,sizeof(rbuf)-1);
            printf("child process has read datas successfully\n");
            printf("read rbuf:%s\n",rbuf);
            close(fd[0]);//close the read end
            exit(1);
        }
        else if(id>0){//parent process
            close(fd[0]);//close the read end
            const char* wbuf="hello world";
            write(fd[1],wbuf,strlen(wbuf));
            printf("parent process has writen datas successfullly\n");
            close(fd[1]);
            printf("parent process has closed the writen end successfully\n");
            sleep(1);
        }
    }
}

2、命名管道通信

#include <wait.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#define BUFFERSIZE 80
void main(){
    umask(0);
    if(mkfifo("myfifo",0666)!=0){
    //creat fifo error
        perror("mkfifo");
        exit(1);
    }
    printf("create fifofile successfully!\n");
    pid_t id=fork();//create child progress
    if(id<0){
        printf("fork error\n");
    }
    else if(id==0){//child process
        int fd=open("myfifo",O_WRONLY);//open the file in write mode
        if(fd==-1){
            perror("fopen error");
            exit(1);
        }
        printf("write fifofile successfully!\n");
        const char* wbuf="hello world";
        write(fd,wbuf,strlen(wbuf));
        sleep(1);
        close(fd);
    }
    else if(id>0){//parent process){
        int fd=open("myfifo",O_RDONLY);//open the file int read mode
        char rbuf[BUFFERSIZE]={0};
        read(fd,rbuf,sizeof(rbuf)-1);
        printf("%s\n",rbuf);
        sleep(1);
        close(fd);
    }
}

五、执行结果

1、匿名管道

 2、命名管道

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
匿名管道和命名管道都是用于进间通信的方式,但它们之间有一些区别。 匿名管道: 匿名管道是一种向通信方式,只能用于子进程或者兄弟进之间的通信。在创建匿名管道时,操作系统会自动为其分配一个文件描述符,通过该文件描述符,进可以进行读写操作。 匿名管道的创建方式如下: ```C int pfd[2]; pipe(pfd); // 创建匿名管道 ``` 其中,pfd[0]是管道的读端,pfd[1]是管道的写端。 匿名管道的使用方式如下: ```C char buf[1024]; pid_t pid; int pfd[2]; pipe(pfd); pid = fork(); if (pid == 0) { // 子进程 close(pfd[1]); // 关闭写端 read(pfd[0], buf, sizeof(buf)); // 读取数据 printf("child process read from pipe: %s\n", buf); close(pfd[0]); // 关闭读端 } else if (pid > 0) { // close(pfd[0]); // 关闭读端 write(pfd[1], "hello world", strlen("hello world")); // 写入数据 close(pfd[1]); // 关闭写端 } else { perror("fork"); exit(1); } ``` 命名管道: 命名管道也是一种向通信方式,但可以用于任意进之间的通信。在创建命名管道时,需要指定一个路径名,并且需要手动创建该文件。操作系统会为其分配一个文件描述符,通过该文件描述符,进可以进行读写操作。 命名管道的创建方式如下: ```C int fd; mkfifo("/tmp/myfifo", 0666); // 创建命名管道 fd = open("/tmp/myfifo", O_RDONLY); // 打开命名管道 ``` 其中,"/tmp/myfifo"是文件路径名,0666是文件权限。 命名管道的使用方式如下: ```C char buf[1024]; int fd; fd = open("/tmp/myfifo", O_RDONLY); read(fd, buf, sizeof(buf)); // 读取数据 printf("read from fifo: %s\n", buf); close(fd); ``` 需要注意的是,命名管道的写入操作可以在任意进中进行,只要有权限打开该文件即可。如果多个进同时写入数据到同一个命名管道,可能会导致数据混乱。因此,使用命名管道时需要特别注意数据的同步问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值