2016-12-10 5 views
0

Мне нужно написать чат-программу в C с помощью сокетов, и я застрял на своем пути.Язык C - Сокеты - Чат между двумя клиентами (с использованием одного сервера как среднего человека)

У меня есть три файла: server, client1, client2. Мой первоначальный план: - Client1 отправляет сообщения на сервер

  • Сервер получает и посылает его в CLIENT2
  • Client2 получает сообщение client1, пишет что-то назад и отправляет его на сервер
  • Сервер получает сообщение CLIENT2 и отправляет его клиенту1
  • Клиент1 получает его и записывает что-то обратно, которое сначала принимается сервером, etc.etc.etc.

Петля заканчивается, когда любой из клиентов отправляет «выход».

Моя проблема в нескольких словах:

  • Первый обмен успешным (Client1 -> Client2, то Client2 к Client1)

  • Однако, после того, как Client2 отправил свое первое сообщение в Client1 , он не ждет ответа Client1. Он пишет «Client1:» с пустой строкой для сообщения, а затем сразу же открывает свое поле «Client2:».

Что, во имя Бога, может быть неправильным здесь?

Client1.c

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 

int compare_strings(char a[], char b[]) 
{ 
    int c = 0; 
    while (a[c] == b[c]) 
    { 
     if (a[c] == '\0' || b[c] == '\0') 
     break; 
     c++; 
    } 
    if (a[c] == '\0' && b[c] == '\0') 
    return 0; 
    else 
    return -1; 
} 


int main() { 
    int clientSocket; 
    char buffer[1024]; 
    struct sockaddr_in serverAddr; 
    socklen_t addr_size; 
    int cmdEXIT = 0; 

    clientSocket = socket(PF_INET, SOCK_STREAM, 0); 

    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(7891); 
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 

    addr_size = sizeof serverAddr; 
    connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size); 

    while (cmdEXIT == 0) 
    { 
     printf("Client 1 : "); 
     scanf(" %[^\n]s", buffer); 
     send(clientSocket,buffer,sizeof buffer - 1,0); 
     if (compare_strings(buffer, "exit")==-1) 
     { 

      memset(&buffer[0], 0, sizeof(buffer)); 

      recv(clientSocket, buffer, sizeof buffer - 1, 0); 
      if (compare_strings(buffer, "exit")==-1) 
      { 
       printf("Client 2 : "); 
       printf("%s\n", buffer); 
       memset(&buffer[0], 0, sizeof(buffer)); 
      } 
      else cmdEXIT=1; 
     } 
     else cmdEXIT=1; 
    } 
    return 0; 
} 

Server.c

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 

int compare_strings(char a[], char b[]) 
{ 
    int c = 0; 
    while (a[c] == b[c]) 
    { 
     if (a[c] == '\0' || b[c] == '\0') 
     break; 
     c++; 
    } 
    if (a[c] == '\0' && b[c] == '\0') 
    return 0; 
    else 
    return -1; 
} 

int main() { 
    int welcomeSocket, newSocket, Client2; 
    struct sockaddr_in serverAddr; 
    struct sockaddr_storage serverStorage; 
    socklen_t addr_size; 

    char buffer[1024]; 

    welcomeSocket = socket(PF_INET, SOCK_STREAM, 0); 

    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(7891); 
    serverAddr.sin_addr.s_addr = inet_addr("127.0.01"); 
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 

    bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); 

    if (listen(welcomeSocket,5)==0) 
     printf("Listening\n"); 
    else 
     printf("Error\n"); 

    addr_size = sizeof serverStorage; 
    newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size); 
    Client2 = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size); 

    int cmdEXIT = 0; 

    while (cmdEXIT == 0) 
    { 
     recv(newSocket, buffer, 1024, 0); 
     printf ("%s\nEnvoie au Client2\n", buffer); 
     send(Client2,buffer,1024,0); 
     if (compare_strings(buffer, "exit")==0) 
     { 
      cmdEXIT = 1; 
     } 
     else 
     { 
      memset(&buffer[0], 0, sizeof(buffer)); 
      recv(Client2, buffer, 1024, 0); 
      printf ("%s\nEnvoie au Client1\n", buffer); 
      send(newSocket,buffer,1024,0); 
      if (compare_strings(buffer, "exit")==0) 
      { 
       cmdEXIT = 1; 
      } 
     } 
    } 

    return 0; 
} 

Client2.c

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 

int compare_strings(char a[], char b[]) 
{ 
    int c = 0; 
    while (a[c] == b[c]) 
    { 
     if (a[c] == '\0' || b[c] == '\0') 
     break; 
     c++; 
    } 
    if (a[c] == '\0' && b[c] == '\0') 
    return 0; 
    else 
    return -1; 
} 

