Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/EmptyTag/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过TCP/IP将2D阵列从服务器发送到客户端,并将其打印为棋盘_C_Sockets_Matrix_Multidimensional Array_Tcp - Fatal编程技术网

通过TCP/IP将2D阵列从服务器发送到客户端,并将其打印为棋盘

通过TCP/IP将2D阵列从服务器发送到客户端,并将其打印为棋盘,c,sockets,matrix,multidimensional-array,tcp,C,Sockets,Matrix,Multidimensional Array,Tcp,如何将2D数组从服务器发送到客户端,就像他们下棋一样 这是我的server.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]; } Clien

如何将2D数组从服务器发送到客户端,就像他们下棋一样

这是我的server.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;
}
这是我的client.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);
}
这是client.c输出:

但我想看到的是服务器所做的:

我怎么修理?
我不知道这会不会是你的真实答案。但这样做并不是一个网站要做的功课。因此,这篇文章是对这个问题的一般性回答。正如您已经使用的套接字一样,您可能知道,TCP协议以位的八位字节发送和接收数据。在大多数现代系统中,字节是位的八位字节。因此,一般来说,TCP以字节的形式发送/接收数据。在C编程语言中,字符串表示一系列字节,在一系列字节的末尾为零

因此,您可以将数据作为C字符串发送。以C语言中的二维数组为例,它当然可以表示为一维数组。鉴于:

0 1
2 3
可以表示为0 1 2 3。将一维索引转换为二维索引的常用公式为:

index = row_position + row_length * column_position
继续。取0 1 2 3的一维级数。对于2x2棋盘,2值的索引为2

2 = 0 + 2 * 1 == 2
^   ^   ^   ^
|   |   |   |
I  RP  RL  CP
其中I是索引,RP是行位置,RL是行长度,CP是列位置。现在您可以用上面的方法对棋盘进行编码,您可以发送棋盘数据了。例如,您可以这样发送:0 1 2 3。。。20 21 22.
完成后,您可以接收数据并对其进行解码。祝大家好运

@1071;öСааааааааааааа。需要帮助如果你认为答案确实解决了你的问题,你应该将其标记为已接受。这样,其他人就会知道这个解决方案确实有效。@ItsGhost还使用信号函数接口处理信号有一些缺点。我不记得实际的问题了。可能是比赛状态,或者是其他与你同时出现的信号,或者是阻塞选择呼叫。如果您有空闲时间,您可以查看sigprocmask及其友元函数。由于您已经处理了套接字,因此使用sigaddset注册信号并检查服务器/客户机事件循环中的信号到达更加方便和准确。这样,您可以在逻辑所在的同一位置处理信号。这还有一个优点,即在终止/重新启动/停止应用程序之前可以执行更多逻辑。单纯的信号不允许在信号处理程序中进行复杂的操作,但如果您将使用select/poll/epoll捕捉信号,则可以正确终止程序。正如我所说,所有的逻辑都停留在一个地方。