进程间通信--管道

来源:互联网 发布:电脑microsoft windows 编辑:程序博客网 时间:2024/06/05 17:20

我们知道进程都有各自不同的地址空间,任何有一个进程的全局变量在在另外一个进程都看不到的,所以进程之间交换数据时在内核进行,通俗的说A进程把数据拷贝到内核,B进程从内核中把数据读走,我们把内核提供的这种机制叫做进程间通信,(IPC).
这里写图片描述
管道:
管道:(pipe)
管道是一种基本的ipc机制,由pipe函数创建;

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

调用pipe函数时在内核中开辟一块缓冲区(管道)用于通信,它有一个独断和一个写端,然后通过fileds参数传出给用户程序两个文件描述符fileds[0]指向管道的读端,fileds[1]指向管道的写端.所以管道在用户程序看起来就像一个打开的文件,通过read(fileds [0])或者write(fileds [1])
pipe函数调用成功返回0,失败返回-1;
如何实现两个进程通信的?
1)父进程创建管道
这里写图片描述
2)父进程fork出子进程
这里写图片描述
3)父进程关闭fd[0].子进程关闭fd[1]
这里写图片描述
a:首先父进程调用pipo开通管道,得到两个文件描述指向管道的两端
b:父进程通过那个fork创建子进程,那么子进程也有两个文件描述符指向管道的两端
c;父进程关闭fd0,子进程关闭管道fd1,这样父进程向管道写数据,子进程向管道读数据,这就实现了进程的通信.
管道分为两种:匿名管道和命名管道
一:匿名管道:
第一:匿名管道只能实现本地进程之间的通信,不能实现跨网络之间的通信
第二:匿名管道只能实现父进程和子进程之间通信,而不能实现任意两个本地进程之间的通信
使用:
在父进程中,首先创建这个匿名管道,然后fork创建子进程,关闭子进程的读端,子进程只能进行写,子进程向这个匿名管道里面写数据,父进程向这个匿名管道里面读数据,这样就实现了进程间的通信.
实现:

#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<unistd.h>#include<string.h>#include<sys/wait.h>//int main(){ int fds[2] ={0};    if(pipe(fds)<0)    {        perror("pipe");        return 1;    }    pid_t id =fork();    if(id==0)    {        //子进程写        close(fds[0]);     char *msg ="hello pipe,i am a child!";        while(1)        {            write(fds[1],msg,strlen(msg));            sleep(1);        }        exit(0);//退出    }    else{        //父进程读        close(fds[1]);        char buf[1024];        while(1)        {            ssize_t ret = read(fds[0],buf,sizeof(buf)-1);            if(ret>0)            {                buf[ret-1]=0;                printf("client->father:%s\n",buf);            }        }        pid_t tmp =wait(NULL);    } return 0;}

这里写图片描述
二:命名管道(FIFO)
概念:
FIFO不同于管道之处在于它提供一个路径与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能通过FIFO相互通信.FIFO总是按照先进先出的原则工作,第一个被写入的数据将首先从管道中再读出
命名管道的创建与读写
方式一:在shell下交互第创建一个命名管道
方式二:在程序中使用系统函数简历命名管道,shell方式下课使用mknod或mkfifo命令,下面命令使用mknod
mknod namespace
创建命名管道的系统函数有两个:mknod和mkfifo.两个函数都定义在sys/types.h,函数原型如下:

#include<sys/types.h>#include<sys/stat.h>int mknod(const char*path,mode_t mod,dev_t dev);int mfifo(const char*path,mode_t mod);

我们以mkfifo为例:

umask(0);    if(mkfifo("./mypipe",0666|S_IFIFO)<0)//创建管道    {        perror("mkfifo");    return 1;    }

“S_IFIFO|0666”指明创建一个命名管道且访问权限为0666,创建者,用户,其他用户对该管道的访问权限都是可读可写.

1:编写Makefile文件

.PHONY:allall:server clientserver:server.c        gcc -o $@ $^client:client.c        gcc -o $@ $^.PHONY:cleanclean:        rm -f server client mypipe

这里面要注意创建管道在server.c的文件中,只有先创建管道,才能向client.c文件中写数据.
2:server.c用来读数据(读端)

server.c//向管道读数据#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>int main(){    umask(0);    if(mkfifo("./mypipe",0666|S_IFIFO)<0)//创建管道    {        perror("mkfifo");    return 1;    }    int fd = open("./mypipe",O_RDONLY);//以只读的方式打开   if(fd<0)   {       perror("open");       return 2;   }   char buf[1024];   while(1)   {       ssize_t s = read(fd,buf,sizeof(buf)-1);      if(s>0)       {           buf[s] =0;           printf("client say#%s\n",buf);       }  else if(s == 0)       {           printf("client is quite,server quite\n");           break;       }   }   close(fd);    return 0;}

3:client.c向管道写数据(写端)

client.c向管道写数据#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<string.h>int main(){    int fd = open("./mypipe",O_WRONLY);//只写的方式打开    if(fd<0)    {        perror("open");        return 2;    }    char buf[1024];    while(1)    {        printf("please enter: ");        fflush(stdout);        ssize_t s = read(0,buf,sizeof(buf)-1);    if(s>0)        {            buf[s-1] =0;            write(fd,buf,strlen(buf));        }    }    close(fd);    return 0;}

4:结果:
这里写图片描述

原创粉丝点击