IPC之管道编程(1)

来源:互联网 发布:php 积分商城 开源 编辑:程序博客网 时间:2024/06/16 17:59

1、IPC

IPC:是指进程间通信(Inter Process Cnmunication)。进程间相互通信的方式主要有以下6种:
(1)管道(pipe)和有名管道(FIFO)。
(2)信号(signal)
(3)消息队列
(4)共享内存
(5)信号量
(6)套接字(socket)


2、进行进程间通信的目的

(1)数据传输:一个进程需要将它的数据发送给另一个进程。
(2)资源共享:多个进程之间共享同样的资源。
(3)通知事件:一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。
(4)进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。


3、管道通信

管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。


4、管道创建

管道包括无名管道和有名管道两种,前者用于父进程和子进程之间的通信;后者用于统一系统的任意两个进程间的通信。
(1) 无名管道由pipe()函数创建:

#include <unistd.h>int pipe(int fd[2]);

当一个管道建立时,它会创建两个文件描述符:
fd[0]用于读管道,fd[1]用于写管道。

(2)命名管道由mkfifo()函数创建:

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

mkfifo() 中 path 需要指定为文件的绝对路径。
nkfifoat() 当 fd 为 AT_FDCWD时,则路径名以当前目录开始。
mode 创建一个命名管道时的属性。
一旦创建了FIFO,就可以用 open 打开它,一般的文件访问函数(read、write、close等)都可用于FIFO。
当 open 一个FIFO时,非阻塞标志(O_NONBLOCK)会产生以下影响。
1、没有使用O_NONBLOCK:访问要求无法满足要求时进程将阻塞,如试图读取空FIFO时,将导致进程阻塞。
2、使用O_NONBLOCK:访问要求无法满足时不阻塞,立刻出错返回,errno 是 ENXIO


5、管道关闭

关闭管道只需要将文件描述符关闭即可,可以使用普通的close()函数逐个关闭。


6、管道通信demo

(1)无名管道
这里写图片描述

demo:

#include <apue.h>int main(int argc, const char *argv[]){    int fd[2];    pid_t pid;    int n;    char line[MAXLINE];    /* 创建管道 */    if (pipe(fd) < 0)        err_sys("pipe error");    /* 创建子进程 */    if ((pid = fork()) < 0)        err_sys("fork error");    else if (pid > 0){            //父进程        close(fd[0]);        write(fd[1], "Hello World\n", 12);        close(fd[1]);        waitpid(pid, NULL, 0);    //等待子进程退出        exit(0);    }    else{                         //子进程        close(fd[1]);        sleep(1);                 //先让父进程有时间写数据        n = read(fd[0], line, MAXLINE);        write(STDOUT_FILENO, line, n);        close(fd[0]);        exit(0);    }    return 0;}

注意:系统必须先调用pipe()再调用fork(),不然会产生两个进程,子进程也不会继承文件描述符!

(2)命名管道通信demo
创建两个进程,一个为写进程,另一个为读进程。

/**************//*   读进程   *//*************/#include <apue.h>#include <fcntl.h>#define FIFO "/tmp/myfifo"int main(int argc, char *argv[]){    char buf_rd[100];    int fd;    int bytes_rd;    /* 创建管道 */    if ((mkfifo(FIFO, O_CREAT | O_EXCL) < 0) && (errno != EEXIST))        printf("Can't create fifo\n");    printf("Preparing for reading bytes...\n");    memset(buf_rd, 0, sizeof(buf_rd));    /* 打开管道 */    fd = open(FIFO, O_RDONLY | O_NONBLOCK);    if (fd == -1){        perror("Open fifo error");        exit(10);    }    while(1){        memset(buf_rd, 0, sizeof(buf_rd));        if (bytes_rd = read(fd, buf_rd, 100) == -1)            if (errno == EAGAIN)                printf("No data yet\n");        printf("Read %s from FIFO\n", buf_rd);        sleep(1);    }}
/**************//*   写进程   *//*************/#include <apue.h>#include <fcntl.h>#define FIFO_SERVICE "/tmp/myfifo"int main(int argc, char *argv[]){    char buf_wr[100];    int  bytes_wr;    int  fd;    int i;    if (argc == 1){        printf("Please send something\n");        printf("Usage : ./a.out string ...\n");        exit(1);    }    for (i = 1; i < argc; i++){        strcat(buf_wr, " ");        strcat(buf_wr, argv[i]);    }    fd = open(FIFO_SERVICE, O_WRONLY | O_NONBLOCK);    if (fd == -1){        perror("Open FIFO error");        exit(10);    }    if ((bytes_wr = write(fd, buf_wr, 100)) == -1){        if (errno == EAGAIN)            printf("The FIFO has been read yet, Please try agian\n");    }    else        printf("Write%s to FIFO\n", buf_wr);}