Linux通信--构建进程通信的 方案之管道(下)|使用匿名管道实现功能解耦|命名管道实现serve&client通信

文章目录

一、管道的应用实例-父进程唤醒子进程,子进程执行某种任务

二、命名管道

1.创建一个命名管道

2.匿名管道与命名管道的区别

3.命名管道的打开规则

4.用命名管道实现server&client通信



一、匿名管道的应用实例-父进程唤醒子进程,子进程执行某种任务

后续将源码上传到gitee,上传后修改链接。

二、命名管道

  • 管道应用的一个限制就是只能具有共同祖先的进程进行通信
  • 如果想让不相关的进程交换数据,可以使用FIFO文件来做,它被称为命名管道
  • 命名管道是一种特殊的文件

1.创建一个命名管道

创建命令:mkfifo filename

创建函数: int mkfifo(const char * filename,mode_t mode);

参数:管道的名字,创建的管道权限

2.匿名管道与命名管道的区别

  • 匿名管道由pipe函数创建并打开
  • 命名管道由mkfifo函数创建,打开用open
  • FIFO(命名管道)与pipe(匿名管道)之间的区别在于,他们创建与打开的方式不同,这些工作完成后,他们有相同的语义。

3.命名管道的打开规则

  • 如果是只读方式打开FIFO
  • O_NONBLOCK disable:阻塞直到有相应进程为写而打开FIFO
  • O_NONBLOCK enable:立刻返回成功
  • 如果是只写方式打开FIFO
  • O_NONBLOCK disable:阻塞直到有相应进程为读而打开FIFO
  • O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

4.用命名管道实现server&client通信

实例功能:

1创建管道

2 创建的命名管道可以让两个进程通信

3. 进程A 向管道中写入 进程B从管道中读取并打印到标准输出

需求分析:首先需要创建两个进程,client端和server端,还需要一个common文件来声明共同的定义和方法,所以创建三个文件client.cc,server.cc,common.hpp。接下来逐个文件分析

1.首先,创建管道,只需要创建一次即可,本次案例在server.cc中创建,client.cc中使用即可

common.hpp
#pragma once 
#include<iostream>
#include<string>
#define NUM 1024
const std::string fifoname = "./fifo";
uint32_t mode = 0666;


server.cc

umask = 0; //这个设置不影响系统的umask,只影响此进程的
int n = mkfifo(fifoname.c_str(),mode);

至此管道已经创建

2.让服务端直接开启管道文件

int rfd = open(fifoname.c_str(),O_RDONLY);
//打开失败
if(rfd < 0)
{
    std::cout<<errno<<endl;
    return 2;
}

//打开成功
    ....

3.client端不需要创建文件,只用写方式打开文件就可以

// int open(const char * pathname ,int oflag, ...) 
//成功则返回文件描述符,失败-1


int wfd = open(filename.c_str(),O_WRONLY);
if(wfd <0)
{
    //写方式打开失败
    return 1;
}


4.两端开始通信

server端:
 
char buffer[1024];
while(true)
{
    buffer[0] = 0;

    //read(int fd , void * buf, size_t count) fd是文件描述符,用于要定位读取的文件或者其他设备,buf为缓冲区地址,count是要读取的字节数,读成功返回实际读取的字节数,返回复数读取失败,返回0读取到文件末尾
    
    //从rfd文件中读取x个字节到buffer中
    ssize_t n = read(rfd,buffer,sizeof(buffer)-1);

    if(n> 0)
    {
        buffer[n] = 0;
        std::cout<<"client " <<buffer <<std::endl;
    }

    else if(n== 0)
    {
        std::cout<<"client quit, me too" <<std::endl;
        break;
    }

    else
    {
        std::cout<<errno<<std::endl;
        break;
     }
}

client端:

    char buffer[NUM];
    while(true)
    {
        std::cout<<"please enter your message : ";
        char * msg = fgets(buffer,sizeof(buffer)-1,stdin);
        assert(msg);
        (void)msg;
        
        //处理发送消息的回车,最后一个字符删掉
        buffer[strlen(buffer)-1] = o;
        ssize_t n = write(wfd,buffer,strlen(buffer));
        assert(n>= 0);
        (void)n;
    }

    
    

5.两端通信结束,关闭对应的文件描述符

close(wfd);

close(rfd);


猜你喜欢

转载自blog.csdn.net/jolly0514/article/details/132548062