云计算百科
云计算领域专业知识百科平台

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

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

发送进程

代码

#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.h 和 stdlib.h:提供基本的输入/输出功能(如 printf 和 fgets)以及内存管理功能(如 exit)。

  • string.h:提供字符串操作函数,如 strncpy 和 strcmp。

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

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

  • sys/mman.h:包含内存映射相关的函数,如 mmap 和 shm_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;
}

赞(0)
未经允许不得转载:网硕互联帮助中心 » 基于信号量与共享内存实现客户与服务器进程通信
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!