1

I need to write a chat program in C using sockets and I got stuck on my way.

I have three files: server, client1, client2. My initial plan: - Client1 sends the messages to server

  • Server receives it and sends it to Client2
  • Client2 receives Client1's message, writes something back and sends it to server
  • Server receives Client2's message and sends it to Client1
  • Client1 receives it and writes something back which is firstly received by server, etc.etc.etc.

The loop ends when either of the clients sends "exit".

My problem in a few words:

  • The first exchange is successful (Client1 -> Client2, then Client2 to Client1)

  • However, after Client2 has sent its first message to Client1, he doesn't wait for Client1's response. He writes "Client1 : " with an empty line for the message and then immediately opens his own "Client2 : " message field.

What in God's name can be wrong here?

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;
}

Result in a screenshot:

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

ALar
  • 31
  • 1
  • 3

2 Answers2

2

So, as promised in the previous comment, here is my solution. To cut long story short: every time I test what the value of recv is. If it is equal to 1, it means that there is no message received, "the line is free" and the client can type his own message. Otherwise, he has to display the received message and only after that he can send his own text.

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;
}
ALar
  • 31
  • 1
  • 3
1

Disclaimer: I haven't run your code myself, so the below analysis could be wrong.

I recommend you check the return value of recv, which would return -1 on error. If recv is encountering an error in this line of Client2.c: recv(clientSocket, buffer, sizeof buffer - 1, 0); at the beginning of the while loop the buffer would remain zeroed out.

Thus, Client 2 would not wait for Client 1's message, and would simply print an empty string for the message from Client 1.

Let me know if any of this helps or you need more assistance. If the above is true, you should make sure that the connection is not getting interrupted, among other things.

tbg
  • 71
  • 2
  • 1
    Thanks for the help! It was not exactly the cause of the problem (it turns out that recv is equal to 1 in empty messages) but it helped me to find a way to make clients wait for each other. I will submit my solution below for those who will look for an answer to the same problem later. – ALar Dec 11 '16 at 15:41