linux管道(pipe)

转载自:http://blog.chinaunix.net/uid-27034868-id-3394243.html


管道是一种两个进程间进行单向通信的机制。因为管道传递数据的单向性,管道又称为半双工管道。管道的这一特点决定了器使用的局限性。管道是Linux支持的最初Unix IPC形式之一,具有以下特点:


*** 数据只能由一个进程流向另一个进程(其中一个读管道,一个写管道);如果要进行双工通信,需要建 立两个管道。
*** 管道只能用于父子进程或者兄弟进程间通信。,也就是说管道只能用于具有亲缘关系的进程间通信。

   除了以上局限性,管道还有其他一些不足,如管道没有名字(匿名管道),管道的缓冲区大小是受限制的。管道所传输的是无格式的字节流。这就需要管道输入方和输出方事先约定好数据格式。虽然有那么多不足,但对于一些简单的进程间通信,管道还是完全可以胜任的。

   使用管道进行通信时,两端的进程向管道读写数据是通过创建管道时,系统设置的文件描述符进行的。从本质上说, 管道也是一种文件,但它又和一般的文件有所不同,可以克服使用文件进行通信的两个问题,这个文件只存在 内存中。
    通过管道通信的两个进程,一个进程向管道写数据,另外一个从中读数据。写入的数据每次都添加到管道缓冲区的末尾,读数据的时候都是从缓冲区的头部读出数据的。

      #include

       int pipe(int pipefd[2]);

(匿名)管道两端分别用描述符pipefd[0]pipefd[1]来描述。需要注意的是,管道两端的任务是固定的,一端只能用于读,有描述符pipefd[0]表示,称其为管道读端;另一端只能用于写,由描述符pipe[1]来表示,称其为管道写端。
该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信。在此不再作多介绍,下面看看有名管道吧。
    管道的一个不足之处就是没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(name pipe或FIFO)提出后,该限制得到了解决。FIFO不同与管道之处在与她提供一个路径名与之关联,以FIFO的文件形式存储在文件系统中。有名管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信了。值得注意的是FIFO(First In First Out)总是按照先进先出的原则工作,第一个被写入的数据首先从管道中读出。
     在Linux中我们经常使用管道重定向数据。比如:
   
   


下面介绍一下创建有名管道的系统调用,有两个, mknod和mkfifo





#include  

#include 

int mknod(const char *pathname, mode_t mode, dev_t dev);

int mkfifo( const char *pathname, mode_t mode );

函数mknod参数中pathname为创建有名管道的全路径名,mode为创建有名管道的模式,指明其存取权限;dev为设备值,该值取决于文件创建的种类,它只在创建设备文件是才会用到。这两个函数调用成功都返回0,否则返回-1.
读写有名管道:

#include 

ssize_t read (int fd , void * buf , size_t nbytes)

ssize_t write (int fd , void * buf , size_t nbytes)

接下来给大家演示一下通过有名管道通信的聊天程序。。。

    // 李四.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <pthread>

    #define FIFO_READ    "writefifo" //另外一个程序只要把本程序
    #define FIFO_WRITE    "readfifo" //拷贝一份然后调换这两个宏即可

    #define BUF_SIZE    1024
    int left = 0;
    void *read_buf()
    {
        int rfd = -1;
        char buf[BUF_SIZE] = { '\0' };
        int i;

        printf("等待对方……\n");
        while ((rfd = open(FIFO_READ, O_RDONLY)) == -1) {
            sleep(1);
        }
        while (left != 1) {
            //printf("i=%d ",i++);
            int len = read(rfd, buf, BUF_SIZE);
            if (len > 0) {
                buf[len] = '\0';
                
                if(strcmp(buf,"不理你了") == 0){
                    printf("\n对方已经走开!\n");
                    left = 1;
                    break;
                //    exit(0);
                }
                for(i = 0; i < strlen("我:"); i++)
                    printf("\b");

                printf("对方:%s\n", buf);
                printf("我:");
                fflush(stdout);
            }
        }
        
        close(rfd);
        return NULL;
    }

    void *write_to()
    {
        int wfd;
        char buf[BUF_SIZE];
        int len;

        umask(0);
        if (mkfifo(FIFO_WRITE, S_IFIFO | 0666)) {
            printf("Can't create FIFO %s because %s", FIFO_WRITE,
             strerror(errno));
            exit(1);
        }
        umask(0);
        wfd = open(FIFO_WRITE, O_WRONLY);
        if (wfd == -1) {
            printf("open FIFO %s error: %s", FIFO_WRITE, strerror(errno));
            exit(1);
        }
        while (left != 1) {
            printf("我: ");
            fgets(buf, BUF_SIZE, stdin);
            buf[strlen(buf) - 1] = '\0';
            if (strcmp(buf, "不理你了") == 0 || left == 1) {
                write(wfd, buf, strlen(buf));//通知对方
                close(wfd);
                unlink(FIFO_WRITE);
                exit(0);
            }
            write(wfd, buf, strlen(buf));
            fflush(stdin);
        }
    }
    int main(int argc, char *argv[])
    {
        pthread_t thIDr, thIDw;
        
        pthread_create(&thIDr, NULL,(void *)read_buf, NULL);
        pthread_create(&thIDw, NULL,(void *)write_to, NULL);
        pthread_join(thIDr, NULL);
        pthread_join(thIDw, NULL);

        return 0;
    }


学以置用,呵呵,效果如下:


pthread不是Linux下的默认的库,也就是在链接的时候,无法找到phread库中哥函数的入口地址,于是链接会失败。

在gcc编译的时候,要加 -lpthread参数即可解决。

不要忘了加上头文件#include<pthread.h>  (原文中作者没加,这里加了)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值