linux 管道通信

进程通信

进程是系统分配资源的最小单位, 不同进程之间是相互隔离的, Linux常用于进程通信的几种方式有

  1. 匿名管道及有名管道 : 匿名管道用于具有亲缘关系的进程通信, 有名管道则可用于一般进程之间.
  2. 信号 : 软件层对中断机制的一种模拟.
  3. 消息队列
  4. 共享内存 : 不同进程享同一块内存区域, 不同进程可以实时查看对方对共享内存的更新. 需要借助同步机制, 如互斥锁, 信号量.
  5. 信号量 : 主要用于不同进程以及同一进程不同线程的同步和互斥.
  6. 套接字 : 广泛用于网络间进程通信.

无名管道

管道是是基于文件描述符的通信方式, 无名管道只能用于具有亲缘关系之间的进程通信.  建立一个管道时 它会创建两个文件描述符, fd[0] 和 fd[1] , 其中 fd[0] 用于读取数据,  fd[1] 用于写入数据, 请看下图 :

如果父进程需要向子进程发送数据通信,  那么可以在父进程上创建一个管道,  关闭父进程的fd[0]和子进程的fd[1],  子进程向父进程发送数据就与之相反.

下面演示了父进程向管道写入数据, 子进程从中读取.  sleep()函数确保父进程已经关闭了相应的文件描述符.

#include<stdio.h>
#include<sys/types.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>

int main(void){

    pid_t pid;
    int pipe_fd[2];
    char buf[1024];
    const char data[] = "管道测试";
    int real_read, real_write;

    memset(buf, 0, sizeof(buf));
    /* 创建管道 */
    if(pipe(pipe_fd) < 0){
        perror("pipe");
        exit(1);
    }

    if((pid = fork()) < 0){
        perror("fork");
        exit(1);
    }else if(pid == 0){
        /* 子进程关闭写描述符, 等待1秒让父进程关闭读描述符*/
        close(pipe_fd[1]);
        sleep(2);
        if((real_read = read(pipe_fd[0], buf, 1024)) > 0){
            printf("读取管道内容 : %s\n", buf);
        }
        close(pipe_fd[0]);
        exit(0);
    }else{
        /* 父进程关闭读描述符, 等待1秒让子进程关闭写描述符 */
        close(pipe_fd[0]);
        sleep(1);
        if((real_write = write(pipe_fd[1], data, strlen(data))) > 0){
            printf("写入管道内容 : %s\n", data);
        }
        close(pipe_fd[1]);
        /* 收集子进程退出信息 */
        waitpid(pid, NULL, 0);
        exit(0);
    }
}

管道读写需要注意几点

  • 向管道写入数据时, 管道读端必须存在, 否则写进程将收到内核传来SIGPIPE信号.
  • 向管道写入数据, 不保证原子性, 如果读进程不读取管道缓冲区中的数据, 那么写进程会一直阻塞.
  • 父子进程运行是, 并不能保证先后顺序, 这里简单用sleep()解决.

标准流管道

相当系统调用,  用于创建连接到另一个进程之间的管道,  这里的进程是指可进行一定操作的可执行文件, 标准流管道把一系列创建过程合并到popen() 中了.

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<fcntl.h>

/*  标准管道流操作 */
int main(void){
     FILE *fp;
     char *cmd = "ps -ef";
     char buf[1024];

     /* r 文件指针连接到command的标准输出*/
     if((fp = popen(cmd, "r")) == NULL){
          printf("popen error");
          exit(1);
     }
     while((fgets(buf, 1024, fp)) != NULL){
         printf("%s\n", buf);
     }
     pclose(fp);
     exit(0);
}

有名管道

Linux中专门设立了一个专门的特殊文件系统--管道文件,以FIFO的文件形式存在于文件系统中,这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交换数据.但在磁盘上只是一个节点,而文件的数据则只存在于内存缓冲页面中,与普通管道一样.

管道文件的读写可能有阻塞问题

对于读进程

  1. 如果管道是阻塞打开, 且当前FIFO没有数据, 则读进程一直阻塞.
  2. 如果非阻塞打开, 立即执行读操作.

对于写进程

  1. 如果管道是阻塞打开, 则一直阻塞到可以写入.
  2. 如果非阻塞打开而不能全部写入, 则写入部分或者写入失败.

下面包含两个程序, 一个用于读取管道, 并在该程序中创建管道, 另一个用于写管道.  首先要调用读程序.

读程序

#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include<limits.h>

/* 由读管道创建 */
#define MYFIFO    "/tmp/myfifo"

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

    int fd;
    char buf[PIPE_BUF];
    int nread;

    /* 如果管道不存在则创建 */
    if(access(MYFIFO, F_OK) == -1){
        /* 0是管道文件, 666是权限 */
        if((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST)){
            perror("create fifo");
            exit(1);
        }
    }

    /* 只读阻塞方式打开管道 */
    fd = open(MYFIFO, O_RDONLY);
    if(fd == -1){
        perror("open");
        exit(1);
    }

    /* 读取字符串 */
    while(1){
        memset(buf, 0, sizeof(buf));
        if((nread = read(fd, buf, PIPE_BUF)) > 0){
            printf("read %s\n", buf);
        }
    }

    close(fd);
    exit(0);
}

