首页 文章

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

提问于
浏览
1

我需要使用套接字在C中编写一个聊天程序,我遇到了困难 .

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

  • Server收到它并将其发送给Client2

  • Client2接收Client1的消息,写回来并将其发送到服务器

  • Server收到Client2的消息并将其发送给Client1

  • Client1接收它并写回一些由服务器等首先接收的内容.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

2 回答

  • 1

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

    我建议你检查 recv 的返回值,这将在出错时返回 -1 . 如果 recv 在此行Client2.c中遇到错误:在while循环开始时_1113631_缓冲区将保持清零状态 .

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

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

  • 1

    所以,正如之前评论中所承诺的,这是我的解决方案 . 简而言之:每次我测试recv的 Value 是什么 . 如果它等于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;
    }
    

相关问题