Отправка 2D-массива с сервера на клиент через TCP / IP и распечатка в виде шахматной доски - PullRequest
0 голосов
/ 16 февраля 2020

как я могу send 2D-массив с Сервера на Клиента (ов), как если бы они играли в шахматы?

Это мой сервер. c Файл:

// MAPPA
#define RIGHE 5
#define COLONNE 5



// STRUTTURA DATI
typedef struct ClientNode {
    int data;
    struct ClientNode* prev;
    struct ClientNode* next;
    char ip[16];
    char name[31];
} ClientList;


// Global variable
int serverSocket = 0, clientSocket = 0;
ClientList *top, *lastAdded;
int clientDisconnessi = 0;
char mappa[RIGHE][COLONNE];

void setupMap(char[][COLONNE]);
void setDestinationOnMap(char[][COLONNE]);
void setObstaclesOnMap(char[][COLONNE]);
void setPackagesOnMap(char[][COLONNE]);
void printMap(char[][COLONNE]);
void hideObstacles(char);
int getNumberOfPackages(char[][COLONNE]);
int getNumberOfObstacles(char[][COLONNE]);
void catch_ctrl_c_and_exit(int);
void sent_to_all_clients(ClientList*, char*);
void client_handler(void*);
int countNumberOfClientsConnected(ClientList*);
void whoIsOn(ClientList*);
int isNotACommand(char*);
ClientList *creaNuovoNodo(int, char*);

