进程间通信---管道

管道

管道是⼀一种最基本的 IPC机制,由pipe函数创建。

#include<stdio.h>
int pipe(int fileds[2])

调用pipe函数时在内存中开辟一块缓冲区(就称为管道),用于通信,它有一个读端和一个写端,通过函数参数传给用户程序两个文件描述符,fileds[0]指向管道的读端,fileds[1]指向管道的写端。(方便记忆就可以理解为,标准输入0,标准输出1)看起来管道就像是一个打开的文件, 通过read(fileds[0]),和write(fileds[1])往里面写和读, 从上面的图我们可以看出,也就是在读写内核缓冲区。 pipe函数创建管道成功返回0,失败返回-1。

1.父进程创建管道
这里写图片描述
2.父进程fork出子进程
这里写图片描述
3.父进程关闭fd[0],子进程关闭fd[1]
这里写图片描述
代码:

 #include<stdio.h>
 #include<unistd.h>
 #include<errno.h>
 #include<string.h>
 int main()
 {
     int _pipe[2];
     int ret = pipe(_pipe);
     if(ret==-1)//创建管道失败
     {
         printf("creat pipe error!errno code is :%d\n",errno);//错误码
         return 1;//返回值
     }
     pid_t id = fork();
     if(id<0)//创建子进程失败
     {
         printf("fork error!");
         return 2;
     }
     else if(id==0)
     {
         //child
         close(_pipe[0]);//关闭读端
         int i = 0;
         char *_mesg = NULL;
         while(i<100)
         {
             _mesg = "I am child!";
             write(_pipe[1],_mesg,strlen(_mesg)+1);//xie
             sleep(1);
             i++;
         }
     }
     else
     {
         //father
         close(_pipe[1]);//关闭写端
         char _mesg_c[100];
         int j = 0;
         while(j<100)
         {
             memset(_mesg_c,'\0',sizeof(_mesg_c));
             read(_pipe[0],_mesg_c,sizeof(_mesg_c));
             printf("%s\n",_mesg_c);
             j++;
         }
     }
 }

运行结果:
这里写图片描述

管道的特点:
1.匿名管道支持单方向通信。

2.管道通信依赖于文件系统。
所以管道的生命周期是随进程。(进程一旦结束,管道也就随之而被释放)

3.匿名管道只能用于两个具有亲缘关系的两个进程。(例如父子进程)

4.匿名管道是按照字节流的方式来进行读写的。(没有格式要求)

5.管道自带同步机制。(读写的顺序一致)

匿名管道存在着如下两个缺点
1. 匿名管道只能用于连接具有共同祖先的进程。
2. 匿名管道是依附进程而临时存在的。

但是 命名管道可以在任意的文件之间通信。

命名管道(FIFO)

命名管道(NamedPipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。不同于匿名管道的是:命名管道可以在不相关的进程之间和不同计算机之间使用,服务器建立命名管道时给它指定一个名字,任何进程都可以通过该名字打开管道的另一端,根据给定的权限和服务器进程通信。而且,FIFO总是按照先进先出的原则工作,第一个被写入的数据首先从管道中读出。
创建命名管道的系统函数有两个:mknod和mkfifo
函数原型:

#include<sys/types.h>
#include<sys/stat.h>
int mknod(const char*path,mode_t mod,dev_t dev);
int mkfifo(const char*path,mode_t mode);

函数参数中的path为创建的命名管道的路径名,mod为创建命名管道的模式,指明其存取权限,dev为设备值,该值文件创建的种类,它只在创建设备文件时才会用到。这两个函数带哦用成功返回0,失败都返回-1.线面用mknod函数创建一个命名管道

umask(0);//重置管道的存取权限
if(mknod("/tmp/fifo",S_IFIFO|0666)==-1)
{
    perror("mknod error");
    exit(1);
}
//函数mkfifo的使用代码
umask(0);
if(mkfifo("/tmp/fifo",S_IFIFO|0666)==-1 )
{
    perror("mkfifo error");
    exit(1);
}
//"S_IFIFO|0666"致命创建一个管道的存取权限为0666

命名管道的使用和匿名管道基本相同,只是在使用命名管道之前首先要使用open函数打开,因为命名管道是存在于硬盘上的文件,而管道是存在于内存中的特殊文件。
需要注意,使用open的几点:
1. 调用open()打开命名管道可能会被阻塞,但是如果同时用读写方式(O_RDWR)打开,则一定不会造成阻塞。
2. 如果以制度方式(O_RDONLY)打开,则调用open()函数的进程将会被阻塞直到有写才能打开管道。
3. 同样,以写方式(O_WRONLY)打开也会阻塞直到有读方式打开管道。
命名管道可以实现进程间的通信:

//client.c 管道的写端
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main()
{
    umask(0);
    if(mkfifo("./mypipe",0666 | S_IFIFO)<0)
    {
        perror("mkfifo error");
        return 1;
    }
    int fd = open("./mypipe",O_RDONLY);
    if(fd<0)
    {
        printf("open file error!\n");
        return 2;
    }
    char buf[1024];
    while(1)
    {
        ssize_t ret = read(fd,buf,sizeof(buf)-1);
         if(ret>0)//error or end of file
             {
                 buf[ret] = 0;
                 printf("client say# %s\n",buf);
             }
         else if(ret==0)
         {
             printf("client quit !server begin quit!\n");
             break;
     }

   }
    close(fd);
    return 0;
}
//server.c 管道的读端
 #include<stdio.h>
 #include<sys/types.h>
 #include<sys/stat.h>
 #include<unistd.h>
 #include<fcntl.h>
 #include<string.h>
 int main()
 {
     int fd = open("./mypipe",O_WRONLY);
     if(fd<0)
     {
         printf("open file error!\n");
         return 2;
     }
     char buf[1024];
     while(1)
     {
         printf("please enter # ");
         fflush(stdout);
         ssize_t ret = read(0,buf,sizeof(buf)-1);
          if(ret>0)
              {
                  buf[ret-1] = 0;
                  write(fd,buf,strlen(buf));
              }

    }
     close(fd);
     return 0;
 }

运行结果:这里写图片描述

匿名管道和命名管道:

首先,FIFO是一种永久性的机构,它具有普通的UNIX系统文件名。在系统下可利用MKNOD命令建立永久的管道,除非刻意删除它,否则它将一直保持在系统中。

其次,正是由于有名管道以“文件名”来标识,所以只要事先约定某一特定文件名,那样所有知道该约定的服务进程,不论它们之间是否有亲属关系,都可以便利地利用管道进行通信。

命名管道文件被创建后,一些进程就可以不断地将信息写入命名管道文件里,而另一些进程也可以不断地从命名管道文件中读取信息。对命名管道文件的读写操作是可以同时进行的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值