ALar
ALar

Reputation: 31

C language - Sockets - A chat between two clients (using one server as middle man)

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

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

My problem in a few words:

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

Upvotes: 1

Views: 4826

Answers (2)

ALar
ALar

Reputation: 31

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

Upvotes: 2

tbg
tbg

Reputation: 71

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.

Upvotes: 1

Related Questions