Linux进程学习之:管道通信

概述

管道是流行的进程间通信机制,使用了虚拟文件系统对象。
管道只能单向通信,如果要实现双向通信,就得再开辟一个新的管道出来
管道分为无名管道和有名管道,无名管道只能在具有血缘关系的进程间通信,有名管道可以在多进程之间通信

管道由pipe函数创建,函数声明如下:

/* Create a one-way communication channel (pipe).
   If successful, two file descriptors are stored in PIPEDES;
   bytes written on PIPEDES[1] can be read from PIPEDES[0].
   Returns 0 if successful, -1 if not.  */
extern int pipe (int __pipedes[2]) __THROW __wur;

pipe函数的参数是一个数组大小为二的一维数组,如果创建成功,两个文件描述符存储在管道里面,管道1只能写入,管道0只能读取,返回0代表创建成功,-1代表创建失败。

调用pipe函数后,系统会在内存中开辟一段内存,大小有待研究,这段内存成为管道,他有一个写端和读端。具体写的时候是如何写的目前还不清楚,读也是。

在创建子进程之前先创建管道,这样在创建子进程最后,子进程就会复制父进程的全部资源,包括管道的两个文件描述符。

  1. 如果所有指向管道写端的文件描述符都关闭了,而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样

  2. 如果有指向管道写端的文件描述符没关闭,而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回

  3. 如果所有指向管道读端的文件描述符都关闭了,这时有进程指向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止

  4. 如果有指向管道读端的文件描述符没关闭,而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再write会阻塞,直到管道中有空位置了才写入数据并返回
    (copy from https://www.cnblogs.com/MrListening/p/5858358.html)

coding

无名管道:

#include <iostream>
#include <unistd.h>
#include <string>
#include <stdlib.h>

using namespace std;

int main()
{
    int fd[2];
    if (pipe(fd)){
        cout << "create pipe failed" << endl;
    }
    pid_t pid;
    pid = fork();
    if (pid > 0){
        cout << "This is the parent: " << pid << endl;
        string wStr = "hello world!";
        write(fd[1], wStr.data(), wStr.size());
        sleep(10);
        close(fd[1]);
        exit(0);
    }
    if (pid == 0){
        cout << "This is the child: " << pid << endl;
        char rStr[128] = {'\0'};
        read(fd[0], rStr, sizeof (rStr));
        cout << rStr << endl;
        read(fd[0], rStr, sizeof (rStr));
        close(fd[0]);
        exit(0);
    }
    if (pid < 0){
        cout << "fail to fork" << endl;
        exit(1);
    }
    return 0;
}

有名管道

无名管道只能在具有血缘关系的进程间通信,而有名管道则可以在任意两个进程间通信。

首先,需要使用mkfifo函数生成一个管道文件,然后在两个进程中都使用open函数打开,然后就可以一个进程往管道写,一个管道读了。mkfifo 函数包含在sys/stat.h头文件中,函数声明如下:

/* Create a new FIFO named PATH, with permission bits MODE.  */
extern int mkfifo (const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

两个参数,第一个是路径,第二个是权限,一般的使用方法是

int ret = mkfifo("./myfifo", 0777);
if (ret < 0)
	cout << "create myfifo failed" << endl;
else
	cout << "create myfifo successfully" << endl;

上面的代码创建了一个名为myfifo的管道文件。

全部代码是:

#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
 
using namespace std;
 
int main(){
    int ret = mkfifo("./myfifo", 0777);
    if (ret < 0)
        cout << "create myfifo failed" << endl;
    else
        cout << "create myfifo successfully" << endl;
    return 0;
}

接下来需要创建两个文件,一个负责写入信息,一个负责读取信息

首先是写入信息的文件,这个文件中,我们首先要以只写方式打开管道文件,然后往里面写内容

 #include <iostream>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 using namespace std;
 
 int main(){
     int fd = open ("./myfifo", O_WRONLY); // O_WRONLY 包含在fcntl.h头文件中
     if (fd < 0){
         cout << "open myfifo failed" << endl;
         return -1;
     }
     cout << "open myfifo successfully" << endl;
     sleep(10);  // sleep函数包含在 stdlib.h 头文件中
     char signal = '1';
     write(fd, &signal, sizeof(signal));  // write 函数包含在unistd.h头文件中
     cout << "writed signal" << endl;
     return 0;
 }

注意:如果运行出错的话,删掉注释试一下

上述代码解释:首先打开管道文件,并打印打开成功与否信息,休眠十秒后往管道内写入信息,休眠的目的是当运行读管道内容的进程时,可以明显看出,当管道内没有内容可读时,读进程将会被阻塞,直到写进程在管道写入了信息。

接下来是读进程的代码:

 #include <iostream>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
 
 using namespace std;
 
 int main(){
     int fd = open("./myfifo", O_RDONLY);
     if (fd < 0){
         cout << "open myfifo file failed" << endl;
         return -1;
     }
     cout << "open myfifo file successfully" << endl;
     char signal[] = {"0"};
     read (fd, signal, sizeof(signal));
     cout << "read signal " << signal << endl;
     return 0;
 }

此代码相关注释可以参考写进程代码的注释

运行的时候,在第一个终端运行写进程代码,第二个终端运行读进程代码,可以看出在写进程睡眠十秒之后,往管道内写入了信息,此时阻塞的读进程被激活并读取管道内的信息。

此处,提个问题,读进程是如何知道管道被写入信息的?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园2.0是高校信息化建设的新阶段,它面对着外部环境变化和内生动力的双重影响。国家战略要求和信息技术的快速发展,如云计算、大数据、物联网等,为智慧校园建设提供了机遇,同时也带来了挑战。智慧校园2.0强调以服务至上的办学理念,推动了教育模式的创新,并对传统人才培养模式产生了重大影响。 智慧校园建设的解决之道是构建一个开放、共享的信息化生态系统,利用互联网思维,打造柔性灵活的基础设施和强大的基础服务能力。这种生态系统支持快速迭代的开发和持续运营交付能力,同时注重用户体验,推动服务创新和管理变革。智慧校园的核心思想是“大平台+微应用+开放生态”,过解耦、重构和统一运维监控,实现服务复用和深度融合,促进业务的快速迭代和自我演化。 智慧校园的总体框架包括多端协同,即“端”,它强调以人为中心,全面感知和捕获行为数据。这涉及到智能感知设备、超级APP、校园融合门户等,实现一“码”或“脸”行,提供线上线下服务端的无缝连接。此外,中台战略是智慧校园建设的关键,包括业务中台和数据中台,它们支持教育资源域、教学服务域等多个领域,实现业务的深度融合和数据的全面治理。 在技术层面,智慧校园的建设需要分期进行,逐步解耦应用,优先发展轻量级应用,并逐步覆盖更多业务场景。技术升级路径包括业务数据化、数据业务化、校园设施智联化等,利用IoT/5G等技术实现设备的泛在互联,并过人工智能与物联网技术的结合,建设智联网。这将有助于实现线上线下一网办,提升校园安全和学习生活体验,同时支持人才培养改革和后勤管理的精细化。 智慧校园的建设不仅仅是技术的升级,更是对教育模式和管理方式的全面革新。过构建开放、共享的信息化生态系统,智慧校园能够更好地适应快速变化的教育需求,提供更加个性化和高效的服务,推动教育创新和人才培养的高质量发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值