进程通信(1) —– 无名管道和有名管道

  • Post author:
  • Post category:其他





一、实验目的

1.了解操作系统中的无名管道和有名管道

2.掌握进程通信中的管道编程模型



二、实验内容

管道是一种进程间通信的方式,在linux中分为有名管道和无名管道。有名管道就是把一个进程的输出写到一个文件中,再把此文件作为另一个进程的输入,普通管道只能用于父子进程,而有名管道能用于不相关的进程间。本次实验的内容需要编写一个普通管道程序和命名管道程序,并测试。



三、实验要求

实验需要提前准备一台PC机,并在PC机上搭建Linux Ubuntu环境。



四、实验步骤及操作

1.打开Linux系统,新建一个终端

2.新建文件

3.编写代码

4.编译运行



五、程序源码



1. 普通管道 piperw.c

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

#define BUFSZ PIPE_BUF

void err_quit(char *msg);

int main(int argc, char *argv[])
{
    int fd[2]; //文件描述符fd[0]表示读取管道,fd[1]表示写入管道
    int fdin; /* 输入文件描述符 */
    char buf[BUFSZ];//buf为缓冲区
    int pid, len;

    /* Create the pipe */
    if((pipe(fd)) < 0)
        err_quit("pipe");
    
    /* 分叉并关闭适当的描述符 */
    if((pid = fork()) < 0)
        err_quit("fork");
    if (pid == 0) {
        close(fd[1]);//关闭子进程的写数据
		//read()函数调用成功会返回读取到的字节数
        while((len = read(fd[0], buf, BUFSZ)) > 0)
			//STDOUT_FILENO表示将buf中的内容写到标准输出
            write(STDOUT_FILENO, buf, len);//STDIN_FILENO表示标准输出
        close(fd[0]);
    } else {
        /* Parent是writer,关闭读描述符 */
        close(fd[0]);
		//open函数打开文件成功
        if((fdin = open(argv[1], O_RDONLY)) < 0) {
            perror("open");
            /* 发送一些东西,因为我们无法打开输入 */
            write(fd[1], "123\n", 4);
    	} else {
        //管道里的数据必须被读走
        while((len = read(fdin, buf, BUFSZ)) > 0)
        	write(fd[1], buf, len);
        	close(fdin);
    	}
   		/* 关闭写描述符 */
   		close(fd[1]);
    }
    //waitpid会使目前进程暂停,直到有信号来或者子进程结束
    waitpid(pid, NULL, 0);
    
    

    exit(EXIT_SUCCESS);
}
    
void err_quit(char *msg)
{
    perror(msg);
    exit(EXIT_FAILURE);
}

在这里插入图片描述



2. 无名管道 wrfifo.c

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <time.h>

int main(int argc, char *argv[])
{
    int fd;			/* FIFO文件描述符 */
  	int len;			/* 写入FIFO的字节 */
    char buf[PIPE_BUF];	/* 确保原子写入 */
    time_t tp;			/* For time call */

    /* Identify myself */
    printf("I am %d\n", getpid());

    /* Open the FIFO write-only */
    if((fd = open(argv[1], O_WRONLY)) < 0) {
       perror("open");
       exit(EXIT_FAILURE);
    }

    /* Generate some data to write */
    while(1) {
        /* 获取当地时间 */
        time(&tp);
        /* 创建要写入的字符串 */
        len = sprintf(buf, "wrfifo %d sends %s", getpid(), ctime(&tp));
        /* 使用(len + 1),因为sprintf不计算结束的null */
        if((write(fd, buf, len + 1)) < 0) {
            perror("write");
            close(fd);
            exit(EXIT_FAILURE);
        }
        printf("%s",buf); 
        sleep(3);
    }

    close(fd);
    exit(EXIT_SUCCESS);
}

在这里插入图片描述



3. 有名管道 rdfifo.c

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>

void myfunc1(int sign_no)
{
	if(sign_no==SIGINT){
		printf("\nExit pipe!\n");
	}   
		
	else if(sign_no==SIGQUIT)
		printf("I have get SIGQUIT\n");  
}

int main(int argc, char *argv[])
{
	printf("I am %d\n", getpid());
    int fd;	/* Descriptor for FIFO */
    int len; /* Bytes read from FIFO */
    char buf[PIPE_BUF];
    char buf1[50]="Hello,Bit-Dong!";

	//在当前目录下创建一个有名管道
	unlink("test_rdfifo");
    if((mkfifo("test_rdfifo",0777)) < 0) {
        perror("mkfifo");
        exit(EXIT_FAILURE);
    }

    /* Open the FIFO read-write */
    if((fd = open("test_rdfifo", O_RDWR)) < 0) {
        perror("open");
        exit(EXIT_FAILURE);
    }
    
    if((write(fd,buf1,50))<0){
           perror("write");
   }
    /* 读取并显示FIFO的输出直到EOF */
    	len = read(fd, buf, PIPE_BUF - 1); 
        printf("rdfifo read: %s\n", buf);
    	signal(SIGINT, myfunc1);
   		sleep(10);   
    

    close(fd);

    exit(EXIT_SUCCESS);
}


在这里插入图片描述



版权声明:本文为Dustinthewine原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。