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

C语言中具有共享内存和信号量的客户机-服务器程序,c,client-server,posix,semaphore,shared-memory,C,Client Server,Posix,Semaphore,Shared Memory,我真的不明白共享内存是如何工作的,我正在尝试编写一个服务器-客户机程序,其中服务器和客户机使用共享内存和信号量相互通信 共享内存结构: 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 shmi

我真的不明白共享内存是如何工作的,我正在尝试编写一个服务器-客户机程序,其中服务器和客户机使用共享内存和信号量相互通信

共享内存结构:

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\u t key=ftok(“2048\u client.c”,42);
如果(键==-1){
printf(“ftok失败”);
返回-1;
}
共享内存*shm;
如果((shmid=shmget(键,大小(msg),IPC|u CREAT | 0600))<0){
佩罗尔(“shmget”);
出口(1);
}
如果((shm=shmat(shmid,NULL,0))==(char*)-1){
佩罗尔(“shmat”);
出口(1);
}
msg=shm;
int方向=-1;
srand(时间(空));
//服务器为共享内存结构设置值
sem\u等待(&msg->sem\u服务器);
//设置电路板
初始化();
//这块板从两块开始
创建游戏片();
printf(“创建的作品”);
创建游戏片();
msg->client=0;
int i;
对于(i=0;iboard[i]=board[i];
sem_post(&msg->sem_服务器);
//游戏循环
而(1){
//客户端读取和更改值
//服务器读取客户端更改的值
如果(!移动_板(方向))
继续;
sem\u等待(&msg->sem\u服务器);
移动++;
方向=味精->方向;
如果(勾选_win()){
印刷电路板(-1);
printf(“祝贺您!您赢得了%d个移动\r\n”,移动);
返回0;
}
创建游戏片();
如果(!has_moves_left()){
印刷电路板(-1);
printf(“您输了!再试一次\r\n”);
//睡眠(1);
返回1;
}
sem_post(&msg->sem_服务器);
}
客户:

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); 
}
int-shmid;
key\u t key=ftok(“2048\u client.c”,42);
如果(键==-1){
printf(“ftok失败”);
返回-1;
}
共享内存*shm;
msg=(共享内存*)malloc(sizeof(共享内存));
如果((shmid=shmget(键,大小(msg),IPC|u CREAT | 0600))<0){
佩罗尔(“shmget”);
出口(1);
}
如果((shm=shmat(shmid,NULL,0))==(char*)-1){
佩罗尔(“shmat”);
出口(1);
}
atexit(退出时2);
系统(“stty raw”);
srand(时间(空));
而(1){
//客户端读取服务器更改的值并对其进行更改
sem\u等待(&msg->sem\u服务器);
印刷电路板(方向);
方向=按键();
msg->direction=方向;
sem_post(&msg->sem_服务器);
}

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

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

您的代码有很多错误

  • 您根本没有初始化信号量。对于此操作 信号量位于共享内存中,请确保将pshared参数设置为非零
  • 通过这种方式,您不能仅使用一个信号量进行双向同步 (否则,你会发布一个sem_post,也就是说,sem_会立即在同一个网站上等待 进程,因此该线程可以继续,而另一个线程无法运行)
  • 您在客户机中malloc'msg,但从未将其推送到共享内存中, 因此,共享内存仍然没有初始化
  • 您认为系统(“STTYRAW”)除了打开一个严重的安全问题大罐之外,还能实现什么
  • 显然,它不是可运行的代码。我已经解决了很多小问题,但半小时后就放弃了,因为问题太多了。将char*与shared_mem*进行比较是错误的。在编译器上启用-Wall和-Wextra并修复所有警告。您的代码中充满了它,不幸的是,所有这些都表明存在严重问题
从设计的角度来看,还有更多的问题

显然,您使用的是服务器中全局的一维阵列“板”。这是不合适的,原因有二:

  • 电路板始终是二维的,为什么不使用二维阵列呢
  • 您可以将其用作全局变量,所有函数都可以访问它。这是“javascript”风格的编程。请将电路板设置为main本地,并将其传递给各个功能

添加了信号量,但我仍然认为我做错了什么,因为它仍然无法按预期工作。我看不出在哪里创建/初始化信号量。(1) 客户机和服务器是无关的PGM还是分叉的?(2) 您使用的是sem_init还是sem_open?请不要使用semctl/semget和friends,它们是“旧接口”。使用较新的POSIX接口sem_init/sem_post/sem_wait,使用起来不那么麻烦。@Klaas van Gend,OP已经在使用sysV共享内存,而我(通常)更喜欢并推荐POSIX接口sysV信号量,但它确实具有POSIX ipc系列中不可用的功能。他们不会离开的。