int main() { 
    int clientSocket; 
    char buffer[1024]; 
    struct sockaddr_in serverAddr; 
    socklen_t addr_size; 
    int cmdEXIT = 0; 

    clientSocket = socket(PF_INET, SOCK_STREAM, 0); 

    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(7891); 
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 

    addr_size = sizeof serverAddr; 
    connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size); 


    while (cmdEXIT == 0) 
    { 
     recv(clientSocket, buffer, sizeof buffer - 1, 0); 
     if (compare_strings(buffer, "exit")==-1) 
     { 
      printf("Client 1 : "); 
      printf("%s\n", buffer); 
      memset(&buffer[0], 0, sizeof(buffer)); 

      printf("Client 2 : "); 
      scanf(" %[^\n]s", buffer); 
      send(clientSocket,buffer,sizeof buffer - 1,0); 
      if (compare_strings(buffer, "exit")==-1) 
      { 
       memset(&buffer[0], 0, sizeof(buffer)); 
      } 
      else cmdEXIT = 1; 
     } 

     else cmdEXIT = 1; 
    } 

    return 0; 
} 

Результат в скриншоте:

Client 2 being too bossy and not waiting for his turn to speak

+0

Зачем вам нужен отдельный код для двух клиентов? – e0k

ответ

0

Отказ от ответственности: я сам не запускаю ваш код, поэтому анализ ниже может быть неправильным.

Я рекомендую вам проверить возвращаемое значение recv, которое вернет -1 при ошибке. Если recv сталкивается с ошибкой в ​​этой строке Client2.c: recv(clientSocket, buffer, sizeof buffer - 1, 0); в начале цикла while, буфер останется без изменений.

Таким образом, Клиент 2 не будет ждать сообщения Client 1, и будет просто печатать пустую строку для сообщения от клиента 1.

Позвольте мне знать, если это помогает или вам нужна дополнительная помощь. Если это верно, вы должны убедиться, что соединение не прерывается, между прочим.

+0

Спасибо за помощь! Это не совсем причина проблемы (оказалось, что recv равно 1 в пустых сообщениях), но это помогло мне найти способ заставить клиентов ждать друг друга. Я отправлю решение ниже для тех, кто будет искать ответ на ту же проблему позже. – ALar

0

Итак, как и было обещано в предыдущем комментарии, вот мое решение. Сократить длинный рассказ короткий: каждый раз, когда я проверяю, что такое значение recv.Если оно равно 1, это означает, что сообщения не получено, «линия свободна», и клиент может ввести свое собственное сообщение. В противном случае он должен отобразить полученное сообщение, и только после этого он может отправить свой собственный текст.

Client1.c

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 

//fonction pour comparer deux strings : renvoie 0 si les valeurs sont égales 
//et -1 sinon 

int compare_strings(char a[], char b[]) 
{ 
    int c = 0; 
    while (a[c] == b[c]) 
    { 
     if (a[c] == '\0' || b[c] == '\0') 
     break; 
     c++; 
    } 
    if (a[c] == '\0' && b[c] == '\0') 
    return 0; 
    else 
    return -1; 
} 


int main() { 
    //déclaration des variables 
    int clientSocket; 
    char buffer[1024]; 
    struct sockaddr_in serverAddr; 
    socklen_t addr_size; 
    int cmdEXIT = 0; 

    //paramètrage du socket 
    clientSocket = socket(PF_INET, SOCK_STREAM, 0); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(7891); 
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 
    addr_size = sizeof serverAddr; 

    //connection au serveur 
    connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size); 

    //premier message du Client1 
    printf("Client 1 : "); 
    scanf(" %[^\n]s", buffer); 
    send(clientSocket,buffer,sizeof buffer - 1,0);  

    //continuer à envoyer et recevoir des messages 
    //tant qu'un des clients n'envoive pas "exit" 
    while (cmdEXIT == 0) 
    { 
     //si le message envoyé n'est pas "exit" 
     if (compare_strings(buffer, "exit")==-1) 
     { 
      //vider le buffer 
      memset(&buffer[0], 0, sizeof(buffer)); 
      //la valeur de recv qui est égale a 1 si recv n'a pas 
      //encore reçu de message 
      //sinon, elle est égale au nombre de bits reçu 
      int recvValue = recv(clientSocket, buffer, sizeof buffer - 1, 0); 
      //si recv n'est pas égal a 1 => un message a été reçu 
      if (recvValue != 1) 
      { 
       //si le contenu n'est pas "exit" 
       if (compare_strings(buffer, "exit")==-1) 
       { 
        //afficher le message du Client2 
        printf("Client 2 : "); 
        printf("%s\n", buffer); 
        //vider le buffer 
        memset(&buffer[0], 0, sizeof(buffer)); 
       } 
       //si Client2 a envoyé "exit" 
       else cmdEXIT=1; 
      } 
      //si rcv est égal a 1 => pas de message reçu 
      else 
      { 
       //Client1 peut saisir son message 
       printf("Client 1 : "); 
       scanf(" %[^\n]s", buffer); 
       //et l'envoyer à Client2 
       send(clientSocket,buffer,sizeof buffer - 1,0); 
      } 
     } 
     //sinon finir la boucle 
     else cmdEXIT=1; 
    } 

    return 0; 
} 

