【进程间通信:管道】(二)

简介: 【进程间通信:管道】(二)

2.3 管道读写规则

当没有数据可读时:

O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。

O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

当管道满的时候:

O_NONBLOCK disable: write调用阻塞,直到有进程读走数据

O_NONBLOCK enable:调用返回-1,errno值为EAGAIN

如果所有管道写端对应的文件描述符被关闭,则read返回0

如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程退出

当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

前面的都很好理解,这里提一嘴什么是原子性:原子性就是假如我们往管道中写入一句"hello world"时,如果能够将其完整写进去时进行写入,否则就不进行写入,也就是程序的执行只能够有两种结果:数据全部写入和数据全部都没写入,不存在着写入一半的情况。

2.4 匿名管道特点

只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

管道提供流式服务

一般而言,进程退出,管道释放,所以管道的生命周期随进程

一般而言,内核会对管道操作进行同步与互斥

管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道

629f6bc1c7404cd5b48ed04f3e3fb881.png


2.5 命名管道

2.5.1 概念

管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。

如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件。

2.5.2 使用

我们知道匿名管道是具有血缘关系的进程建立通信的方式,而命名管道则是可以让没有血缘关系的进程建立通信。那么如何让没有血缘关系的进程看到同一份资源呢?

我们首先来看看这样一个命令:


8ec6194b134a465783c4841435e07074.png

我们通过mkfifo命令创建了一个叫做fifo的管道文件,当我们将字符串输出重定向到该文件时我们发现光标卡在了这里不动了,而当我们去读取的时候才会显现,当我们终止掉时两边都已经结束了:

d3919629c1024d95935c31420d8ceef1.gif

这是在命令行上创建的命名管道。而这种管道是内存级别的文件,是不会刷新到磁盘上的。生成的命名管道文件只是内核缓冲区的一个标识,用于让多个进程找到同一个缓冲区。匿名管道和命名管道的本质都是内核中的一块缓冲区。再来回答如何让不同的进程看到同一份资源,我们可以采用文件路径+文件名来作为唯一标识该文件的方法来创建文件作为一个命名管道。

除了用命令行式的方法,我们还可以用系统调用:

int mkfifo(const char *filename,mode_t mode);


971fdd98ee674d3cb98f13e9f17f1b3d.png

通过这个我们可以实现一个简单的服务端与客户端进行通信的程序:

server.cc:

#include<iostream>
#include<cstring>
#include<string>
#include<cerrno>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
using namespace std;
int main()
{
    const string fileName("myfile");
    umask(0);
    int n=mkfifo(fileName.c_str(),0666);
    if(n<0)
    {
        cerr<<"strerrno:"<<errno<<strerror(errno)<<endl;
        return 1;
    }
    cout<<"server creat fifo success"<<endl;
    int rop=open(fileName.c_str(), O_RDONLY);
    if(rop<0)
    {
        cerr<<"strerrno:"<<errno<<strerror(errno)<<endl;
        return 1;
    }
    cout<<"server open fifo success,begin ipc"<<endl;
    char buffer[1024];
    while(true)
    {
        buffer[0]=0;
        int n=read(rop,buffer,sizeof(buffer)-1);
        if(n>0)
        {
            buffer[n]=0;
            cout<<buffer<<endl;
        }
        else if(n==0)
        {
            cout<<"client exit,server also exit"<<endl;
            break;
        }
        else
        {
            cerr<<"strerrno:"<<errno<<strerror(errno)<<endl;
            return 1;
        }
    }
    close(rop);
    unlink(fileName.c_str());
    return 0;
}

client.cc:

#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string>
#include<cerrno>
#include<cstring>
using namespace std;
int main()
{
    const string fileName("myfile");
    int wop=open(fileName.c_str(),O_WRONLY);
    if(wop<0)
    {
        cerr<<"strerrno:"<<errno<<strerror(errno)<<endl;
        return 1;
    }
    string myinfo;
    while(true)
    {
        cout<<"请输入你的消息"<<endl;
        getline(cin,myinfo);
        write(wop,myinfo.c_str(),myinfo.size());
        myinfo[strlen(myinfo.c_str())-1]=0;
    }
    close(wop);
    return 0;
}

