进程间通讯之管道

管道也是进程间通讯的常用方式,管道通讯分为有名管道和无名管道通讯,但无论哪种管道通讯都是半双工的通讯方式,即不同的进程完成不同的工作,读、写数据分别有不同的进程完成。负责写的进程关闭读端,负责读的进程关闭写端。有名管道与无名管道的区别在于有名管道会在磁盘上创建一个inode节点,不会创建block,会存在一个文件名。而无名管道不会存在文件名。所以,无名管道只能用于父子进程之间进行数据传输,而有名管道不受限制,可在任意两进程之间进行数据传输。

有名管道工作原理:
 通过命令mkfifo或函数mkfifo()来创建一个管道文件FIFO,通过对管道文件的操作从而实现对内存空间上的数据流进行传输。
实例:
A进程:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <fcntl.h>
int main()
{
 int fd = open("FIFO", O_WRONLY);//会阻塞运行
 if(fd < 0)
 {
  int n = mkfifo("FIFO", 0664);
  if(n == -1)
  {
   perror("FIFO");
   exit(0);
  }
  fd = open("FIFO", O_WRONLY);
  assert(fd != -1);
 }
 printf("open success\n");
 while(1)
 {
  printf("please input: ");
  char buff[128] = {0};
  fgets(buff, 128, stdin);
  if(strncmp(buff, "end", 3) == 0)
  {
   break;
  }
  write(fd, buff, strlen(buff) - 1);
 }
 close(fd);
}
B进程:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <fcntl.h>
int main()
{
 int fd = open("FIFO", O_RDONLY);
 if(fd < 0)
 {
  int n = mkfifo("FIFO", 0664);
  if(n == -1)
  {
   perror("FIFO");
   exit(0);
  }
  fd = open("FIFO", O_RDONLY);
  assert(fd != -1);
 }
 printf("open success\n");
 while(1)
 {
  char buff[128] = {0};
  int n = read(fd, buff, 127);// 会阻塞运行
  if(n == 0)
  {
   break;
  }
  printf("%s  %d\n",buff,strlen(buff));
 }
 close(fd);
}
注:进程A和进程B都会存在阻塞的现象。A进程阻塞是因为写入数据,没有进程来读取数据而进入阻塞。B进程阻塞是因为读取时没有进程写入数据而阻塞。

无名管道工作原理:
  无名管道并不会去创建管道文件,所以,无名管道只能应用于父子进程之间。应为父子进程之间对于fork之前打开的文件描述符是共享的。
  无名管道的操作:

int pipe(int fd[2]);用于创建并打开一个无名管道,并且使fd[0]指向管道读端,fd[1]指向管道写端。

  无名管道进行数据传输时,由于管道的半双工特性因此,父进程执行写操作是关闭读端,执行读操作时关闭写端。子进程也是同样的道理。

实例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
int main()
{
 int fds[2] = {0};
 if(pipe(fds) == -1)
 {
  printf("error...\n");
  exit(0);
 }
 if(fork() == 0)
 {
  close(fds[1]);
  while(1)
  {
   char buff[128] = {0};
   int n = read(fds[0], buff, 127);
   if(n == 0)
   {
    break;
   }
   printf("%s  %d",buff,strlen(buff));
  }
  close(fds[0]);
 }
 else
 {
  close(fds[0]);
  while(1)
  {
   printf("please input:");
   char buff[128] = {0};
   fgets(buff, 128, stdin);
   if(strncmp(buff, "end", 3) == 0)
   {
    break;
   }
   write(fds[1], buff, strlen(buff) - 1);
   sleep(1);
  }
  close(fds[1]);
 }
}
      无论是有名管道还是无名管道文件,都支持一般文件操作,如:open   read  write  close,而对于无名管道,pipe创建的就是文件描述符,所以不用执行open函数。

猜你喜欢

转载自blog.csdn.net/magic_world_wow/article/details/79826686