管道

什么是管道?

在Linux中,管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:限制管道的大小。实际上,管道是一个固定大小的缓冲区。

代码
#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++;
         }
     }
 }
管道特点及4种情况
  1. 单向通信。
  2. 只有在具有亲缘关系的进程间通信。
  3. 具有同步机制。
  4. 它是一种面向字节流的通信服务。
  5. 生命周期随进程

使用管道需要注意以下四种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志)

  1. 如果所有指向管道写端的文件描述符都关闭了,(管道写端的引用计数为0),而仍然有进程从管道的读端读取数据,那么管道中剩余的数据都被读取之后,再次read将会返回0,就像读到文件结尾一样。也就是说,写端不会写,读端读完之后就会再等着写端去写,但是写端关闭了啊,不会写了,所以就出现上面说的情况。这就体现出了管道的同步机制。
  2. 如果有指向管道写端的文件描述符没有关闭,(管道写端的引用计数大于0)而持有管道写端的进程也没有向管道中写数据,这时有进程管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。通俗讲就是,读端读数据,一直读,但是写端不写了,而且写端并没有关闭,所以这时读端就会一直等着写端去写。这就造成了阻塞式等待。
  3. 如果所有指向管道读端的文件描述符都关闭了(管道读端的引用计数为0),这时有进程向管道的写端写数据,那么该进程会收到SIGPIPE,通常会导致进程异常终止。所以进程就会异常退出了。
  4. 如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0)而持有管道读端的进程也没有从管道中读取数据,这时有进程向管道写端写数据,那么在管道写满时再写将会阻塞,直到管道中有了空位置才写入并返回,也就是管道的同步机制。
命名管道

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

命名管道的使用和匿名管道基本相同,只是在使用命名管道之前首先要使用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;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值