【Linux】之进程间通信

发布时间:2023年12月18日

0x00.概述

本文将基于linux系统介绍进程间通信的几种方式,包括匿名管道,命名管道,systemV的共享内存等,全是干货,无废话

0x01.匿名管道

匿名管道: 通过调用 pipe 函数创建的,它在内存中创建一个缓冲区,用于父子进程之间的通信。这个缓冲区通常是在内核的地址空间中分配的,而不是在文件系统中创建文件。因此,数据通过这个内存缓冲区进行传递,而不涉及真实的文件。匿名管道主要用于相关的父子进程之间的通信。

1.代码实现

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

int main() {
    int pipefd[2];
    pipe(pipefd);

    pid_t child_pid = fork();

    if (child_pid == -1) {
        perror("fork");
        return 1;
    }

    if (child_pid > 0) {
        // Parent Process
        close(pipefd[0]);  // 关闭读取端

        // 向管道写入数据
        const char *message = "Hello, Pipe!";
        write(pipefd[1], message, 13);

        close(pipefd[1]);  // 关闭写入端
    } else {
        // Child Process
        close(pipefd[1]);  // 关闭写入端

        // 从管道读取数据
        char buffer[50];
        read(pipefd[0], buffer, sizeof(buffer));
        printf("Child Process: Received message: %s\n", buffer);

        close(pipefd[0]);  // 关闭读取端
    }

    return 0;
}

2.代码讲解

创建时pipe接收一个输出型参数,创建成功返回fd[0]和fd[1],分别对应管道的读和写端,子进程写父进程读,很好理解。

0x02.命名管道

命名管道:?通过调用 mkfifo 函数创建的,它在文件系统中创建一个特殊类型的文件。当进程使用命名管道进行通信时,数据通过文件系统的路径来传递。尽管文件系统中有一个相关的文件,但实际上,数据仍然是通过内存缓冲区传递的。但与匿名管道不同,命名管道提供了一个在文件系统中可见的标识符,允许独立的进程通过文件路径来访问这个管道

1.代码实现

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

int main() {
    const char *fifoPath = "/tmp/myfifo";

    // 创建命名管道
    mkfifo(fifoPath, 0666);

    // 创建子进程
    pid_t child_pid = fork();

    if (child_pid == -1) {
        perror("fork");
        return 1;
    }

    if (child_pid == 0) {
        // 子进程写入数据到命名管道
        int fd = open(fifoPath, O_WRONLY);
        const char *message = "Hello, FIFO!";
        write(fd, message, strlen(message));
        close(fd);
    } else {
        // 父进程读取数据从命名管道
        int fd = open(fifoPath, O_RDONLY);
        char buffer[100];
        read(fd, buffer, sizeof(buffer));
        printf("Parent Process: Received message: %s\n", buffer);
        close(fd);

        // 等待子进程结束
        wait(NULL);

        // 删除命名管道
        unlink(fifoPath);
    }

    return 0;
}

2代码讲解

int mkfifo(const char *pathname, mode_t mode)

总结:命名管道就是在磁盘上中创建了一个特殊的文件,这个文件可以被打开,但是打开后不会将内存中的数据刷新到磁盘。在磁盘上就有了路径,而路径是唯一的,所以双方就可以通过文件的路径来看到同一份资源,即管道文件。

0x03管道总结

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

2.管道具有通过让进程间协同,提供了访问控制(父子进程会相互协调进行读写操作)

3.管道提供的是面向字节流式的通信服务 --- 面向字节流 --- 通过定制协议实现(父进程多次写入,子进程一次性读取)

4.管道是基于文件的,文件的生命周期是随进程的,即管道的生命周期也随进程的!(数据通过内存缓冲区传递)

5.管道是单向通信的,就是半双工通信的一种特殊方式.(一边写完另一边才能读,类似对讲坤)

0x04.SystemV

1.原理图

2.理解

1.当共享内存创建出来后,通过系统调用挂接到对应的进程当中,操作系统会给进程分配一个mm_struct上的虚拟地址空间(在堆栈之间的共享代码区),通过页表建立与物理内存的映射,从而实现对共享内存的访问

2.共享内存块不属于某个进程,而属于操作系统。

3不同于pipe和fifo通过read,write来进行通信,共享内存属于用户空间,可以直接进行内存级的读和写。

3.实现

实现共享内存间通信分为以下几步:创建共享内存,将进程挂接到共享内存,使用共享内存,分离进程与共享内存,删除共享内存

先引入头文件

创建(create)

shmget()

第一个参数指定相同的key,调用一个类似哈希的算法ftok,求出一个相同的值

第二个参数指定共享内存的大小,一般是4096字节(页的整数倍)

第三个参数:设置选项后还可以加权限,一般是0666

1.IPC_CREATE:创建共享内存,如果底层已经存在,则获取并返回;如果不存在,则创建共享内存然后再返回,

?2.IPC_EXCL:单独使用它没有意义,一般和IPC_CREATE合起来使用,见下:

?3.IPC_CREATE | IPC_EXCL:如果底层不存在,则创建共享内存并返回;如果底层存在,则出错返回。言外之意,如果返回成功,那么一定是一个全新的内存块!

ftok()

一般用项目所在路径名和工程编号生成一个随机值

挂接(attach)

shmat()

函数接受三个参数:

shmid:共享内存段的标识符(ID),即通过调用 shmget() 函数创建共享内存时返回的 shmid。表示你想挂接哪一个共享内存。

shmaddr:共享内存段连接到进程地址空间的首地址。通常将其设置为 NULL,指示系统选择适当的地址。如果想要指定特定的地址,可以传递一个非空的地址值。但不建议这样使用。

shmflg:标志参数,用于指定连接共享内存的选项。常用的选项有:

SHM_RDONLY:以只读方式连接共享内存,不允许写入。
SHM_RND:将 shmaddr 参数忽略,系统选择一个地址以进行连接。

char* shmaddr = (char*)shmat(shmid,nullptr,SHM_RDONLY);

一般需要强转为我们需要的类型?

使用(use)

分离(detach)

shmdt()

成功返回0,失败返回-1?

删除(remove)

手动删除

在终端输入ipcs -m 查看共享内存使用情况

输入ipcrm -m shmid 删除共享内存

代码删除(shmctl)

shmid:共享内存段的标识符(ID),即通过调用 shmget() 函数创建共享内存时返回的 shmid。

cmd:控制命令,用于指定要执行的操作类型。可以使用以下命令之一:

IPC_STAT:获取共享内存段的状态信息,将结果存储在 buf 参数指向的 struct shmid_ds 结构体中。
IPC_SET:设置共享内存段的状态信息,使用 buf 参数中提供的值。
IPC_RMID:删除共享内存段,将其标记为删除状态,并在释放最后一个进程的附加段之后销毁。
buf:一个指向 struct shmid_ds 结构体的指针,用于传递或接收共享内存段的状态信息。
?

    int n = shmctl(shmid,IPC_RMID,nullptr);

?以上就是全部内容,能力有限,如果觉得对你有帮助,请点赞支持一下吧

文章来源:https://blog.csdn.net/m0_73865858/article/details/134958939
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。