写程序

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<errno.h>
#include<fcntl.h>
#include<stdlib.h>
#include<limits.h>

/* 由读管道创建 */
#define MYFIFO    "/tmp/myfifo"

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

    int fd;
    char buf[PIPE_BUF];
    int nwrite;

    if(argc <= 1){
        printf("Usage: ./fifo_write <strring>");
        exit(1);
    }
    sscanf(argv[1], "%s", buf);

    /* 只写阻塞方式打开管道 */
    fd = open(MYFIFO, O_WRONLY);
    if(fd == -1){
        perror("open");
        exit(1);
    }

    /* 写入字符串 */
    if((nwrite = write(fd, buf, PIPE_BUF)) > 0){
        printf("write : %s\n", buf);
    }
    close(fd);
    exit(0);
}

编译运行

读程序
$ gcc fifo_read.c -o fifo_read
$ ./fifo_read
read 写入1
read 写入2
read 写入3

写程序
$ gcc fifo_write.c -o fifo_write
$ ./fifo_write
$ ./fifo_write 写入1
write : 写入1
$ ./fifo_write 写入2
write : 写入2
$ ./fifo_write 写入3
write : 写入3
时间: 2024-10-10 16:44:20

linux 管道通信的相关文章

Linux进程通信——管道

进程间通信(IPC:Inner Proceeding Communication) 进程是操作系统实现程序独占系统运行的假象的方法,是对处理器.主存.I/O设备的抽象表示.每个进程都是一个独立的资源管理单元,每个进程所看到的是自己独占使用系统的假象,因此各个进程之间是不能够直接的访问对方进程的资源的,不同的进程之间进行信息交互需要借助操作系统提供的特殊的进程通信机制. 进程之间的通信,从物理上分,可以分为同主机的进程之间的通信和不同主机间的进程之间的通信.从通信内容方式上分,可以分为数据交互.同

Linux学习记录--命名管道通信

命名管道通信 什么是命名管道 一个主要的限制是,它是匿名管道的应用还没有名字,因此,只有它可以用于进程间通信的方式与亲缘关系.在命名管道(named pipe或FIFO)提出后,该限制得到了克服.FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中. 这样,即使与FIFO的创建进程不存在亲缘关系的进程,仅仅要可以訪问该路径,就行彼此通过FIFO相互通信 有名管道创建 int mkfifo(const char * pathname, mode_t mode)

Linux进程通信----匿名管道

Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组 表示的文件描述字.这个数组有两个文件描述字,第一个是用 于读数据的文件描述符第二个是用于写数据的文件描述符. 不能将用于写的文件描述符进行读操作或者进行读的文件描述 符进写操作,这样都会导致错误. 关于匿名管道的几点说明: 1.匿名管道是半双工的,即一个进程只能读,一个进程只能写    要实现全双工,需要两个匿名管道. 2.只能在父子进程或者兄弟进程进行通信. 3.在读的时候关闭写文件描

linux进程通信之命名管道

前一节学习了无名管道,这节学习命名管道. 二命名管道 无名管道只能用来在父子进程或兄弟进程之间进行通信,这就给没有亲缘关系的进程之间数据的交换带来了麻烦,解决这个问题就是本节要学习的另一种管道通信:命名管道. 命名管道也被称为FIFO文件,FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中.这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIF

Linux笔记--Linux进程通信

Linux进程间通信 文章来源: http://www.cnblogs.com/linshui91/archive/2010/09/29/1838770.html 一.进程间通信概述进程通信有如下一些目的:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.C.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).D.

管道通信,王明学learn

管道通信 一.通讯目的 1.数据传输 一个进程需要将数据发送给另一个进程. 2.资源共享 多个进程之间共享同样的资源. 3.通知事件 一个进程需要向另一个/组进程发送消息,通知它们发生了某事件. 4.进程控制 有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变. 二.通讯发展 Linux进程间通信(IPC:interprocesscommunication)由以下几部分发展而来: 1.UNIX进程间通信 2.基于Sy

浅析linux进程通信的方式

求职笔试中,考察进程通信方式是一个老生长谈的问题,每次都让我答得一头雾水,于是我总结了一下 这些必须了解的知识点. 实现linux进程通信的方式有6种: --内存共享 --信号(Singal) --管道(Pipe) --消息队列(Message) --信号量(Semaphore) --socket 消息队列通信 请关注:http://blog.csdn.net/ljianhui/article/details/10287879 内存共享通信 请关注:http://blog.csdn.net/lj

linux 管道--转

linux 管道 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别. 有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建. Linux管道的实现机制 在Linux中,管道是一种使用非常频繁的通信机制.从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为: ·      限制管道

linux管道详解

原文链接:http://blog.csdn.net/qq_38646470/article/details/79564392 符号表示 | 和管道特别形象. 作用: 管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别. 有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建. 实现机制 在Linux中,管道是一种使用非常频繁的通信机制.从