int main()
{

    setupMap(mappa);

    // Associa come handler del comando CTRL-C la funzione catch_ctrl_c_and_exit
    signal(SIGINT, catch_ctrl_c_and_exit);

    // Creazione socket
    serverSocket = socket(AF_INET , SOCK_STREAM , 0);
    if (serverSocket == -1) {
        printf("Fail to create a socket.");
        exit(1);
    }

    // Socket information
    struct sockaddr_in server_info, client_info;
    int s_addrlen = sizeof(server_info);
    int c_addrlen = sizeof(client_info);
    memset(&server_info, 0, s_addrlen);
    memset(&client_info, 0, c_addrlen);
    server_info.sin_family = PF_INET;
    server_info.sin_addr.s_addr = INADDR_ANY;
    server_info.sin_port = htons(8888);

    // Binding
    if (bind(serverSocket, (struct sockaddr *) &server_info, s_addrlen) == -1) {
        perror("Errore binding");
        exit(1);
    }

    // Imposta all'ascolto
    if (listen(serverSocket, 5) == -1) {
        perror("Errore listening");
        exit(1);
    }

    // Visualizzare indirizzo IP del server
    getsockname(serverSocket, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
    printf("Start server on: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));

    // Lista doppiamente concatenata per i client che contiene come primo nodo le informazioni sul server
    top = creaNuovoNodo(serverSocket, inet_ntoa(server_info.sin_addr));
    lastAdded = top;

    while (1) {

        clientSocket = accept(serverSocket, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
        if (clientSocket == -1) {
            perror("Errore accept");
            exit(1);
        }

        // Visualizzare l'indirizzo IP del client
        getpeername(clientSocket, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
        printf("Client %s:%d come in.\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));

        // Inserimento (append) nella linked list dei client
        ClientList *client = creaNuovoNodo(clientSocket, inet_ntoa(client_info.sin_addr));
        client->prev = lastAdded;
        lastAdded->next = client;
        lastAdded = client;

        pthread_t tid;
        if (pthread_create(&tid, NULL, (void *) client_handler, (void *) client) != 0) {
            perror("Create pthread error!\n");
            exit(1);
        }
    }

    return 0;
}

void catch_ctrl_c_and_exit(int sig)
{
    ClientList *tmp;

    while (top != NULL) {
        printf("\nClose socketfd: %d\n", top->data);
        close(top->data); // close all socket include server_sockfd
        tmp = top;
        top = top->next;
        free(tmp);
    }

    printf("Hai spento il server\n");

    exit(0);
}

void send_to_all_clients(ClientList *client, char messageToBeSent[LENGTH_SEND])
{
    ClientList *tmp = top->next;


    while (tmp != NULL) {
        if (client->data != tmp->data) { // notifica tutti i client ad eccezione di se stesso
            printf("Send to sockfd %d: \"%s\" \n", tmp->data, messageToBeSent);
            if (send(tmp->data, messageToBeSent, LENGTH_SEND, 0) == -1 ){ // invia LENGTH_SEND byte di messageToBeSent a tmp->data il quale contiene il filedescriptor per un client
                perror("Errore nell'invio del messaggio");
                exit(1);
            }
        }

        tmp = tmp->next;
    }

}

void client_handler(void *p_client)
{
    int hasLeftTheChatroom = 0;
    char nickname[LENGTH_NAME] = ""; // ricevuto tramite il send da parte del client
    char receivedMessage[LENGTH_MSG] = "";
    char messageToBeSent[LENGTH_SEND] = "";
    char mapToBeSent[RIGHE][COLONNE];
    ClientList *client = (ClientList *) p_client;

    // Conversazione
    while (1) {

        if (hasLeftTheChatroom) {
            break;
        }

        int receive = recv(client->data, receivedMessage, LENGTH_MSG, 0);
        if (receive > 0) {

            if (strlen(receivedMessage) == 0) {
                continue;
            }

            // Impacchetta quelle informazioni nella stringa messageToBeSent
            sprintf(messageToBeSent, "-%s (%s): %s", client->name, client->ip, receivedMessage);




            // TODO: 
            if (strcmp(receivedMessage, ":map") == 0) {
                char escape = '\n';
                for (int i = 0; i < RIGHE; i++) {
                    for (int j = 0; j < COLONNE; j++) {
                        if (send(client->data, &mappa[i][j], LENGTH_SEND, 0) == -1) {
                            perror("Errore nell'invio");
                            exit(1);
                        }
                    }
                }
            }


        }

        else {
            printf("Fatal Error: -1\n");
            hasLeftTheChatroom = 1;
        }

        if (isNotACommand(receivedMessage)) // Se il messaggio ricevuto non è un comando (tranne :exit)
            send_to_all_clients(client, messageToBeSent);

    }

    // Rimozione di un nood dalla lista
    close(client->data);
    if (client == lastAdded) { // remove an edge node
        lastAdded = client->prev;
        lastAdded->next = NULL;
    } else { // remove a middle node
        client->prev->next = client->next;
        client->next->prev = client->prev;
    }

    free(client);
}

/* Conta il numero di client attualmente connessi */
int countNumberOfClientsConnected(ClientList *client)
{
    ClientList *tmp = client;
    int count = 0;

    while (tmp != NULL) {
        count++;
        tmp = tmp->next;
    }

    return count;
}

/* Restituisce vero se il messaggio ricevuto non è un comando (eccezion fatta per :exit) */
int isNotACommand(char *receivedMessage)
{
    return (strcmp(receivedMessage, ":howManyOn") != 0 && strcmp(receivedMessage, ":howManyOff") != 0 
                    && strcmp(receivedMessage, ":who") != 0);
}

/* Predispone la mappa */
void setupMap(char mappa[][COLONNE])
{

    //memset(mappa, ' ', sizeof mappa); oppure . . .
    for (int i = 0; i < RIGHE; i++) {
        for (int j = 0; j < COLONNE; j++) {
            mappa[i][j] = ' ';
        }
    }

    setDestinationOnMap(mappa);

    setObstaclesOnMap(mappa);

    setPackagesOnMap(mappa);

    printMap(mappa);

}

/* Posiziona la destinazione del gioco in un punto qualsiasi della mappa */
void setDestinationOnMap(char mappa[][COLONNE])
{
    int rigaDestinazione, colonnaDestinazione;

    srand(time(NULL)); // Randomizza numeri

    rigaDestinazione = rand() % RIGHE;
    colonnaDestinazione = rand() % COLONNE;

    mappa[rigaDestinazione][colonnaDestinazione] = 'D';
}

/* Posiziona gli ostacoli sulla mappa in posizioni casuali */
void setObstaclesOnMap(char mappa[][COLONNE])
{
    int rigaOstacolo, colonnaOstacolo;
    int numeroMassimoDiOstacoli = RIGHE * COLONNE * 1/5;

    srand(time(NULL));

    for (int times = 0; times < numeroMassimoDiOstacoli; times++) { 

        rigaOstacolo = rand() % RIGHE;
        colonnaOstacolo = rand() % COLONNE;

        if (mappa[rigaOstacolo][colonnaOstacolo] != 'D')
            mappa[rigaOstacolo][colonnaOstacolo] = '*';
        /*else 
            printf("Ho trovato una coincidenza, infatti %c = 'D' cioè mappa[%d][%d]\n", mappa[rigaOstacolo][colonnaOstacolo], rigaOstacolo, colonnaOstacolo);*/

    }
}

/* Posiziona i pacchi sulla mappa */
void setPackagesOnMap(char mappa[][COLONNE])
{
    int rigaPacco, colonnaPacco;
    int numeroMassimoDiPacchi = RIGHE * COLONNE * 1/2;

    srand(time(NULL));

    for (int times = 0; times < numeroMassimoDiPacchi; times++) {

        rigaPacco = rand() % RIGHE;
        colonnaPacco = rand() % COLONNE;

        if (mappa[rigaPacco][colonnaPacco] != 'D' && mappa[rigaPacco][colonnaPacco] != '*')
            mappa[rigaPacco][colonnaPacco] = 'P';
        /*else 
            printf("Ho trovato una coincidenza, infatti %c = '*' oppure 'D' cioè mappa[%d][%d]\n", mappa[rigaPacco][colonnaPacco], rigaPacco, colonnaPacco);*/

    }
}

/* Visualizza la mappa sullo schermo */
void printMap(char mappa[][COLONNE])
{
    for (int i = 0; i < RIGHE; i++) {
        for (int j = 0; j < RIGHE; j++) {
            printf("[ %c ]", mappa[i][j]);
            //hideObstacles(mappa[i][j]); 
        }
        printf("\n");
    }
}

/* Nasconde gli ostacoli e colora l'obiettivo in verde */
void hideObstacles(char cella)
{
    if (cella == 'D')
        printf(ANSI_COLOR_GREEN "[ %c ]" ANSI_COLOR_RESET, cella); // Colora in verde l'obiettivo
    else if (cella != '*')
        printf("[ %c ]", cella);
    else
        printf("[   ]");
}

/* Restituisce il numero di pacchi presenti sulla mappa */
int getNumberOfPackages(char mappa[][COLONNE])
{
    int number = 0;

    for (int i = 0; i < RIGHE; i++) {
        for (int j = 0; j < COLONNE; j++) {
            if (mappa[i][j] == 'P')
            number++;
        }
    }

    return number;
}

/* Restituisce il numero di ostacoli presenti sulla mappa */
int getNumberOfObstacles(char mappa[][COLONNE])
{
    int number = 0;

    for (int i = 0; i < RIGHE; i++) {
        for (int j = 0; j < COLONNE; j++) {
            if (mappa[i][j] == '*')
            number++;
        }
    }

    return number;
}

ClientList *creaNuovoNodo(int sockfd, char* ip)
{
    ClientList *p = (ClientList *) malloc(sizeof(ClientList));

    p->data = sockfd;

    p->prev = NULL;
    p->next = NULL;

    strncpy(p->ip, ip, 16);
    strncpy(p->name, "NULL", 5);

    return p;
}

и это мой клиент. c файл:

// Global variables
volatile sig_atomic_t hasLeftTheChat = 0;
int clientSocket = 0;
char nickname[LENGTH_NAME];

void catch_ctrl_c_and_exit(int);
void recv_msg_handler();
void send_msg_handler();
void str_trim_lf (char*, int);
void str_overwrite_stdout();

int main()
{
    // Associa come handler del segnale CTRL-C la funzione catch...
    signal(SIGINT, catch_ctrl_c_and_exit);

    // Creazione della socket
    clientSocket = socket(AF_INET , SOCK_STREAM , 0);
    if (clientSocket == -1) {
        printf("Fail to create a socket.");
        exit(1);
    }

    // Socket information
    struct sockaddr_in server_info, client_info;
    int s_addrlen = sizeof(server_info);
    int c_addrlen = sizeof(client_info);
    memset(&server_info, 0, s_addrlen);
    memset(&client_info, 0, c_addrlen);
    server_info.sin_family = PF_INET;
    server_info.sin_addr.s_addr = inet_addr("127.0.0.1");
    server_info.sin_port = htons(8888);

    // Connect to Server
    if (connect(clientSocket, (struct sockaddr *)&server_info, s_addrlen) == -1) {
        printf("Connection to Server error!\n");
        exit(1);
    }

    // Richiesta nome
    printf("Please enter your name: ");
    if (fgets(nickname, LENGTH_NAME, stdin) != NULL) {
        str_trim_lf(nickname, LENGTH_NAME);
    }
    if (strlen(nickname) < 2 || strlen(nickname) >= LENGTH_NAME-1) {
        printf("\nName must be more than one and less than thirty characters.\n");
        exit(1);
    }

    // Names
    getsockname(clientSocket, (struct sockaddr*) &client_info, (socklen_t*) &c_addrlen);
    getpeername(clientSocket, (struct sockaddr*) &server_info, (socklen_t*) &s_addrlen);
    printf("Connect to Server: %s:%d\n", inet_ntoa(server_info.sin_addr), ntohs(server_info.sin_port));
    printf("You are: %s:%d\n", inet_ntoa(client_info.sin_addr), ntohs(client_info.sin_port));

    // Invio dei dati al server
    if (send(clientSocket, nickname, strlen(nickname), 0) == -1) {
        perror("Errore con l'invio del nickname al server");
        exit(1);
    }

    // Creazione del thread relativo alla funzione send_msg_handler per l'invio dei messaggi
    pthread_t send_msg_thread;
    if (pthread_create(&send_msg_thread, NULL, (void *) send_msg_handler, NULL) != 0) {
        printf ("Create pthread error!\n");
        exit(1);
    }

    // Creazione del thread relativo alla funzione recv_msg_handler per la ricezione dei messaggi
    pthread_t recv_msg_thread;
    if (pthread_create(&recv_msg_thread, NULL, (void *) recv_msg_handler, NULL) != 0) {
        printf ("Create pthread error!\n");
        exit(1);
    }

    while (1) {
        if(hasLeftTheChat) {
            printf("\nHai abbandonato la chat.\n");
            break;
        }
    }

    close(clientSocket);

    return 0;
}

void catch_ctrl_c_and_exit(int sig)
{
    hasLeftTheChat = 1;
}

void recv_msg_handler()
{

    char receivedMessage;

    while (1) {
        // Riceve i dati dal server
        if ( recv(clientSocket, &receivedMessage, LENGTH_SEND, 0) <= 0) {
            perror("[-]Error in receiving data from server\n");
            break;
        }
        else {
            printf("\r[ %c ]\n", receivedMessage);
            str_overwrite_stdout();
        }
    }

}

void send_msg_handler()
{
    char messageToBeSent[LENGTH_MSG] = {};

    while (1) {
        str_overwrite_stdout();

        while (fgets(messageToBeSent, LENGTH_MSG, stdin) != NULL) {

            str_trim_lf(messageToBeSent, LENGTH_MSG);

            if (strlen(messageToBeSent) == 0) 
                str_overwrite_stdout();

            else 
                break;

        }

        // Invio dei dati al server
        if (send(clientSocket, messageToBeSent, LENGTH_MSG, 0) == -1) {
            perror("Errore con l'invio del messaggio");
            exit(1);
        }

        if (strcmp(messageToBeSent, ":exit") == 0) {
            break;
        }

    }

    catch_ctrl_c_and_exit(2);

}

void str_trim_lf (char* arr, int length) {
    int i;
    for (i = 0; i < length; i++) { // trim \n
        if (arr[i] == '\n') {
            arr[i] = '\0';
            break;
        }
    }
}

void str_overwrite_stdout() {
    printf("\r%s", "> ");
    fflush(stdout);
}

Это клиент. c вывод:

client

но я хочу видеть это так, как это делает сервер:

enter image description here

  • Как мне исправить?

1 Ответ

1 голос
/ 16 февраля 2020

Я не знаю, это будет реальный ответ для вас. Но SO не сайт для домашней работы. Так что пост является ответом на вопрос в общем виде. Как вы уже использовали сокеты, вы, вероятно, знаете, что протокол TCP отправляет и получает данные в октетах битов. В большинстве современных систем байт является октетом битов. Таким образом, в общем случае TCP отправляет / получает данные в байтах. В C языке программирования строки представляют собой серию байтов с нулем в конце серии.

Таким образом, вы можете отправлять данные как C строка. Возьмите двумерный массив в C. Это, конечно, можно представить как одномерный. Дано:

0 1
2 3

Может быть представлено как 0 1 2 3. Обычная формула для преобразования одномерного индекса в двумерный:

index = row_position + row_length * column_position

Продолжить. Возьмите одномерные серии 0 1 2 3. Значение 2 имеет индекс 2 для шахматной доски 2x2.

2 = 0 + 2 * 1 == 2
^   ^   ^   ^
|   |   |   |
I  RP  RL  CP

Где I - индекс, RP - позиция строки, RL - длина строки, CP - положение столбца. Теперь, когда вы можете кодировать свою шахматную доску описанным выше способом, вы можете отправлять данные шахматной доски. Например, вы можете отправить его так: 0 1 2 3 ... 20 21 22. После этого вы можете получить свои данные и декодировать их. Wi sh вам всем везет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...