C语言 - 套接字 - 两个客户端之间的聊天(使用一个服务器作为中间人)

时间:2016-12-10 16:41:28

标签: c sockets server clients

我需要使用套接字在C中编写聊天程序,但我遇到了问题。

我有三个文件:server,client1,client2。我的初步计划: - Client1将消息发送到服务器

  • 服务器接收它并将其发送到Client2
  • Client2收到Client1的消息,写回来并将其发送到服务器
  • 服务器接收Client2的消息并将其发送到Client1
  • Client1收到它并写回一些由服务器等首先收到的东西。等等。

当任一客户端发送"退出"。

时,循环结束

我的问题用几句话说:

  • 第一次交换成功(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

2 个答案:

答案 0 :(得分:1)

免责声明:我自己没有运行您的代码,因此以下分析可能是错误的。

我建议您检查recv的返回值,该值会在出错时返回-1。如果recv在此行Client2.c中遇到错误:在while循环开始时recv(clientSocket, buffer, sizeof buffer - 1, 0);,则缓冲区将保持清零状态。

因此,客户端2不会等待客户端1的消息,只会打印来自客户端1的消息的空字符串。

如果有任何帮助或需要更多帮助,请告诉我。如果上述情况属实,则应确保连接不会中断,等等。

答案 1 :(得分:1)

所以,正如前面评论中所承诺的,这是我的解决方案。简而言之:每次我测试recv的价值是什么。如果它等于1,则表示没有收到消息,&#34;该行是免费的&#34;并且客户端可以键入自己的消息。否则,他必须显示收到的消息,然后才能发送他自己的文本。

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