Makefile:

.PHONY:all
all:client server
client:client.cc
  g++ -o $@ $^ -std=c++11
server:server.cc
  g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
  rm -rf client server

效果:


4db82ce57db64379a6091beb600169f2.gif

由于我们是在服务端建立好的匿名管道,所以当我们退出时最好在服务端中干掉管道文件。

顺便提问一下:多个进程在通过管道通信时,删除管道文件则无法继续通信吗?

显然不是的,由于管道文件只是起一个标识作用,之前已经打开管道的进程依旧可以正常通信。

目录
相关文章
|
29天前
|
消息中间件 Unix Linux
C语言 多进程编程(二)管道
本文详细介绍了Linux下的进程间通信(IPC),重点讨论了管道通信机制。首先,文章概述了进程间通信的基本概念及重要性,并列举了几种常见的IPC方式。接着深入探讨了管道通信,包括无名管道(匿名管道)和有名管道(命名管道)。无名管道主要用于父子进程间的单向通信,有名管道则可用于任意进程间的通信。文中提供了丰富的示例代码,展示了如何使用`pipe()`和`mkfifo()`函数创建管道,并通过实例演示了如何利用管道进行进程间的消息传递。此外,还分析了管道的特点、优缺点以及如何通过`errno`判断管道是否存在,帮助读者更好地理解和应用管道通信技术。
|
6天前
|
SQL 网络协议 数据库连接
已解决:连接SqlServer出现 provider: Shared Memory Provider, error: 0 - 管道的另一端上无任何进程【C#连接SqlServer踩坑记录】
本文介绍了解决连接SqlServer时出现“provider: Shared Memory Provider, error: 0 - 管道的另一端上无任何进程”错误的步骤,包括更改服务器验证模式、修改sa用户设置、启用TCP/IP协议,以及检查数据库连接语句中的实例名是否正确。此外,还解释了实例名mssqlserver和sqlserver之间的区别,包括它们在默认设置、功能和用途上的差异。
|
5月前
|
存储 负载均衡 Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
|
5月前
|
消息中间件 Unix Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
|
2月前
|
消息中间件 Linux 开发者
Linux进程间通信秘籍:管道、消息队列、信号量,一文让你彻底解锁!
【8月更文挑战第25天】本文概述了Linux系统中常用的五种进程间通信(IPC)模式:管道、消息队列、信号量、共享内存与套接字。通过示例代码展示了每种模式的应用场景。了解这些IPC机制及其特点有助于开发者根据具体需求选择合适的通信方式,促进多进程间的高效协作。
78 3
|
2月前
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
52 0
|
2月前
|
Linux C语言
【C语言】进程间通信之命名管道fifo
【C语言】进程间通信之命名管道fifo
14 0
|
2月前
|
C语言
【C语言】进程间通信之管道pipe
【C语言】进程间通信之管道pipe
28 0
|
2月前
|
Python
Python IPC深度探索:解锁跨进程通信的无限可能,以管道与队列为翼,让你的应用跨越边界,无缝协作,震撼登场
【8月更文挑战第3天】Python IPC大揭秘:解锁进程间通信新姿势,让你的应用无界连接
20 0
|
2月前
|
消息中间件 存储 网络协议
从零开始掌握进程间通信:管道、信号、消息队列、共享内存大揭秘
在操作系统中,进程间通信(IPC)是至关重要的,它提供了多种机制来实现不同进程间的数据交换和同步。本篇文章将详细介绍几种常见的IPC方式,包括管道、信号、消息队列、共享内存、信号量和套接字,帮助你深入理解并合理应用这些通信方式,提高系统性能与可靠性。
125 0