通过TCP/IP将2D阵列从服务器发送到客户端,并将其打印为棋盘
如何将2D数组从服务器发送到客户端,就像他们下棋一样 这是我的server.c文件:通过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
// 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捕捉信号,则可以正确终止程序。正如我所说,所有的逻辑都停留在一个地方。