进程间通信--管道

我们知道进程都有各自不同的地址空间,任何有一个进程的全局变量在在另外一个进程都看不到的,所以进程之间交换数据时在内核进行,通俗的说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:all
all:server client
server:server.c
        gcc -o $@ $^
client:client.c
        gcc -o $@ $^
.PHONY:clean
clean:
        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:结果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值