linux_c開發(5-2)進程間通訊_管道通訊

管道通信

什麼是管道?
管道是單向的、先進先出的,他把一個進程的輸出和另一個進程的輸入連接在一起。一個進程(寫進程)在管道的尾部寫入數據,另一個進程(讀進程)從管道的頭部讀出數據。
管道創建
管道包括無名管道和有名管道兩種,前者用於父進程和子進程間的通訊,後者可用於同一系統中的任意兩個進程間的通訊。
無名管道由pipe()函數創建:
int pipe(int filedis[2]);
當一個管道建立時,他會創建兩個文件描述符:
filedis[0]用於讀管道,filedis[1]用於寫管道。
管道關閉
關閉管道只需要將這兩個文件描述符關閉即可,可以使用普通的close函數逐個關閉。
eg:

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

int main(void)
{
    int pipe_fd[2];
    if(pipe(pipe_fd)<0)
    {
        printf("pipe creat error\n");
        return -1;
    }
    else
        printf("pipe creat success\n!");
    close(pipe_fd[0]);
    close(pipe_fd[1]);
}

管道讀寫
管道用於不同進程見得通信。通常先創建一個管道,再通過fork函數創建一個子進程,該子進程會繼承父進程所創建的管道。
這裏寫圖片描述
注意事項
必須在系統調用fork()前調用pipe()否則子進程將不會繼承文件描述符。
例: pipe_rw.c

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

int main(void)
{
    int pipe_fd[2];
    pid_ pid;
    char buf_r[100];
    char* p_wbuf;
    int r_num;
    memset(buf_r,0,sizeof(buf_r));
/*創建管道*/
    if(pipe(pipe_fd)<0)
    {
        printf("pipe creat error\n");
        return -1;
    }
/*創建子進程*/
    if((pid=fork())==0)
    {
        printf("\n");
        close(pipe_fd[1]);
        sleep(2);/*讓子進程停下里讓父進程往管道里寫東西*/
        if ((r_num=read(pipe_fd[0],buf_r,100))>0)
            {
            printf("%d number read from the pipe is %s\n",r_num,buf_r)
            }
        close(pipe_fd[0]);
        exit(0);
    }   
    else if(pid>0)
    {
        close(pipe_fd[0];
        if(write(pipe_fd[1],"hello",5)!=-1)
            printf("parent write hello!\n");
        if(write(pipe_fd[1],"pipe",5)!=-1)
            printf("parent write pipe!\n");
        close (pipe_fd[1]);
        sleep(3);
        waitpid(pid,NULL,0);//等待子進程結束
        exit(0);
    }
    return 0;
}

運行結果

命名管道
命名管道和無名管道基本相同,不同點是:無名管道只能由父子進程使用,但有名管道不相關的進程也能交換數據。
創建

#include<sys/types.h>
#include<sys/stat.h>

int mkfifo(const char* pathname,mode_t mode)

**pathname:**FIFO文件名
mode:屬性
一旦創建了一個FIFO,就可以用open打開它,一般的文件訪問函數(close、read、write等)都可以用於FIFO。
操作
當打開FIFO時,非阻塞標誌(O_NONBLOCK)將對以後的讀寫產生如下影響:
1、沒有使用O_NONBLOCK: 訪問要求將阻塞。
2、使用O_NONBLOCK: 訪問無法滿足時不阻塞,立刻返回出錯。errno是ENXIO.
例子: 使用mkfifo創建有名管道並實現兩個進程之間的通訊。

/*fifo_read.c*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo"

/*
 * 程序入口
 * */
int main(int argc,char** argv)
{
    char buf_r[100];
    int  fd;
    int  nread;

    printf("Preparing for reading bytes...\n");
    memset(buf_r,0,sizeof(buf_r));

    /* 打開管道 */
    fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
    if(fd==-1)
    {
        perror("open");
        exit(1);    
    }
    while(1)
    {
        memset(buf_r,0,sizeof(buf_r));

        if((nread=read(fd,buf_r,100))==-1)
        {
            if(errno==EAGAIN)
                printf("no data yet\n");
        }
        printf("read %s from FIFO\n",buf_r);
        sleep(1);
    }
    /*後面三句話是不會被運行到的,但不會影響程序運行的效果當程序在上面的死循環中執行時收到信號後會馬上結束運行而沒有執行後面的三句話。這些會在後面的信號處理中講到,現在不理解沒有關係,這個問題留給大家學習了信號處理之後來解決。*/
    close(fd); //關閉管道
    pause(); /*暫停,等待信號*/
    unlink(FIFO); //刪除文件
}
/*fifo_write.c
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO_SERVER "/tmp/myfifo"

/*
 * 程序入口
 * */
int main(int argc,char** argv)
{
    int fd;
    char w_buf[100];
    int nwrite;

    /*創建有名管道*/
    if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL|O_RDWR)<0)&&(errno!=EEXIST))
    {
        printf("cannot create fifoserver\n");
    }

    /*打開管道*/
    fd=open(FIFO_SERVER,O_WRONLY |O_NONBLOCK,0);
    if(fd==-1)
    {
        perror("open");
        exit(1);
    }

    /*入參檢測*/
    if(argc==1)
    {
        printf("Please send something\n");
        exit(-1);
    }
    strcpy(w_buf,argv[1]);

    /* 向管道寫入數據 */
    if((nwrite=write(fd,w_buf,100))==-1)
    {
        if(errno==EAGAIN)
            printf("The FIFO has not been read yet.Please try later\n");
    }
    else 
    {
        printf("write %s to the FIFO\n",w_buf);
    }
    close(fd); //關閉管道
    return 0;
}

運行結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章