匿名管道(pipe)和命名管道(mkfifo)

匿名管道(pipe)和命名管道(mkfifo)

进程间通信必须通过内核提供的通道。

1、匿名管道

匿名管道通过打开的文件描述符来标识的。——用于具有亲缘关系间进程之间的通信。

img

int pipe(int fds[2]);//返回值0表示成功,-1表示失败

fd[0]:读 fd[1]:写
写数据时要关闭读端
读数据时要关闭写端

2、命名管道

命名管道借助于文件系统实现,文件系统中的路径名是全局的,各进程都可以访问,因此可以用文件系统中的路径名来标识一个IPC通道。——用于具有非亲缘关系间进程之间的通信。

命名管道的打开规则:

如果当前打开操作是为读而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为写而打开该FIFO
O_NONBLOCK enable:立刻返回成功
如果当前打开操作是为写而打开FIFO时
O_NONBLOCK disable:阻塞直到有相应进程为读而打开该FIFO
O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

需要注意的是打开的文件描述符默认是阻塞的.

管道的创建

img

管道文件大小为0,没有亲缘关系的文件也能通过管道名,来取到该管道中的缓存。

//创建管道文件 int mkfifo(const char *name,mode_t mode)

//打开管道文件

int fd=open(name,O_RDONLY);读

int fd=open(name,O_WRONLY);写

3、匿名管道与命名管道的区别:

  • 匿名管道是由pipe函数创建 并打开的

  • 命名管道是由mkfifo函数创建 的 ,打开用open

    命名管道和匿名管道唯一的区别就是在创建的打开,一旦这些工作完成后,它们有相同的意义。

匿名管道实例1:

/*
*  父进程通过命令行的方式输入内容(argv[1])写入管道
*  子进程从管道中读取数据并输出到标准输出
*  
*   note: ./pipe hello world
*        仅能输出hello(argv[1]),word(argv[2])不能输出.
*/

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
   int pipefd[2];
   pid_t pid;
   char recv_buf[1024];
   int len;

   if(argc < 2)
   {
      perror("Usage error:");
      exit(1);
   }


   if(pipe(pipefd) < 0)
   {
       perror("pipe()");
       exit(1);
   }

   pid = fork();
   if(-1 == pid)
   {
       perror("fork()");
       exit(1);
   }

   if(0 == pid)
   {
      close(pipefd[1]);
      while((len = read(pipefd[0],recv_buf,10)) > 0 )
         write(1,recv_buf,len);

      puts("\n");
      close(pipefd[0]);

      exit(0);
   }
   else
   {
       close(pipefd[0]);
       write(pipefd[1],argv[1],strlen(argv[1]));
      
       close(pipefd[1]);
       wait(NULL);
       exit(0);
   }

  exit(0);
}

匿名管道实例2:

/*
*  父进程通过命令行的方式输入文件路径名(argv[1])写入管道
*  子进程从管道中读取数据并输出到标准输出
*
*  eg. ./pipe pipe.c
*      ./pipe ./pipe.c
*      ./pipe ./home/user/IPC/pipe.c
*/


#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv)
{
   int pipefd[2];
   pid_t pid;
   char recv_buf[1024];
   char send_buf[1024];
   int recv_len;
   size_t send_len;
   FILE *fp = NULL;

   if(argc < 2)
   {
      perror("Usage error:");
      exit(1);
   }


   if(pipe(pipefd) < 0)
   {
       perror("pipe()");
       exit(1);
   }

   pid = fork();
   if(-1 == pid)
   {
       perror("fork()");
       exit(1);
   }

   if(0 == pid)
   {
      close(pipefd[1]);
      while((recv_len = read(pipefd[0],recv_buf,10)) > 0 )
         write(1,recv_buf,recv_len);

      puts("\n");
      close(pipefd[0]);

      exit(0);
   }
   else
   {
       close(pipefd[0]);
       fp = fopen(argv[1],"r");
       if(NULL == fp)
       {
           perror("fopen()");
           exit(1);
       }
       
       while((send_len = fread(send_buf,1,10,fp)) > 0)
            write(pipefd[1],send_buf,send_len);
      
       fclose(fp);

       close(pipefd[1]);
       wait(NULL);
       exit(0);
   }

  exit(0);
}

命名管道实例:

公共头文件public.h:

#ifndef PUBLIC_H__
#define PUBLIC_H__

#define MKFIFO_NAME "tp"   //定义管道文件名

#endif

写端代码(write.c):

#include
#include
#include
#include
#include
#include
#include
#include
#include

#include "public.h"

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(int argc, char *argv[])
{
    mkfifo(MKFIFO_NAME, 0644);
    int infd = open("Makefile", O_RDONLY);
    if (infd == -1)
        ERR_EXIT("open error");

    int outfd;
    outfd = open(MKFIFO_NAME, O_WRONLY);
    if (outfd == -1)
        ERR_EXIT("open error");

    char buf[1024];
    int n;
    while ((n = read(infd, buf, 1024)) > 0)
        write(outfd, buf, n);

    close(infd);
    close(outfd);

    return 0;
}

读端代码(read.c):

#include
#include
#include
#include
#include
#include
#include
#include
#include

#include "public.h"

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

int main(int argc, char *argv[])
{

    int outfd = open("Makefile2", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (outfd == -1)
        ERR_EXIT("open error");

    int infd;
    infd = open(MKFIFO_NAME, O_RDONLY);
    if (infd == -1)
        ERR_EXIT("open error");

    char buf[1024];
    int n;
    while ((n = read(infd, buf, 1024)) > 0)
        write(outfd, buf, n);

    close(infd);
    close(outfd);
    unlink(MKFIFO_NAME); // delete a name and possibly the file it refers to
    return 0;
}

PS:部分内容来源于其他博客,侵权删。

你可能感兴趣的:(linux-IPC,linux,ipc)