美文网首页
进程间的通信方式, since 2020-11-02

进程间的通信方式, since 2020-11-02

作者: Mc杰夫 | 来源:发表于2020-11-03 07:52 被阅读0次

进程间的通信方式

(2020.11.02 Mon)
进程有其独立性,每个进程的数据停留在自己的进程空间里,互不干涉。有时需要进程间分享数据,进行进程间通信(Inter-proess communication, IPC)

一种原始的IPC方式:通过文件交换信息

一个进程往文件里写数据,另一个从中读出数据。

$ping localhost > log.txt &
$while true; do tail -l log.txt; done;
信号作为IPC

一个进程发出信号,放入目标进程的描述符,另一个进程进行系统调用时,在自己的描述符中看到该信号。两个进程通过信号进行了简单的数据交换。缺点是无法大量交换数据。内核空间和进程空间独立,所以绕开了进程空间相互独立的限制。

管道pipe

管道变更文本流的方向,管道的目的地是另一个进程。可以把一个进程的输出变成另一个进程的输入。管道直接把一个进程的输出和另一个进程的输入连接起来。用|表示管道。

$echo hello | grep lo

管道把echo的输出导入grep命令,grep是从文本流中寻找'lo'字符串。由于输入的hello包含了lo,所以grep命令打印出hello。
该命令会同时启动两个进程。

基于管道的进程间数据交换发生在内核空间。通过内核来绕开进程空间的独立性限制。创建管道之后,内核空间会有一个专用的缓冲区用于存放要传输的数据。输出进程向缓冲区不停的写数据,输入进程从缓冲区按顺序取出数据。效果上看,数据沿着管子有序的从一个进程到另一个进程。

缓冲区被设计成环形(circular array?)的数据结构。旧的数据已经取出时,新的数据就可以占用这块内存空间。如果缓存区放满,则尝试进入的数据的进程会等待,直到另一端的进程取出消息。两个进程终结,管道会自动消失,缓冲区的内存空间也会收回。

管道的创建

利用fork机制。关于资源的fork,进程会把打开文件的信息复制给子进程。这样,进程输入和输出端口的信息会复制到子进程。因此,一个进程会像新建文件一样,先创建一个管道,该进程的输入和输出,直接接到这个管道上。

完成上述步骤,进程会fork。随着资源fork,进程到管道的两个连接也复制到了子进程上,两个进程同时接上同一个管道。随后,每个进程关闭自己不需要的一个连接。parent关闭从管道来的输入连接,即子进程输出到管道的连接。这样,剩下的连接就行程了可以从一个进程到另一个进程传输的管道。

这种创建管道的方式基于fork机制,因此管道必须用于parent和child进程之间,或者拥有相同祖先的两个子进程之间。为解决这一问题,Linux提供了命名管道(named pipe)

命名管道的基础是FIFO,一种特殊的文件类型,它在文件系统中有对应的路径。如果一个进程以读方式打开fifo文件,另一个以写方式打开,则内核就会在这两个进程间建立管道。FIFO存活于内核空间,其效率比存储器文件的IPC高很多。

只要两个进程读写同一个FIFO文件,就可以自由的建立管道,可以直接用命令来创建命名管道:

$mknod {file_name} p

比如,在临时文件夹创建一个命名管道

mknod /tmp/named_pipe p

打开两个命令行窗口,在窗口1输入

$tail -f /tmp/named_pipe

在窗口2输入

$echo hello >> /tmp/named_pipe

返回窗口1,会看到echo的内容被命名管道传递到了这边。

用rm指令删除FIFO文件,named pipe连接也会随之消失。

在Linux系统中,管道共用了存储器文件的API,所以创建到使用都很方便。

(2020.11.03 Tues)

其他IPC方式

不同的IPC方式都实现了进程间的资源共享,包括消息队列,共享内存和套接字

消息队列message queue以及对比管道

与pipe相似,在内核空间把数据排好队,先入先出。MQ的数据单元是一个长度不定的消息,而pipe是以字节为单位的数据流。pipe两端分别只能连接一个进程,而mq允许多个进程参与,既可以有多个进程往mq中放入消息,也可以有多个进程从mq中取出消息。mq不依附于特定的进程,也不会像pipe那样自动消失。mq一旦被创建,就会一直停留在内核空间,知道某个进程删除该queue。

