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;
}

运行结果

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