zoukankan      html  css  js  c++  java
  • Linux进程间通信---管道和有名管道

    一、管道

        管道:管道是一种半双工的通信方式,数据只能单方向流动,而且只能在具有亲缘关系的进程间使用,因为管道

    传递数据的单向性,管道又称为半双工管道。进程的亲缘关系通常是指父子进程关系。

        管道的特点决定了其使用的局限性:

    • 数据只能由一个进程流向另一个进程(其中一个为写管道,另一个为读管道);如果要进行全双工通信,需要

    建立两个管道。

    • 管道只能用于父子进程或者兄弟进程间的通信,也就是说管道只能用于具有亲缘关系的进程间的通信,无亲缘

    关系的进程不能使用管道。

        管道的创建:

        Linux下创建管道可以通过函数pipe来完成。该函数如果调用成功则返回0,并且数组中将包含两个新的文件描述符;

    如果有错误发生,返回-1,该函数返回两个文件描述符:pipefd[0]和pipefd[1]。前者打开来读,后者打开来写。该函

    的原型为:

        #include <fcntl.h>

        #include <unistd.h>

        int pipe(int pipefd[2]);

    1. 下面是通过建立管道和创建父子进程间的通信:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <string.h>
    #include <sys/wait.h>
    
    int main()
    {
        int fd[2];
        pid_t pid;
        int ret;
        ret= pipe(fd);
        if(ret== -1)
        {
            perror("pipe.
    ");
            exit(1);
        }
        pid= fork();
        if(pid== -1)
        {
            perror("fork.
    ");
            exit(1);
        }
        else if(pid== 0)
        {
            char buff[256];
            close(fd[1]);
            read(fd[0],buff,256);
            printf("Form parent say: %s
    ",buff);
            close(fd[0]);
        }
        else
        {
            char *say= "Hello Linux.";
            close(fd[0]);
            write(fd[1],say,strlen(say)+ 1);
            close(fd[1]);
            int status;
            wait(&status);
        }
        return 0;
    }

                                          

        这是父子进程间利用管道进行通信的一个例子。

    2. 下面是通过建立两个管道来实现父子进程间全双工通信:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    
    int main()
    {
        char *parent_talk[]= {"Hello","Can you tell me what time is it?","Ok,I must go,Bye",NULL};
        char *child_talk[]= {"Hi","No problem","See you,Bye",NULL};
        int fd1[2],fd2[2];
        pid_t pid;
        int ret;
        ret= pipe(fd1);
        if(ret== -1)
        {
            perror("pipe1.
    ");
            exit(1);
        }
        ret= pipe(fd2);
        if(ret== -1)
        {
            perror("pipe2.
    ");
            exit(1);
        }
        pid= fork();
        if(pid== -1)
        {
            perror("fork.
    ");
            exit(1);
        }
        else if(pid== 0)
        {
            char buff[256];
            close(fd1[1]);
            close(fd2[0]);
            int i= 0;
            char *talk= child_talk[i];
            while(talk!= NULL)
            {
                read(fd1[0],buff,256);
                printf("Parent say: %s
    ",buff);
                write(fd2[1],talk,strlen(talk)+ 1);
                talk= child_talk[++i];
            }
            close(fd1[0]);
            close(fd2[1]);
        }
        else 
        {
            char buff[256];
            close(fd1[0]);
            close(fd2[1]);
            int i= 0;
            char *talk= parent_talk[i];
            while(talk!= NULL)
            {
                write(fd1[1],talk,strlen(talk)+ 1);
                read(fd2[0],buff,256);
                printf("Child say: %s
    ",buff);
                talk= parent_talk[++i];
            }
            close(fd1[1]);
            close(fd2[0]);
            int status;
            wait(&status);
        }
        return 0;
    }

                                 

        这是通过建立两个管道来实现父子进程间全双工通信的例子。

    二、有名管道      

        管道的有一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(FIFO)提出后,该

    限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存储于文件系统中。有名

    管道是一个设备文件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相

    互通信。需要注意的是,FIFO总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中读出。

        有名管道的创建:

        Linux下有两种方式创建有名管道。一是在Shell下交互地建立一个有名管道,二是在程序中使用系统函数建立有

    管道。Shell方式下可使用mkfifo或mknod命令。创建有名管道的系统函数有两个:mkfifo和mknod。两个函数均定义

    头文件sys/stat.h中,函数的原型为:

        #include <sys/types.h>
        #include <sys/stat.h>
        int mkfifo(const char *pathname,mode_t mode);

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

        函数mkfifo参数中pathname为创建的有名管道的全路径名;mode为创建的有名管道的模式,指明其存取权限;函

    数mknod参数中pathname为创建的有名管道的全路径名;mode为创建的有名管道的模式,指明其存取权限;dev为设

    备值,该值取决于文件创建的种类,它只在创建设备文件时才会用到。这两个函数调用成功都返回0,失败都返回-1。

        下面是使用有名管道建立一个客户端/服务器的例子:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #define BUFFER_SIZE 256
    const char *write_fifo= "write_fifo";
    const char *read_fifo= "read_fifo";
    
    int main()
    {
        if(access(write_fifo,F_OK))
        {
            int ret= mkfifo(write_fifo,0755);
            if(ret== -1)
            {
                perror("mkfifo");
                exit(1);
            }
        }
        int write_fd= open(write_fifo,O_WRONLY);
        if(write_fd== -1)
        {
            perror("open write_fifo.");
            exit(1);
        }
        int read_fd;
        while(1)
        {
            read_fd= open(read_fifo,O_RDONLY);
            if(read_fd== -1)
            {
                sleep(1);
                continue;
            }
            break;
        }
        char sendbuf[BUFFER_SIZE];
        char recvbuf[BUFFER_SIZE];
        while(1)
        {
            printf("Ser:");
            scanf("%s",sendbuf);
            if(strcmp(sendbuf,"quit")== 0)
            {
                unlink(write_fifo);
                break;
            }
            write(write_fd,sendbuf,strlen(sendbuf)+ 1);
            read(read_fd,recvbuf,BUFFER_SIZE);
            printf("Cli:%s
    ",recvbuf);
        }
        close(write_fd);
        close(read_fd);
        return 0;
    }
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <sys/wait.h>
    #define BUFFER_SIZE 256
    const char *write_fifo= "write_fifo";
    const char *read_fifo= "read_fifo";
    
    int main()
    {
        int read_fd= open(write_fifo,O_RDONLY);
        if(read_fd== -1)
        {
            perror("open write_fifio.");
            exit(1);
        }
        if(access(read_fifo,F_OK))
        {
            int ret= mkfifo(read_fifo,0755);
            if(ret== -1)
            {
                perror("mkfifo");
                exit(1);
            }
        }
        int write_fd= open(read_fifo,O_WRONLY);
        if(write_fd== -1)
        {
            perror("open read_fifo.");
            exit(1);
        }
        char sendbuf[BUFFER_SIZE];
        char recvbuf[BUFFER_SIZE];
        while(1)
        {
            read(read_fd,recvbuf,BUFFER_SIZE);
            printf("Ser:%s
    ",recvbuf);
            printf("Cli:");
            scanf("%s",sendbuf);
            if(strcmp(sendbuf,"quit")== 0)
            {
                unlink(read_fifo);
                break;
            }
            write(write_fd,sendbuf,strlen(sendbuf)+ 1);
        }
        close(write_fd);
        close(read_fd);
        return 0;
    }

                                                    

  • 相关阅读:
    [转]SVN服务器搭建和使用(二)
    [转]SVN服务器搭建和使用(一)
    BZOJ 2049 Sdoi2008 Cave 洞穴勘测
    BZOJ 1589 Usaco2008 Dec Trick or Treat on the Farm 采集糖果
    BZOJ 2796 POI2012 Fibonacci Representation
    BZOJ 2115 Wc2011 Xor
    BZOJ 3105 CQOI2013 新Nim游戏
    BZOJ 2460 Beijing2011 元素
    BZOJ 3687 简单题
    BZOJ 1068 SCOI2008 压缩
  • 原文地址:https://www.cnblogs.com/XNQC1314/p/9017531.html
Copyright © 2011-2022 走看看