无法访问共享内存的某些部分

时间:2015-01-23 09:10:38

标签: c memory shared

首先,这是作业。我必须编写Pit版本的代码。就我而言,服务器为每个客户端分发9张卡。游戏规则不是很重要,因为我的问题恰好发生在我试图向一个客户提供9张卡时。

我使用共享内存来存储游戏的信息(状态,连接的玩家数量......)和客户的牌。

这是我对共享内存的表示。信息是struct,每张卡都是enum的一部分。

Shared Memory 这是我的问题:我有一个函数initialize_pit(),它使用shm_open()ftruncate()mmap()初始化共享内存。在这个函数之后,接下来会有一个指针:

  • 游戏的信息,
  • 9张卡中的第一张卡,
  • 优惠(我们在此不在乎,因为这是我的代码的下一步)

然后我将服务器上的卡片随机播放到共享内存中,我显示它们(它完美无缺!),我允许客户获取各自的卡片。就我而言,只有一个客户。

客户端能够获取并打印游戏的信息,例如游戏的状态(位于共享内存中),但它尝试获取的所有卡都是0( default int value,imo)。

我无法理解,因为:

  • 我可以从服务器访问游戏的信息卡。
  • 我只能在客户端访问游戏的信息。
  • 这是完全设置指针的相同功能。

我几乎尝试了一切,我真的无法理解发生了什么。抱歉我的英语不好,我希望我已经清楚了。

提前感谢您的帮助。如果我的问题出现问题,请告诉我。

pit_utilities.h

#define MIN_OFFER 1
#define MAX_OFFER 4

#define NB_TYPES 7
#define MAX_CARDS 9

#define MIN_PLAYERS 3
#define MAX_PLAYERS 7

#define CLIENT 0
#define SERVER 1

/*
Enum représentant une carte du jeu
*/
typedef enum {
    WHEAT,
    BARLEY,
    CORN,
    RYE,
    OATS,
    HAY,
    FLAX
} Card;

extern const Card card_map[NB_TYPES];
extern const char* card_string[NB_TYPES];

/*
Enum représentant les états du jeu
*/
typedef enum {
    LOADING,
    GETTING_CARDS,
    PLAYING
} GameState;

/*
Structure représentant un set de cartes (une offre)
*/
typedef struct {
    Card set[NB_TYPES];
    int quantity;
} CardSet;

/*
Structure représentant les informations de la partie
*/
typedef struct {
    int max_players;
    int connected;
    GameState state;
} GameInfo;


void initialize_pit(GameInfo** infos, Card** cards, CardSet** offers, int role);

pit_utilities.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>

#include "pit_utilities.h"

const Card card_map[NB_TYPES] = { WHEAT, BARLEY, CORN, RYE, OATS, HAY, FLAX };
const char* card_string[NB_TYPES] = { "WHEAT", "BARLEY", "CORN", "RYE", "OATS", "HAY", "FLAX" };

void initialize_pit(GameInfo** infos, Card** cards, CardSet** offers, int role)
{
    //Créer la mémoire partagée de la bonne taille, puis le partager avec mmap
    int mem_fd = shm_open("pit", O_CREAT|O_RDWR, S_IRUSR | S_IWUSR);
    int mem_length = sizeof(Card) * MAX_CARDS * (*infos)->max_players + sizeof(GameInfo);
    ftruncate(mem_fd, mem_length);

    void* memory = mmap(NULL, mem_length, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0);

    //récupère pointeur
    GameInfo* infos_p = (GameInfo*) memory;

    //stocke la structure en mémoire partagée
    if(role == SERVER)  
        *infos_p = **infos;

    //modifie le pointeur donné en signature pour qu'il pointe désormais vers la structure en mémoire partagée
    *infos = infos_p;

    *cards = (Card *)(++infos_p);
    *offers = (CardSet*) *cards;
}

server.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <ctype.h>

#include "pit_utilities.h"

void shuffle(Card *array, size_t n);

char *usage = "Usage : ./server [NB_JOUEURS] (3 < NB_JOUEURS < 7)";

