Linux進程間通訊---管道和有名管道

1、管道數組

    管道:管道是一種半雙工的通訊方式,數據只能單方向流動,並且只能在具備親緣關係的進程間使用,由於管道服務器

傳遞數據的單向性,管道又稱爲半雙工管道。進程的親緣關係一般是指父子進程關係。函數

    管道的特色決定了其使用的侷限性:ui

  • 數據只能由一個進程流向另外一個進程(其中一個爲寫管道,另外一個爲讀管道);若是要進行全雙工通訊,須要

創建兩個管道。spa

  • 管道只能用於父子進程或者兄弟進程間的通訊,也就是說管道只能用於具備親緣關係的進程間的通訊,無親緣

關係的進程不能使用管道。code

    管道的建立:orm

    Linux下建立管道能夠經過函數pipe來完成。該函數若是調用成功則返回0,而且數組中將包含兩個新的文件描述符;blog

若是有錯誤發生,返回-1,該函數返回兩個文件描述符:pipefd[0]和pipefd[1]。前者打開來讀,後者打開來寫。該函進程

的原型爲:ip

    #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.\n");
        exit(1);
    }
    pid= fork();
    if(pid== -1)
    {
        perror("fork.\n");
        exit(1);
    }
    else if(pid== 0)
    {
        char buff[256];
        close(fd[1]);
        read(fd[0],buff,256);
        printf("Form parent say: %s\n",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.\n");
        exit(1);
    }
    ret= pipe(fd2);
    if(ret== -1)
    {
        perror("pipe2.\n");
        exit(1);
    }
    pid= fork();
    if(pid== -1)
    {
        perror("fork.\n");
        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\n",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\n",buff);
            talk= parent_talk[++i];
        }
        close(fd1[1]);
        close(fd2[0]);
        int status;
        wait(&status);
    }
    return 0;
}

 

                             

    這是經過創建兩個管道來實現父子進程間全雙工通訊的例子。

2、有名管道      

    管道的有一個不足之處是沒有名字,所以,只能用於具備親緣關係的進程間通訊,在有名管道(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\n",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\n",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;
}

 

                                                

相關文章
相關標籤/搜索