Linux系统编程-进程间通信(管道)

简介: 标准流管道像文件操作有标准io流一样,管道也支持文件流模式。用来创建连接到另一进程的管道popen和pclose。

1. 进程间通信方式介绍

这篇文章介绍Linux下进程的间的通信方式,常用的方式如下:

1. socket—网络通信
2. 管道---无名管道—命名管道---文件--FIFO
3. 消息队列
4. 共享内存
5. 信号量集
6. 信号—signal捕获信号---kill命令发送信号
 int kill(pid_t pid, int sig);

2. 标准流管道

标准流管道像文件操作有标准io流一样,管道也支持文件流模式。用来创建连接到另一进程的管道popen和pclose。
函数原型:

#include <stdio.h>
FILE* popen(const char* command, const char* open_mode);
int pclose(FILE* fp);

popen用于启动进程,用法含义与fopen类似,第二个参数填权限,支持填"r"和"w"。

pclose用于关闭进程,释放资源。

popen启动进程之后可以直接与启动的进程间通信,比较方便。

示例代码: 从标准管道流中读取 打印/etc/profile的内容:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *file=NULL;
    size_t len=0;
    char buff[1024+1];
    
    file=popen("cat /etc/profile","r"); //执行cat /etc/profile命令,读方式。
  
  if(file!=NULL)
  {
         len=fread(buff,1,1024,file); //读数据    
         buff[len]='\0';
         printf("len=%d\n %s\n",len,buff);
  } 
  pclose(file); //等待线程结束。
  return 0;
}

3. 无名管道

无名管道用于有亲戚关系的进程间通信。 比如: 兄弟进程、父子进程等。

#include <unistd.h> 
int pipe(int fds[2]);

pipe函数用于创建一个无名管道,如果成功,fds[0]就存放可读的文件描述符,fds[1]就存放可写文件描述符。

返回值: 0表示成功,-1表示失败。

无名管道的特点:

  1. 只能在亲缘关系进程间通信(父子或兄弟)
  2. 半双工(固定的读端和固定的写端)
  3. 虚拟管道文件是一个存在内存的特殊文件,可以用read、write函数进行操作。

这里说的管道,就像一条水管,有两个端口,一端进水,另一端出水。管道也有两个端口,分别是读端和写端,进水可看成数据从写端被写入,出水可看数据从读端被读出。在程序里分别就对应了read和write函数。

示例代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc,char **argv)
{
    int fds[2];
    /*1. 创建无名管道:得到管道读写文件描述符  fds[0]和读端相对应, fds[1]和写端相对应*/
    pipe(fds);
    /*2. 创建子进程*/
    pid_t pid;
    pid=fork();
    if(pid==0) //子进程
    {
        char buff[100+1];
        int cnt;
        //从管道的读端读取数据
        cnt=read(fds[0],buff,100); //带阻塞功能
        buff[cnt]='\0';
        printf("子进程收到的数据:%d,%s\n",cnt,buff);
    }
    else //父进程
    {
        char buff[]="1234567890";
        //向管道的写端写数据
        write(fds[1],buff,strlen(buff));
        //等待子进程结束
        wait(NULL);
        printf("父进程正常结束.\n");
    }
    return 0;
}

4. 命名管道

无名管道只能在亲缘关系的进程间通信大大限制了管道的使用,有名管道突破了这个限制,通过指定路径名的形式实现不相关进程间的通信,因为命名管道通信使用的管道是一个实体文件,在磁盘上的存在的,而无名管道是存在内存中的虚拟文件,其他进程无法访问,导致没有关联的进程无法进行通信。

4.1 在命令行如何创建管道文件?

[wbyq@wbyq test]$ mkfifo test.fifo
[wbyq@wbyq test]$ ls
test.fifo
[wbyq@wbyq test]$ ls -l
总用量 0
prw-rw-r--. 1 wbyq wbyq 0 10月 15 15:29 test.fifo

4.2 在命令行演示两个相关的进程通过进行管道文件进行通信

image-20211213090725147

4.3 创建fifo文件的函数

1. 创建FIFO文件
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
参数:
pathname:创建的FIFO文件的全路径名;
mode:文件访问权限,比如0666。
返回值:如果创建成功,则返回0,否则-1。

2. 删除FIFO文件
#include <unistd.h>
int unlink(const char *pathname);

3. 用命令创建和删除FIFO文件
用命令mkfifo创建。
用命令unlink删除。

4.4 创建写端: FIFO

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char **argv)
{
    if(argc!=2)
    {
        printf("./a.out <fifo文件--写>\n");
        return 0;
    }
    int fd=open(argv[1],O_WRONLY);
    if(fd<0)
    {
        printf("%s 文件打开失败.\n",argv[1]);
        return 0;
    }
    char buff[]="1234567890";
    write(fd,buff,strlen(buff));
    close(fd);
    return 0;
}
示例代码: 进程B负责读数据
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc,char **argv)
{
    if(argc!=2)
    {
        printf("./a.out <fifo文件--读>\n");
        return 0;
    }
    int fd=open(argv[1],O_RDONLY);
    if(fd<0)
    {
        printf("%s 文件打开失败.\n",argv[1]);
        return 0;
    }
    char buff[100+1];
    int cnt;
    cnt=read(fd,buff,100);
    buff[cnt]='\0';
    printf("buff=%s\n",buff);
    close(fd);
    return 0;
}

4.5 创建读端: FIFO

在命令行演示两个相关的进程通过进行管道文件进行通信.

image-20211213091027344

代码创建读端,读取数据:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

int main(void)
{
    int fd=0;
    int len=0;
    char buff[100];
    fd=open("myfifo",O_RDONLY);
    len=read(fd,buff,100);
    buff[len]='\0';
    printf("read: %s\n",buff);
    return 0;
}
目录
相关文章
|
7天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
30 3
|
7天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
25 2
|
7天前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
47 8
|
7天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
26 3
|
10天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
29 6
|
10天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
36 6
|
11天前
|
机器学习/深度学习 自然语言处理 Linux
Linux 中的机器学习:Whisper——自动语音识别系统
本文介绍了先进的自动语音识别系统 Whisper 在 Linux 环境中的应用。Whisper 基于深度学习和神经网络技术,支持多语言识别,具有高准确性和实时处理能力。文章详细讲解了在 Linux 中安装、配置和使用 Whisper 的步骤,以及其在语音助手、语音识别软件等领域的应用场景。
42 5
|
11天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####
|
4月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
4月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
167 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)