linux 管道通信

来源:互联网 发布:淘宝客分销系统源码 编辑:程序博客网 时间:2024/06/04 17:51

        首先说明linux进程之间通信的主要方式。大型程序大多会涉及到某种形式的进程间通信,一个较大型的应用程序设计成可以相互通信的“碎片”,从而就把一个任务分到多个进程中去。进程间通信的方法有三种方式:

       1, 管道(pipe)      

       2,System v IPC 机制 ,包括消息队列,信号量,共享内存

       3,套接字(socket)     

         管道机制在UNIX开发的早期就已经提供了,它在本机上的两个进程间的数据传递表现的相当出色;套接字是在BSD(Berkeley Software Development)中出现的,现在的应用也相当的广泛;而System V IPC机制Unix System V 版本中出现的。

         首先讲管道机制,会在以后把其他的通信机制都讲到。

        管道分为pipe(无名管道)和FIFO(命名管道),它们都是通过内核缓冲区按先进先出的方式数据传输,管道一端顺序地写入数据,另一端顺序地读入数据读写的位置都是自动增加,数据只读一次,之后就被释放。
                                                                              1  ,PIPE无名管道
       调用格式为int pipe(int filedes[2]);,文件描述符filedes[0]用来读数据,filedes[1]用来写数据。如果要求程序的可移植性好,就按照习惯的用法来编程。调用成功时,返回值为0;错误时,返回-1,并设置错误代码errno:
       管道在用户程序看起来就像一个打开的文件,通过read(filedes[0],void *_buf,size_t _nypes);或者write
(filedes[1],void *_buf,size_t _nypes)
向这个文件读写数据其实是在读写内核缓冲区。

      下面给出实例:

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
       int pipedes[2];//pipe输入输出文件描述符
       char s[13]="hello world!";
       int pid;
       if(pipe(pipedes)==-1)//创建管道失败
       {
             perror("pipe error!");
             exit(EXIT_FAILURE);
       }
       if(pid=fork()<0)//创建子进程失败
       {
             perror("fork is error!\n");
             return -1;
       }
       else if(pid==0)//在子进程中
       {
             printf("now,write data to pipe\n");
             if(write(pipedes[1],s,13)==-1)
             {
                     perror("write error!");
                     exit(EXIT_FAILURE);
             }
             else
             {
                    printf("the written data is :%s\n",s);
                    exit(EXIT_SUCCESS);
             }
       }
       else if(pid  > 0)//在父进程中
       {
            sleep(4);//保证子进程写操作完成
            printf("now read data from pipe!\n");
            if(read(pipedes[0],s,13)==-1)
            {
                    perror("read error!");
                    exit(EXIT_FAILURE);   
            }
            printf("the data is %s\n",s);
       }
         
       return 0;

}     

达到预期效果。    

 2,有名管道

      无名管道时临时的,在完成通信后就自动消失,且只能在具有亲元关系的进程间实现通信。有名管道他是一个存在的特殊文件,可以在不同的进程间进行通信。用户可以使用shell来创建有名管道,也可以使用mkfifo函数来创建有名管道,可以使用read和write进行读写操作。

下面直接给出操作实例:

fifo_read.c

/*
 * 管道通信:有名管道
 * 无名管道只能用于具有亲缘关系的进程之间,而有名管道可以在互不相关的两个进程间
 * 实现彼此通信。要注意,FIFO严格按照先进先出的规则,对管道及FIFO的读总是从开始
 * 处返回数据,对它们的写则把数据添加到末尾,不支持lseek等文件定位操作。
 *
 * 有名管道的创建使用mkfifo()。创建成功后就可以使用open、read、write这些函数了。
 * 读管道部分
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/*在这里设置打开管道文件的mode为只读形式*/
#define FIFOMODE (O_CREAT | O_RDWR | O_NONBLOCK)
#define OPENMODE (O_RDONLY | O_NONBLOCK)
#define FIFO_SERVER "myfifo"
int main(void)
{
        char buf[100];
        int fd;
        int readnum;
       /*创建有名管道,设置为可读写,无阻塞,如果不存在则按照指定权限创建*/
        if ((mkfifo(FIFO_SERVER, FIFOMODE) < 0) && (errno != EEXIST)) {
                printf("cannot create fifoserver\n");
                exit(1);
        }
        printf("Preparing for reading bytes... ...\n");
        /*打开有名管道,并设置非阻塞标志*/
        if ((fd = open(FIFO_SERVER, OPENMODE)) < 0) {
                perror("open");
                exit(1);
        }
        while (1) {
                /*初始化缓冲区*/
                bzero(buf, sizeof(buf));
                /*读取管道数据*/
                if ((readnum = read(fd, buf, sizeof(buf))) < 0) {
                        if (errno == EAGAIN) {
                                printf("no data yet\n");
                        }
                }
                /*如果读到数据则打印出来,如果没有数据,则忽略*/
                if (readnum != 0) {
                        buf[readnum] = '\0';
                        printf("read %s from FIFO_SERVER\n", buf);
                }
                sleep(1);
        }
        return 0;
}

 

fifo_write.c

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

/*特别注意写管道时,设置打开管道文件的格式必须为可写*/
#define FIFO_SERVER "myfifo"
#define OPENMODE (O_WRONLY | O_NONBLOCK)

int main(int argc, char **argv)
{
        int fd;
        int nwrite;

        /*打开管道文件,可写非阻塞*/
        if ((fd = open(FIFO_SERVER, OPENMODE)) < 0) {
                perror("open");
                exit(1);
        }

        /*如果没有在命令行中写入参数,那么要重新运行程序*/
        if (argc == 1) {
                printf("Please send something\n");
                exit(1);
        }

        /*向管道文件中写入数据,在这里要用strlen,如果用sizeof,则只是4个字节的指针长度*/
        if ((nwrite = write(fd, argv[1], strlen(argv[1]))) < 0) {
                if (errno == EAGAIN) {
                        printf("The FIFO has not been read yet.Please try later\n");
                }
        }
        else {
                printf("write %s to FIFO\n", argv[1]);
        }

        return 0;
}


原创粉丝点击