как я могу 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 вывод:
но я хочу видеть это так, как это делает сервер: