【问题标题】:One Process per Client Server using Shared Memory in C每个客户端服务器一个进程使用 C 中的共享内存
【发布时间】:2017-09-22 10:02:46
【问题描述】:

出于学术目的,我正在使用 TCP 协议创建一个“每个客户端一个进程”服务器。

我使用如下所示的全局结构:

struct keyvalue
    {
        char a[4096];
        char b[4096];
    }data[1000];

我使用 fork() 为每个客户创建一个孩子。

我知道每个孩子都将此结构视为父进程的精确副本,但是如果一个孩子进行了更改,其他孩子将看不到它,这是我的目标。

我在谷歌搜索了几个小时,我发现唯一合适的解决方案是 mmap()

下面我将介绍我如何尝试解决此任务:

int main ( int argc, char *argv[])
{
for(int c = 0; c < 1000 ; c++)
    {
        data[c] = mmap(NULL, sizeof(data[c]), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

    }
.
.
.
return 0;
}

但是我认为我没有正确理解这个函数的使用,并且文档对这个项目没有帮助。

如果有人向我解释在我的项目中使用此功能的确切方法,那就太好了。 编辑:

这个全局结构被两个全局函数使用:

void put(char *key, char *value)
{
.
.
.       
strcpy(data[lp].keys,key);
strcpy(data[lp].values,value);
.
.
.   
}

谢谢你的表现,对不起我的英语不好。

【问题讨论】:

  • 这个结构数组应该对所有进程可见?你会考虑使用 pthreads 吗?
  • @k_kaz 是的,它应该对所有进程都可见。因为它是一个服务器,所以每个进程(客户端)都必须有权访问这个结构。我不能使用 pthreads,因为它是出于学术目的并且说明很严格。

标签: c linux tcp server mmap


【解决方案1】:

您可以使用以下代码创建一个结构数组,该数组在多个分叉进程之间共享。

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

#define MAX_LEN 10000

struct region {
        int len;
        char buf[MAX_LEN];

};

int fd;

int main(void){

        //Create shared memory
        fd = shm_open("/myregion", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
        if (fd == -1)
                printf("Error: shm_open\n");

        //Expand to meet the desirable size
        if (ftruncate(fd, MAX_LEN*sizeof(struct region)) == -1)
                printf("Error: ftruncate\n");



        pid_t pid = fork();
        if (pid == 0){
                struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
                if (ptr == MAP_FAILED)
                        printf("Error\n");


                memset(ptr, 0, 50*sizeof(struct region));
                usleep(1500000);
                ptr[33].len = 42;

        }else if (pid > 0){
                struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
                if (ptr == MAP_FAILED)
                        printf("Error\n");


                usleep(1000000);
                printf("Value before: %d\n", ptr[33].len);
                usleep(1000000);
                printf("Value after: %d\n", ptr[33].len);

        }else{
                printf("Error: fork\n");
        }

        shm_unlink("/myregion");

        return 0;
}

编译:gcc -o shmem_test shmem_test.c -lrt

编辑:如果您不能使用 shm_open,或者您可以在主函数中执行以下操作:

int main(void){

        struct region * ptr = mmap(NULL, MAX_LEN*sizeof(struct region), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED,-1,0);
        pid_t pid = fork();
        if (pid == 0){

                usleep(1500000);
                ptr[33].len = 42;

        }else if (pid > 0){

                usleep(1000000);
                printf("Value before: %d\n", ptr[33].len);
                usleep(1000000);
                printf("Value after: %d\n", ptr[33].len);

        }else{
                printf("Error: fork\n");
        }

        return 0;
}

两者的区别在于 shm_open 创建了一个命名共享内存,这意味着不同可执行文件中的不同进程可以映射这块内存,前提是它们具有 struct region 定义。在第二种情况下,这是无法做到的,即共享内存是匿名的。

【讨论】:

  • 在这种情况下,结构体的大小是多少?我的目标是创建 1000 个该结构的实例,以便服务器保存客户端发送的一些数据。这就是我使用 data[1000] 的原因
  • @ArisKantas 将 MAX_LEN 更改为所需的大小。初始化不是通过变量声明,而是通过 ftruncate
  • 你能解释一下这个编译错误:在函数main': serv2.c:(.text+0x310): undefined reference to shm_open'collect2:错误:ld返回1退出状态
  • 将 -lrt 添加到您的 gcc 命令中。 shm_open 是外部库中的一个函数。我编辑了答案以添加编译命令。
  • @k_kat 如果我有 2 个必须在全局结构中读/写的函数怎么办?自从我在 main 中创建结构后,他们怎么知道我正在谈论的结构?
猜你喜欢
  • 2020-03-22
  • 2018-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-10
相关资源
最近更新 更多