进程间通信--管道

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

在Linux系统中,管道是实现进程间通信的一种重要方式,分为匿名管道和命名管道。 ### 匿名管道 匿名管道是一种基于文件的进程间通信方式,本质上是内核中的一块缓冲区,用于连接一个进程的输出和另一个进程的输入。创建匿名管道使用`pipe`函数,其工作原理是利用`fork`函数创建子进程,使父子进程共享管道的读写端。 匿名管道使用步骤如下: 1. 调用`pipe`函数创建管道。 2. 使用`fork`函数创建子进程,此时父子进程共享管道的读写端。 3. 父子进程根据需要关闭不需要的读写端。 4. 进行数据的读写操作。 5. 读写完成后,关闭管道的读写端。 匿名管道有其读写规则和四种常见场景,例如写端不写且不退出、读端不读且不退出等情况。使用匿名管道时,可通过编写`makefile`、`Task.hpp`、`ctrlPipe.cc`等文件来实现具体的进程间通信逻辑[^1]。 ### 命名管道 命名管道是一种具有实际文件系统路径名的管道,它允许不相关的进程之间进行通信。创建命名管道使用`mkfifo`系统调用。 使用命名管道实现进程间通信的步骤如下: 1. 调用`mkfifo`函数创建命名管道文件。 2. 不同的进程打开该命名管道文件进行读写操作。 3. 读写完成后,关闭命名管道文件。 4. 可删除命名管道文件。 使用命名管道实现`serve&client`通信时,需要编写`Common.hpp`、`pipeServer.cpp`、`pipeClient.cpp`、`makefile`等文件来完成具体的通信逻辑[^1]。 以下是一个简单的匿名管道示例代码: ```c #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { int pipefd[2]; pid_t pid; char buffer[100]; // 创建管道 if (pipe(pipefd) == -1) { perror("pipe"); return 1; } // 创建子进程 pid = fork(); if (pid == -1) { perror("fork"); return 1; } if (pid == 0) { // 子进程,关闭读端 close(pipefd[0]); const char *message = "Hello, parent process!"; write(pipefd[1], message, sizeof(message)); close(pipefd[1]); } else { // 父进程,关闭写端 close(pipefd[1]); ssize_t n = read(pipefd[0], buffer, sizeof(buffer)); if (n > 0) { buffer[n] = '\0'; printf("Received from child: %s\n", buffer); } close(pipefd[0]); } return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值