• docker与宿主机共享内存通信


    docker与宿主机共享内存通信

    docker中的进程要与宿主机使用共享内存通信,需要在启动容器的时候指定“–ipc=host”选项。然后再编写相应的共享内存的程序,一个跑在宿主机上,另一个跑在docker上面。

    宿主机程序准备

    • shm_data.h
    #ifndef _SHMDATA_H_HEADER
    #define _SHMDATA_H_HEADER
     
    #define TEXT_SZ 2048
     
    struct shared_use_st
    {
        int written; // 作为一个标志,非0:表示可读,0:表示可写
        char text[TEXT_SZ]; // 记录写入 和 读取 的文本
    };
     
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • shm_slave.c
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "shmdata.h"
     
    int main(int argc, char **argv)
    {
        void *shm = NULL;
        struct shared_use_st *shared = NULL;
        char buffer[BUFSIZ + 1]; // 用于保存输入的文本
        int shmid;
     
        // 创建共享内存
        shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
        if (shmid == -1)
        {
            fprintf(stderr, "shmget failed\n");
            exit(EXIT_FAILURE);
        }
     
        // 将共享内存连接到当前的进程地址空间
        shm = shmat(shmid, (void *)0, 0);
        if (shm == (void *)-1)
        {
            fprintf(stderr, "shmat failed\n");
            exit(EXIT_FAILURE);
        }
     
        printf("Memory attched at %X\n", (int)shm);
     
        // 设置共享内存
        shared = (struct shared_use_st *)shm;
        while (1) // 向共享内存中写数据
        {
            // 数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本
            while (shared->written == 1)
            {
                sleep(1);
                printf("Waiting...\n");
            }
     
            // 向共享内存中写入数据
            printf("Enter some text: ");
            fgets(buffer, BUFSIZ, stdin);
            strncpy(shared->text, buffer, TEXT_SZ);
     
            // 写完数据,设置written使共享内存段可读
            shared->written = 1;
     
            // 输入了end,退出循环(程序)
            if (strncmp(buffer, "end", 3) == 0)
            {
                break;
            }
        }
     
        // 把共享内存从当前进程中分离
        if (shmdt(shm) == -1)
        {
            fprintf(stderr, "shmdt failed\n");
            exit(EXIT_FAILURE);
        }
     
        sleep(2);
        exit(EXIT_SUCCESS);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • makefile
    all:
    	gcc -o shm_slave shm_slave.c
    clean:
    	rm -rf shm_slave
    
    • 1
    • 2
    • 3
    • 4

    docker镜像准备

    • shm_data.h
    #ifndef _SHMDATA_H_HEADER
    #define _SHMDATA_H_HEADER
     
    #define TEXT_SZ 2048
     
    struct shared_use_st
    {
        int written; // 作为一个标志,非0:表示可读,0:表示可写
        char text[TEXT_SZ]; // 记录写入 和 读取 的文本
    };
     
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • shm_master.c
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include "shmdata.h"
     
    int main(int argc, char **argv)
    {
        void *shm = NULL;
        struct shared_use_st *shared; // 指向shm
        int shmid; // 共享内存标识符
        // 将内容写入到文件,可以通过查看文件确定共享内存是否成功
        FILE* file = fopen("t.txt","w+");
     
        // 创建共享内存
        shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);
        if (shmid == -1)
        {
            fprintf(stderr, "shmat failed\n");
            exit(EXIT_FAILURE);
        }
     
        // 将共享内存连接到当前进程的地址空间
        shm = shmat(shmid, 0, 0);
        if (shm == (void *)-1)
        {
            fprintf(stderr, "shmat failed\n");
            exit(EXIT_FAILURE);
        }
     
        printf("\nMemory attached at %X\n", (int)shm);
     
        // 设置共享内存
        shared = (struct shared_use_st*)shm; // 注意:shm有点类似通过 malloc() 获取到的内存,所以这里需要做个 类型强制转换
        shared->written = 0;
        while (1) // 读取共享内存中的数据
        {
            // 没有进程向内存写数据,有数据可读取
            if (shared->written == 1)
            {
                printf("You wrote: %s", shared->text);
                fputs(shared->text,file);
                fflush(file);
                sleep(1);
     
                // 读取完数据,设置written使共享内存段可写
                shared->written = 0;
     
                // 输入了 end,退出循环(程序)
                if (strncmp(shared->text, "end", 3) == 0)
                {
                    break;
                }
            }
            else // 有其他进程在写数据,不能读取数据
            {
                sleep(1);
            }
        }
     
        // 把共享内存从当前进程中分离
        if (shmdt(shm) == -1)
        {
            fprintf(stderr, "shmdt failed\n");
            flcose(file);
            exit(EXIT_FAILURE);
        }
     
        // 删除共享内存
        if (shmctl(shmid, IPC_RMID, 0) == -1)
        {
            fprintf(stderr, "shmctl(IPC_RMID) failed\n");
            fclose(file);
            exit(EXIT_FAILURE);
        }
     	flcose(file);
        exit(EXIT_SUCCESS);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • makefile
    all:
    	gcc -o shm_master shm_master.c
    clean:
    	rm -rf shm_master
    
    • 1
    • 2
    • 3
    • 4
    • Dockerfile
    FROM gcc:latest
    
    RUN  mkdir /usr/src/shm_test
    
    COPY shm_master.c shm_data.h makefile /usr/src/shm_test/
    
    WORKDIR /usr/src/shm_test
    
    RUN  make
    
    CMD ["./shm_master"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    运行

    运行时需要先下载docker,获取支持c语言编译运行的基础镜像,比如ubuntu、gcc等。这里使用gcc作为基础镜像。

    sudo apt install docker
    sudo docker pull gcc
    # 查看一下gcc的镜像是否拉取下来了
    docker images
    
    • 1
    • 2
    • 3
    • 4

    基础镜像有了后就可以基于基础镜像构建docker容器,基于上面所写的dockerfile,构建镜像:

    sudo docker build -t shm_master:v1 .
    # 查看镜像是否创建成功
    sudo docker images
    
    • 1
    • 2
    • 3

    镜像创建成功后就可以启动容器,启动时记得加上参数“–ipc”。

    # fe9c3bd6d102是之前创建成功的镜像的id
    sudo docker run -d --ipc=host --name master fe9c3bd6d102
    
    • 1
    • 2

    成功启动容器后可以进入到容器内部查看通信相关信息。

    sudo docker exec -it master /bin/bash
    
    • 1

    reference

    需要特别说明的是:以下共享内存的代码均来自博客,在此表示感谢。docker镜像创建参考自北极之光的博客

    1. https://www.cnblogs.com/hailun1987/p/9697236.html

    2. https://www.jianshu.com/p/7eb7c7f62bf3

    3. https://www.cnblogs.com/52php/p/5861372.html

  • 相关阅读:
    生成式AI的新战场:逻辑推断与推理计算
    解决MySQL8.0本地计算机上的MySQL服务启动后停止没有报告任何错误
    JBoss漏洞:JBOSS反序列化漏洞合集
    [word] 如何在word中插入地图? #学习方法#其他
    SpringBoot技术在商场应急管理中的创新应用
    5.4 一家人才测评机构低随机抽取的10名小企业的经理人用两种方法进行自信心测试,得到的自信心测试分数如下
    将windows文件夹挂载到linux机器
    Abbexa人猴痘病毒IgM (MPXV IgM) ELISA试剂盒
    【yolov8系列】yolov8的目标检测、实例分割、关节点估计的原理解析
    五. 激光雷达建图和定位方案-开源SLAM
  • 原文地址:https://blog.csdn.net/github_38294679/article/details/122360026