当前位置: 首页 > article >正文

基于信号量与共享内存实现客户与服务器进程通信

基于信号量与共享内存实现客户与服务器进程通信

发送进程

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>

#define SHARED_MEM_NAME "/shared_mem"
#define SEM_NAME "/sem_sync"
#define MEM_SIZE 1024
#define END_STRING "END"

int main() {
    int shm_fd;
    void *shared_mem;
    sem_t *sem;

    shm_fd = shm_open(SHARED_MEM_NAME, O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) {
        perror("shm_open failed");
        exit(1);
    }
    ftruncate(shm_fd, MEM_SIZE);

    shared_mem = mmap(0, MEM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_mem == MAP_FAILED) {
        perror("mmap failed");
        exit(1);
    }

    sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(1);
    }

    char buffer[MEM_SIZE];
    while (1) {
        printf("输入字符串:");
        fgets(buffer, MEM_SIZE, stdin);
        buffer[strcspn(buffer, "\n")] = 0;  // 去掉换行符

        strncpy((char *)shared_mem, buffer, MEM_SIZE);

        sem_post(sem);

        if (strcmp(buffer, END_STRING) == 0) {
            break;
        }
    }

    munmap(shared_mem, MEM_SIZE);
    close(shm_fd);
    sem_close(sem);

    return 0;
}

详细解析

0,头文件与宏定义

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>

这些头文件包含了程序中使用的标准库和系统库:

  • stdio.hstdlib.h:提供基本的输入/输出功能(如 printffgets)以及内存管理功能(如 exit)。

  • string.h:提供字符串操作函数,如 strncpystrcmp

  • unistd.h:提供对 POSIX 操作系统 API 的访问,如 close 函数。

  • fcntl.h:用于文件控制操作,如 shm_open 中的标志。

  • sys/mman.h:包含内存映射相关的函数,如 mmapshm_open

  • semaphore.h:提供信号量相关的功能,用于进程同步。

#define SHARED_MEM_NAME "/shared_mem"
#define SEM_NAME "/sem_sync"
#define MEM_SIZE 1024
#define END_STRING "END"
  • SHARED_MEM_NAME:共享内存的名称。名称必须以斜杠 / 开头,以表示这是一个 POSIX 共享内存对象。
  • SEM_NAME:信号量的名称,用于同步客户端和服务器进程。
  • MEM_SIZE:共享内存的大小,以字节为单位。在这里,大小为 1024 字节(1 KB)。
  • END_STRING:用于判断是否结束程序的特殊字符串 “END”。

1,shm_fd

shm_fd = shm_open(SHARED_MEM_NAME, O_CREAT | O_RDWR, 0666);

SHARED_MEM_NAME:共享内存的名称。名称必须以斜杠 / 开头,以表示这是一个 POSIX 共享内存对象,这里我们使用 /shared_mem

shm_open 函数包含在 sys/mman.h 头文件中,用于创建或打开一个 POSIX 共享内存对象。

其中 O_CREAT | O_RDRW 标志如果共享内存对象不存在就创建它,并且以可读可写模式打开它。

2,

0666 为权限设置,表示共享内存对象对所有用户可读可写。

错误处理:如果 shm_open 失败,返回 -1,并通过 perror 打印错误信息,然后调用 exit(1) 终止程序。

2,ftruncate

ftruncate(shm_fd, MEM_SIZE);

3,mmap

    shared_mem = mmap(0, MEM_SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shared_mem == MAP_FAILED) {
        perror("mmap failed");
        exit(1);
    }

设置共享内存对象的大小为 MEM_SIZE 字节,即 1024 字节。

  • mmap:将共享内存映射到进程的地址空间,以便我们可以像使用普通内存一样访问它。
    • 0:让操作系统选择共享内存的映射地址。
    • MEM_SIZE:映射的大小(1024 字节)。
    • PROT_WRITE:指定映射区域可写。
    • MAP_SHARED:其他进程对共享内存的修改是可见的,并且会影响到共享内存的实际内容。
    • shm_fd:共享内存对象的文件描述符。
    • 0:偏移量,表示从共享内存的开头开始映射。
  • 错误处理:如果 mmap 失败,返回 MAP_FAILED,并打印错误信息,然后终止程序。

4,sem_open

sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);
if (sem == SEM_FAILED) {
    perror("sem_open failed");
    exit(1);
}
  • sem_open:创建或打开一个命名信号量。
    • SEM_NAME:信号量的名称。
    • O_CREAT:如果信号量不存在,则创建它。
    • 0666:权限设置,表示信号量对所有用户可访问。
    • 0:信号量的初始值为 0(表示不可用状态)。
  • 错误处理:如果 sem_open 失败,返回 SEM_FAILED,并打印错误信息,然后终止程序。

5,主循环

char buffer[MEM_SIZE];
    while (1) {
        printf("输入字符串:");
        fgets(buffer, MEM_SIZE, stdin);
        buffer[strcspn(buffer, "\n")] = 0;  // 去掉换行符

        strncpy((char *)shared_mem, buffer, MEM_SIZE);

        sem_post(sem);

        if (strcmp(buffer, END_STRING) == 0) {
            break;
        }
    }

从键盘中读入字符串,然后去掉换行符。

strcspn 的作用是找到 \n 的位置,然后该位置换为 \0,表示字符串结尾。

strncpy 表示将 buffer 中的内容复制到 shared_mem 中。

sem_post 表示增加信号量的值,表示共享内存中有新的数据可读,这个操作通知服务器进程可以读取共享内存的内容。

我们重复这个循环,直到输入的字符串为 END 时终止。

6,释放资源

munmap(shared_mem, MEM_SIZE);
close(shm_fd);
sem_close(sem);

munmap : 接触共享内存映射,释放地址空间

close : 关闭共享内存的文件描述符

sem_close : 关闭信号量

接收进程

代码与发送进程类似,故不做解析。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <semaphore.h>

#define SHARED_MEM_NAME "/shared_mem"
#define SEM_NAME "/sem_sync"
#define MEM_SIZE 1024
#define END_STRING "END"

int main() {
    int shm_fd;
    void *shared_mem;
    sem_t *sem;

    shm_fd = shm_open(SHARED_MEM_NAME, O_RDONLY, 0666);
    if (shm_fd == -1) {
        perror("shm_open failed");
        exit(1);
    }

    shared_mem = mmap(0, MEM_SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
    if (shared_mem == MAP_FAILED) {
        perror("mmap failed");
        exit(1);
    }

    sem = sem_open(SEM_NAME, 0);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(1);
    }

    char buffer[MEM_SIZE];
    while (1) {
        sem_wait(sem);

        strncpy(buffer, (char *)shared_mem, MEM_SIZE);
        buffer[MEM_SIZE - 1] = '\0';  // 确保字符串以NULL结尾

        printf("读取字符串:%s\n", buffer);

        if (strcmp(buffer, END_STRING) == 0) {
            break;
        }
    }

    munmap(shared_mem, MEM_SIZE);
    close(shm_fd);
    sem_close(sem);

    return 0;
}

http://www.kler.cn/a/401992.html

相关文章:

  • Seatunnel解决Excel中无法将数字类型转换成字符串类型以及源码打包
  • 【微软:多模态基础模型】(5)多模态大模型:通过LLM训练
  • 移门缓冲支架的工作原理
  • macOS 的目录结构
  • 编译OpenCV的速度,家里和公司的电脑相差很大
  • 京东 2025届秋招 自然语言处理
  • Efficient One-stage Video Object Detection byExploiting Temporal Consistency
  • 数据结构——AVL树
  • python: generator IDAL and DAL using sql server 2019
  • 时间类的实现
  • 【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存
  • sql数据库-权限控制-DCL
  • 第二十四章 TCP 客户端 服务器通信 - 当前 TCP 设备
  • 大公司如何实现打印机共享的?如何对打印机进行管控或者工号登录后进行打印?异地打印机共享的如何实现可以帮助用户在不同地理位置使用同一台打印机完成打印任务?
  • 【LeetCode面试150】——49字母异位分词
  • PHP进阶-CentOS7部署LNMP服务架构的项目
  • 【苍穹外卖】学习日志-day1
  • 网络安全常见练习靶场
  • 使用ajax-hook修改http请求响应数据,篡改后再返回给正常的程序
  • 【Docker】快速部署 Pikachu:一个包含常见 Web 安全漏洞的渗透测试练习靶场
  • C++系列之继承
  • 数学分组求偶数和
  • Ubuntu 20.04 默认的软件包源中可能不包含 gcc-11 和 g++-11
  • SOC Boot学习(二)——JTAG Debug介绍
  • LPDDR4芯片学习(四)——DDR Training
  • uniApp项目运行到鸿蒙手机,应用图标一直是H,应用名一直是HBuilder问题