C 中具有共享内存和信号量的客户端服务器程序

Posted

技术标签:

【中文标题】C 中具有共享内存和信号量的客户端服务器程序【英文标题】:Client server program with shared memory and semaphores in C 【发布时间】:2014-05-28 18:58:32 【问题描述】:

我不太了解共享内存的工作原理,我正在尝试编写一个服务器-客户端程序,其中服务器和客户端使用共享内存和信号量相互通信。

共享内存结构:

typedef struct shared_mem
    int board[BOARD_SIZE * BOARD_SIZE];
    int goal;
    int client;
    int direction;
    sem_t sem_server;
shared_mem;
shared_mem *msg;

服务器:

int shmid;
key_t key=ftok("2048_client.c", 42);
if(key == -1) 
        printf("ftok failed");
        return -1;
    
shared_mem *shm;

    if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) 
        perror("shmget");
        exit(1);
    

if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) 
        perror("shmat");
        exit(1);
    

msg=shm;

int direction = -1;
srand(time(NULL));

//SERVER SETS VALUES FOR SHARED MEMORY STRUCTURE

sem_wait(&msg->sem_server);

// setup the board
initialize();

// the board starts with 2 pieces
create_game_piece();
printf("pieces created");
create_game_piece();

msg->client=0;

int i;

for (i = 0; i < BOARD_SIZE * BOARD_SIZE; i++)
    msg->board[i] = board[i];

sem_post(&msg->sem_server);     

// game loop
while (1) 

    //CLIENT READS AND CHANGES VALUES

    //SERVER READS VALUES CHANGED BY CLIENT

    if (!move_board(direction))
        continue;

    sem_wait(&msg->sem_server);
    moves++;
    direction=msg->direction;

    if (check_win()) 
        print_board(-1);
        printf("congratulations! you've won in %d moves\r\n", moves);
        return 0;
    

    create_game_piece();

    if (!has_moves_left()) 
        print_board(-1);
        printf("you lose! try again\r\n");
        //sleep(1);
        return 1;
    
    sem_post(&msg->sem_server); 

客户:

int shmid;
key_t key=ftok("2048_client.c", 42);
if(key == -1) 
        printf("ftok failed");
        return -1;
    
shared_mem *shm;
msg=(shared_mem *)malloc(sizeof(shared_mem));

    if ((shmid = shmget(key, sizeof(msg), IPC_CREAT|0600)) < 0) 
        perror("shmget");
        exit(1);
    

  if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) 
        perror("shmat");
        exit(1);
    

atexit(on_exit2);
system("stty raw");

srand(time(NULL));

while (1) 

    // CLIENT READS VALUES CHANGED BY SERVER AND CHANGES THEM

    sem_wait(&msg->sem_server); 
    print_board(direction);

    direction = keypress();
    msg->direction=direction;
    sem_post(&msg->sem_server); 

有人能告诉我如何协调客户端和服务器访问共享内存的方式,以便它根据代码中的 cmets 工作吗?

【问题讨论】:

【参考方案1】:

SHM_UNLOCK 不会按照你的想法去做。它试图锁定内存中的页面而不是阻止访问。您需要一个信号量来控制对共享内存的访问。请参阅 semctl、semget 等,并在客户端和服务器中使用它们以实现互斥访问。

【讨论】:

添加了信号量,但我仍然认为我做错了什么,因为它仍然无法按预期工作。 我看不到你在哪里创建/初始化信号量。 (1) 客户端和服务器是不相关的 pgms 还是分叉? (2) 你用的是sem_init还是sem_open? 请不要提倡使用 semctl/semget 和朋友 - 他们是“旧界面”。使用较新的 POSIX 接口 sem_init/sem_post/sem_wait,使用起来麻烦很多。 @Klaas van Gend,OP 已经在使用 sysV 共享内存,而我(通常)更喜欢并推荐 posix 接口 sysV 信号量确实具有 posix ipc 系列中不可用的功能。他们不会消失。【参考方案2】:

您的代码有很多问题。

您根本没有初始化信号量。对于此操作, 信号量位于共享内存中,请确保将 pshared 参数设置为非零。 您不能以这种方式仅使用一个信号量进行双向同步 (否则你做一个 sem_post,即立即 sem_waited 进程,因此该线程可能会继续,另一个不会运行)。 您在客户端 malloc'ed msg,从未将其推送到共享内存, 因此共享内存仍未初始化。 您认为 system("stty raw") 除了打开一大堆安全问题之外,还能完成什么? 显然它不是可运行的代码。我已经修复了很多小东西,但半小时后就放弃了,因为它有太多错误。将 char* 与 shared_mem* 进行比较是错误的。在您的编译器上启用 -Wall 和 -Wextra 并修复您收到的所有警告。您的代码充满了它,不幸的是,所有这些都表明存在严重问题。

从设计的角度来看,还有更多的问题。

显然您正在使用服务器中全局的一维数组“板”。这不合适有两个原因:

电路板始终是二维的,为什么不使用二维数组? 您将其用作全局变量,所有函数均可访问。这是“javascript”风格的编程。请将板子本地化为 main 并将其传递给各种功能。

【讨论】:

以上是关于C 中具有共享内存和信号量的客户端服务器程序的主要内容,如果未能解决你的问题,请参考以下文章

具有共享内存和文件作为数据库的 IPC V 客户端/服务器应用程序,用 C 编写

从共享内存段复制数据会导致客户端出现段错误(信号量和共享内存)

如果我使用 select() 服务器而不使用 fork()、线程、共享内存、信号量来编写对等 2 对等应用程序,这可以吗?

C中的基本共享内存程序

在 C/C++ 共享内存中等待和通知

如何在c中制作共享内存?