【Linux】进程通信----管道通信(下)

简介: 【Linux】进程通信----管道通信(下)

【Linux】进程通信----管道通信(上)    https://developer.aliyun.com/article/1565747



3.管道特征

1.管道的生命周期随进程,进程退出,管道释放

2.管道可以用来进行具有血缘关系的进程间通信(常用于父子通信)

3.管道是面向字节流的

4.半双工—单向通信(特殊)

5.互斥与同步机制——对共享资源进行保护的方案


💫 命名管道

概念:

我们前面已经知道:匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。那如果两个毫不相干的进程间通信交互呢?如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。命名管道是一种特殊类型的文件


1.mkfifo

使用说明

NAME
       mkfifo - make FIFOs (named pipes)
 
SYNOPSIS
    #include <sys/types.h>
    #include <sys/stat.h>
    int mkfifo(const char *pathname, mode_t mode);
RETURN VALUE
       On success mkfifo() returns 0.  In the case of an error, -1 is returned (in which case, errno is set appropriately).


在当前路径下直接创建命名管道:

mkfifo named_pipe

往管道文件写东西:



2.创建管道文件

分为三个文件:comm.hpp:公共文件(同一份资源),server.cc:读取端,clinet.cc:写入端

comm.hpp文件(同一份资源)

#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <string>
#include <cerrno>
#include <cstring>
#include <cassert>
 
#define NAMED_PIPE "/tmp/mypipe.name"
 
bool createFifo(const std::string &path)
{
    umask(0);
    int n = mkfifo(path.c_str(),0666);
    if(n==0) return true;
    else
    {
        std::cout<<"errno:"<<errno<<"err string:"<<strerror(errno)<<std::endl;
        return false;
    }
}


server.cc:

#include "comm.hpp"
int main()
{
    bool ret = createFifo(NAMED_PIPE);
    assert(ret);
    (void)ret;
    return 0;
}

运行:



3.删除管道文件

使用说明

unlink   注意头文件,函数的参数以及返回值这三个主要部分:

NAME
       unlink - remove a directory entry
 
SYNOPSIS
       #include <unistd.h>
 
       int unlink(const char *path);
RETURN VALUE
       Upon successful completion, 0 shall be returned. Otherwise, -1 shall be returned and errno set to indicate the error. If -1 is returned, the named file shall not be changed.
 


在comm.hpp中封装好删除的函数:

void removeFifo(const std::string &path)
{
    int n = unlink(path.c_str());
    assert(n==0);
    (void)n;//防止n没使用而警告
}


在server.cc中进行调用:

#include "comm.hpp"
 
int main()
{
    bool ret = createFifo(NAMED_PIPE);
    assert(ret);
    (void)ret;
 
    removeFifo(NAMED_PIPE);
    return 0;
}


至此,创建和删除管道文件的操作我们实现完毕。下面进入通信环节

4.通信

说明:

其实在了解完了匿名管道之后,对于命名管道我们能够更好的理解:

client.cc(写端):

#include "comm.hpp"
 
int main()
{
    int wfd = open(NAMED_PIPE,O_WRONLY);
    if(wfd<0) exit(1);
    //write
    char buffer[1024];
    while(true)
    {
        std::cout<<"Please Say:";
        fgets(buffer,sizeof(buffer),stdin);
        //if(strlen(buffer)>0) buffer[strlen(buffer)-1] = 0;
        ssize_t n = write(wfd,buffer,strlen(buffer));
        assert(n==strlen(buffer));
        (void)n;
    }
    close(wfd);
    return 0;
}


server.cc(读端):

#include "comm.hpp"
 
int main()
{
    bool ret = createFifo(NAMED_PIPE);
    assert(ret);
    (void)ret;
 
    int  rfd = open(NAMED_PIPE,O_RDONLY);
    if(rfd<0) exit(1);
 
    //read
    char buffer[1024];
    while(true)
    {
        ssize_t s = read(rfd,buffer,sizeof(buffer)-1);
        if(s>0)
        {
            buffer[s] = 0;
            std::cout<<"client->server" <<buffer<<std::endl;
        }
        else if(s==0)
        {
            std::cout<<"client quit,俺也一样"<<std::endl;
            break;
        }
        else
        {
            std::cout<<"err string:"<<strerror(errno)<<std::endl;
            break;
        }
    }
    close(rfd);
    removeFifo(NAMED_PIPE);
    return 0;
}


进行通信:



读端多出一行空行:写端输入之后多按了回车,修改为buffer[strlen(buffer)-1] = 0;

if(strlen(buffer) > 0) buffer[strlen(buffer) - 1] = 0;



🌙 管道通信的优化

管道通信的优点有以下几点:

  • 管道通信是简单易用的,只需要使用系统调用 pipe 或 mkfifo 就可以创建一个管道文件,然后使用文件操作函数来读写数据。
  • 管道通信是安全的,匿名管道只能用于具有亲缘关系的进程间通信,命名管道可以通过文件权限来控制访问。
  • 管道通信是面向字节流的,不需要事先约定数据的格式,也不需要考虑字节序的问题。


管道通信的缺点有以下几点:


  • 管道通信是单向的,如果要实现双向通信,需要创建两个管道。
  • 管道通信是阻塞式的,如果读端没有数据可读或者写端没有空间可写,进程会被阻塞。
  • 管道通信是缓冲区有限的,如果写入数据过多而读出数据过少,会导致缓冲区满而无法继续写入。
  • 管道通信是不可靠的,如果读端或者写端被关闭,另一端可能会收到错误的信号或者返回值。


改进管道通信性能和效率的方法有以下几点:


  • 使用双向管道,可以实现两个进程之间的双向通信,而不需要创建两个单向管道。双向管道可以通过 socketpair 系统调用来创建,返回两个文件描述符,分别表示管道的两端。
  • 使用非阻塞模式,可以避免进程在读写管道时被阻塞,提高并发性能。非阻塞模式可以通过 fcntl 系统调用来设置文件描述符的 O_NONBLOCK 标志。
  • 使用自定义协议,可以根据通信的需求和场景,设计合适的数据格式和交互方式,提高数据传输的效率和可靠性。自定义协议可以包括数据包的长度、类型、校验码等信息。
  • 调整管道缓冲区的大小,可以根据数据量的大小和频率,选择合适的缓冲区大小,避免缓冲区溢出或者空闲浪费。管道缓冲区的大小可以通过 fcntl 系统调用来设置 F_SETPIPE_SZ 标志,并且可以通过 /proc/sys/fs/pipe-max-size 来修改最大容量。


🌟结束语 

      今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。


目录
相关文章
|
15天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
40 1
|
3天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
38 13
|
10天前
|
SQL 运维 监控
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
|
18天前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
23天前
|
缓存 算法 Linux
Linux内核的心脏:深入理解进程调度器
本文探讨了Linux操作系统中至关重要的组成部分——进程调度器。通过分析其工作原理、调度算法以及在不同场景下的表现,揭示它是如何高效管理CPU资源,确保系统响应性和公平性的。本文旨在为读者提供一个清晰的视图,了解在多任务环境下,Linux是如何智能地分配处理器时间给各个进程的。
|
1月前
|
网络协议 Linux 虚拟化
如何在 Linux 系统中查看进程的详细信息?
如何在 Linux 系统中查看进程的详细信息?
65 1
|
1月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
1月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
95 8
|
1月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
260 6
|
1月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
80 3
下一篇
DataWorks