Server.c

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 

//fonction pour comparer deux strings : renvoie 0 si les valeurs sont égales 
//et -1 sinon 
int compare_strings(char a[], char b[]) 
{ 
    int c = 0; 
    while (a[c] == b[c]) 
    { 
     if (a[c] == '\0' || b[c] == '\0') 
     break; 
     c++; 
    } 
    if (a[c] == '\0' && b[c] == '\0') 
    return 0; 
    else 
    return -1; 
} 

int main() { 
    //déclaration des variables : Serveur et deux Clients 
    int welcomeSocket, Client1, Client2; 
    struct sockaddr_in serverAddr; 
    struct sockaddr_storage serverStorage; 
    socklen_t addr_size; 
    char buffer[1024]; 

    //paramètrage du Serveur 
    welcomeSocket = socket(PF_INET, SOCK_STREAM, 0); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(7891); 
    serverAddr.sin_addr.s_addr = inet_addr("127.0.01"); 
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 
    bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); 

    //Serveur à l'écoute 
    if (listen(welcomeSocket,5)==0) 
     printf("Listening\n"); 
    else 
     printf("Error\n"); 

    //lier le serveur et les deux clients 
    addr_size = sizeof serverStorage; 
    Client1 = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size); 
    Client2 = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size); 

    int cmdEXIT = 0; 
    //continuer à recevoir et envoyer des messages 
    //tant qu'un des clients n'envoive pas "exit" 
    while (cmdEXIT == 0) 
    { 
     //recevoir le message de Client1 
     recv(Client1, buffer, 1024, 0); 
     //le renvoyer a Client2 
     printf ("%s\nEnvoie au Client2\n", buffer); 
     send(Client2,buffer,1024,0); 
     //sortir de la boucle si Client1 a envoyé "exit" 
     if (compare_strings(buffer, "exit")==0) 
     { 
      cmdEXIT = 1; 
     } 
     //sinon 
     else 
     { 
      //vider le buffer 
      memset(&buffer[0], 0, sizeof(buffer)); 
      //recevoir le message de Client2  
      recv(Client2, buffer, 1024, 0); 
      //le renvoyer a Client1 
      printf ("%s\nEnvoie au Client1\n", buffer); 
      send(Client1,buffer,1024,0); 
      //si Client2 a envoyé "exit" 
      if (compare_strings(buffer, "exit")==0) 
      { 
       cmdEXIT = 1; 
      } 
     } 
    } 

    return 0; 
} 

Client2.c

#include <stdio.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <string.h> 

//fonction pour comparer deux strings : renvoie 0 si les valeurs sont egales et -1 sinon 
int compare_strings(char a[], char b[]) 
{ 
    int c = 0; 
    while (a[c] == b[c]) 
    { 
     if (a[c] == '\0' || b[c] == '\0') 
     break; 
     c++; 
    } 
    if (a[c] == '\0' && b[c] == '\0') 
    return 0; 
    else 
    return -1; 
} 

int main() { 
    //déclaration des variables 
    int clientSocket; 
    char buffer[1024]; 
    struct sockaddr_in serverAddr; 
    socklen_t addr_size; 
    int cmdEXIT = 0; 

    //paramètrage du socket 
    clientSocket = socket(PF_INET, SOCK_STREAM, 0); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_port = htons(7891); 
    serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero); 
    addr_size = sizeof serverAddr; 

    //connection au serveur 
    connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size); 

    //continuer à envoyer et recevoir des messages 
    //tant qu'un des clients n'envoive pas "exit" 
    while (cmdEXIT == 0) 
    { 
     //la valeur de recv qui est égale a 1 si recv n'a pas 
     //encore reçu de message 
     //sinon, elle est egale au nombre de bits reçu 
     int recvValue = recv(clientSocket, buffer, sizeof buffer - 1, 0); 
     //si recv n'est pas égal a 1 => un message a été reçu 
     if (recvValue != 1) 
     { 
      //si le contenu n'est pas "exit"   
      if (compare_strings(buffer, "exit")==-1) 
      { 
       //afficher le message du Client1 
       printf("Client 1 : "); 
       printf("%s\n", buffer); 
       memset(&buffer[0], 0, sizeof(buffer)); 

      } 
      //sinon sortir de la boucle 
      else cmdEXIT = 1; 
     } 
     else 
     { 
      //Client2 peut saisir son message 
      printf("Client 2 : "); 
      scanf(" %[^\n]s", buffer); 
      //Client2 envoie son message au serveur 
      send(clientSocket,buffer,sizeof buffer - 1,0); 
      //si le contenu n'est pas "exit" 
      if (compare_strings(buffer, "exit")==-1) 
      { 
       //vider le buffer 
       memset(&buffer[0], 0, sizeof(buffer)); 
      } 
      //sinon sortir de la boucle 
      else cmdEXIT = 1; 
     } 
    } 
    return 0; 
}