进程间通信之管道

来源:互联网 发布:哪个软件有鱼眼效果 编辑:程序博客网 时间:2024/05/01 18:57

概述

网络编程里面的套接虽然强大,但是使用起来比较麻烦,并且如果只是单机之中不同的进程间通信,那么我们就不需要用网络套接字进行编程,我们有更好的办法!


管道

管道是一种半双工的通信方式,所谓半双工,就是数据只能单方向的进行流动,好比设置管道一的一端为A口,另一端为B口,则数据只能由A流向B。除此之外,管道还只能在有亲缘关系的进程间使用,通常指父子进程。


管道的局限性

管道的局限性是比较多的,除了上述两个缺点之外,它还没有名字,它的缓冲区大小是受限制的,它传递的是无格式的字节流,因为这个缺陷,它得要求输入方和输出方事先约好数据的格式。基于种种不便,除了一些简单的进程间通信,我们基本是不使用管道的。


管道的实现原理

当用管道进行两个进程间的通信的时候,其实使用的是系统设置的文件描述符,也就是说,管道其实就是一个特殊的文件,但是这个文件只存在于内存之中,在创建管道的时候,系统为管道分配一个页面作为数据缓冲区,进行通信的两个进程就是通过读写这个缓冲区实现的。


管道的创建和读写

#include<unistd.h>int pipe(int fd[2])//因为管道是一个半双工通信,所以管道两端的任务是固定的,一端用于读,一端用于写,我们用pipe函数可以创建两个文件描述符,fd[0]我们称为管道读端,fd[1]我们称为管道写端。

管道是一种文件,所以read(),write()等函数也适用于管道。


管道的用法

1.调用pipe()函数创建管道;
2.调用fork()函数创建子进程;
3.在子进程中关闭写端,fd[1],子进程读数据;
4.在父进程中关闭读端,fd[0],父进程写数据;


源代码:(实现全双工通信的管道)

#include<stdio.h>#include<string.h>#include<stdlib.h>#include<sys/wait.h>#include<sys/types.h>#include<unistd.h>void pipe1_rw(int fd1, int fd2)         //全双工的管道每端既可以写数据也可以读数据{    char *message1;    char message2[50];    message1 = "I am a linuxer";    write(fd1, message1, strlen(message1)+1);    read(fd2, message2, 50);    printf("from child process: %s\n", message2);}void pipe2_rw(int fd1, int fd2){    char *message1;    char message2[50];    message1 = "I am a LINUXER";    write(fd2, message1, strlen(message1)+1);    read(fd1, message2, 50);    printf("from parent process: %s\n", message2);}int main(){    int fd1[2], fd2[2];         //因为管道是半双工,所以创建两个管道,实现全双工通信    int pid;    int status;    if(pipe(fd1) < 0)           //管道1    {        printf("line: %d, pipe error\n", __LINE__);        exit(1);    }    if(pipe(fd2) < 0)           //管道2    {        printf("line: %d, pipe error\n", __LINE__);        exit(1);    }    pid = fork();               //创建子进程    switch(pid)    {        case -1:            printf("line: %d, fork error\n", __LINE__);            exit(1);        break;        case 0:                 // 每个进程现在拥有两个管道文件描述符            close(fd1[0]);      // 关闭管道1的读端            close(fd2[1]);      // 关闭管道2的写端            pipe1_rw(fd1[1], fd2[0]);            exit(0);        break;        default:            close(fd1[1]);      // 关闭管道1的写端            close(fd2[0]);      // 关闭管道2的读端            pipe2_rw(fd1[0], fd2[1]);            wait(&status);            exit(0);        break;    }    return 0;}

下面是运行结果:


代码的详细注释见代码部分。

0 0