void shuffle(Card *array, size_t n) {
    if(n > 1) {
        size_t i;
        for(i = 0; i < n - 1; i++) {
            size_t j = i + rand() / (RAND_MAX / (n - i) + 1);
            Card t = array[j];
            array[j] = array[i];
            array[i] = t;
        }
    }
}

int main(int argc, char *argv[])
{
    srand(time(NULL));
    //Initialiser données du jeu

    if(argc != 2 || !isdigit(argv[1][0])) {
        printf("%s\n", usage);
        exit(EXIT_FAILURE);
    }

    int max_players = atoi(argv[1]);

    if(max_players < MIN_PLAYERS || max_players > MAX_PLAYERS) {
        printf("%s\n", usage);
        exit(EXIT_FAILURE);
    }


    //1. Initialiser la mémoire

    GameInfo* infos = &(GameInfo){max_players, 0, LOADING};
    Card* cards;
    CardSet* offers;

    initialize_pit(&infos, &cards, &offers, SERVER);
    printf("Chargement de la mémoire ok!\n");

    //2. Remplir la mémoire de cartes puis autoriser les clients à récupérer leurs mains

    int i, cards_count = infos->max_players * MAX_CARDS;
    for(i = 0; i < cards_count; i++)
        cards[i] = card_map[i % NB_TYPES];
    shuffle(cards, cards_count);

    printf("\nNombre de joueurs max : %d\n", infos->max_players);
    printf("Nombre de joueurs courant : %d\n", infos->connected);
    printf("Etat du jeu : %d\n\n", infos->state);

    for(i = 0; i < cards_count; i++)
        printf("%7s\t%s", card_string[cards[i]], ((i + 1) % MAX_CARDS == 0) ? "\n" : "");

    infos->state = GETTING_CARDS;

    printf("\nEtat du jeu : %d\n", infos->state);

    //3. Lancer le jeu
    while(1){}
    return 0;
}

client.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <ctype.h>

#include "pit_utilities.h"

void show_hand(Card* cards, int index);

char* actions_menu = 
"ACTIONS:\
-------\
    offrir [QUANTITE][RESSOURCE][...]\
    voir\
    prendre [NUMERO]";

int player_nb;

void show_hand(Card* cards, int index)
{
    int count[NB_TYPES] = { 0 };
    int i;
    for(i = 0; i < MAX_CARDS; i++)
        count[cards[index+i]]++;

    printf("\nVotre main:\n");
    for(i = 0; i < MAX_CARDS; i++)
    {
        if(count[index+i] > 0)
            printf("%d %s\n", count[index+i], card_string[cards[i]]);
    }
}

int main(int argc, char *argv[])
{
    GameInfo* infos;
    Card* cards;
    CardSet* offers;

    printf("Lancement du client...");
    initialize_pit(&infos, &cards, &offers, CLIENT);
    printf("Chargement terminé.\n");

    //Vérifications préalables sur l'état du jeu
    if(infos->max_players == infos->connected)
    {
        printf("La partie est déjà pleine!\n");
        exit(EXIT_FAILURE);
    }
    else if(infos->state != LOADING && infos->state != GETTING_CARDS)
    {
        printf("La partie a déjà démarré!\n");
        exit(EXIT_FAILURE);
    }

    //Ajout à la partie
    player_nb = 0;


    //Attente de la distribution des cartes
    printf("En attente de la distribution des cartes...\n");

    while(infos->state != GETTING_CARDS)
    {
        sleep(1);
    }

    //Récupération des cartes
    show_hand(cards, NB_TYPES * player_nb);

    int i;
    for(i = 0; i < MAX_CARDS * (infos->max_players); i++)
        printf("%7s\t%s", card_string[cards[i]], ((i + 1) % MAX_CARDS == 0) ? "\n" : "");

    //Attente du début de la partie
    printf("En attente du lancement de la partie...\n");
    fflush(stdout);

    while(infos->state != PLAYING)
    {
        sleep(1);
    }


    //Menu
    show_hand(cards, NB_TYPES * player_nb);
    printf("%s", actions_menu);
}

0 个答案:

没有答案