消息队列可按数据类型取出消息。消息放入mq时,可以带有一个整数,作为该消息的类型。当进程取出消息时,可以提供参数类型,按照FIFO的顺序,只取出这一类型的消息。此时,类型就起到了筛选消息的功能。
下面是C语言的mq传输数据的程序。sender。

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_struct {
    int type;
    char content[100];
} message;

int main() {
//生成IPC key
key_t key = ftok('path', 65);
//创建一个mq,获得message queue ID
int mqid = msgget(key, 0666 | IPC_CREAT);
//输入文本
printf('please input the text to be sent: ');
fgets(message.content, 100, stdin);
message.type = 1;
//发送数据
msgsnd(mqid, &message, sizeof(message), 0);
printf('data sent: %s', message.content);
return 0;
}

receiver.

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_struct {
    int type;
    char content[100];
} message;

int main() {
//生成IPC key
key_t key = ftok('path',65);
//创建一个mq,获得message queue id
int mqid = msgget(key, 0666 | IPC_CREAT);
//收取数据
msgrcv(mqid, &message, sizeof(message),1 ,0);
printf('Data received: %s', message.content);
//销毁mq
msgctl(mqid, IPC_RMID, NULL);
return 0;
}
共享内存shared memory

打破了进程空间的独立性。一个进程可以将自己内存空间的一部分拿出来作为共享内存,允许其他进程直接读写。数据始终停留在同一个地方,不需要迁移到存储器空间或内核空间,是效率最高的IPC方式。适用于大数据量的场景,比如图像处理。父子进程间共享数据的C代码如下。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
#define ANSI_COLOR_CYAN '\x1b[36m'
#define ANSI_COLOR_REST '\x1b[0m'
void *create_shared_memory(size_t size)
{
//将共享内存设置成可读可写
int protection = PROT_READ | PROT_WRITE;
//将共享内存设置成共享(第三方进程可读)和匿名(第三方进程无法得到访问地址)
int visibility = MAP_ANONYMOUS | MAP_SHARED;
//创建共享内存
return mmap(NULL, size, protection, visibility, 0, 0);
}

int main() {
    setbuf(stdout, NULL);
    void *shmem = create_shared_memory(128);
    int pid = fork();
    if (pid == 0)
    { while(1) 
        {
            char message[100];
            printf('input: ');
            fgets(message, 100, stdin);
            memcpy(shmem, message, sizeof(message));
            printf('child wrote  data successfully: %s\n', shmem);
        }
    }
else
{
    while (1)
        {
            printf(ANSI_COLOR_CYAN 'parent mem data: %s\n' ANSI_COLOR_REST, shmem);
            sleep(1);
        }
    }
}

运行结束,父进程以蓝色输出,子进程以默认颜色输出。

套接字socket

多个进程分布在不同的电脑上,通过网络通信。

Reference

1 Vamei,周昕梓著,树莓派开始玩转Linux,中国工信出版集团,电子工业出版社

相关文章

  • 进程间的通信方式, since 2020-11-02

    进程间的通信方式 (2020.11.02 Mon)进程有其独立性,每个进程的数据停留在自己的进程空间里,互不干涉。...

  • 第二十三章 进程间通信介绍(一)

    本章目标: 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对...

  • Android 面试常问知识

    Q1:线程间的通信进程间通信的几种方式进程间通信方式详解Q2:线程安全SharePreferences 是否线程安...

  • UNIX系统进程间的通信方式

    unix进程间的通信方式

  • 进程间通信方式

    管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字...

  • 进程间通信方式

    概述 进程通信(Interprocess Communication,IPC)是一个进程与另一个进程间共享消息的一...

  • 进程间通信方式

    管道(PIPE):管道是一种半双工的通信方式,数据只能单向流动,一般只能用于父子进程间的通信。 有名管道(name...

  • 进程间通信方式

    01概述 1.1 发展 Linux进程间通信(IPC)大致发展如下: 早期UNIX进程间通信、基于System ...

  • Python Socket 网络编程

    Socket 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络...

  • 知识库 - 收藏集 - 掘金

    Android 进程间通信 AIDL详解 - 掘金最近项目有进程间通信的需求,我使用的是IPC通信的方式,这是An...

网友评论

      本文标题:进程间的通信方式, since 2020-11-02

      本文链接:https://www.haomeiwen.com/subject/aqxbvktx.html