1

我需要使用套接字在 C 语言中编写一个聊天程序,但我被困住了。

我有三个文件:服务器、客户端1、客户端2。我最初的计划: - Client1 将消息发送到服务器

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

当任一客户端发送“退出”时,循环结束。

我的问题简而言之:

  • 第一次交换成功(Client1 -> Client2,然后Client2到Client1)

  • 但是,在 Client2 向 Client1 发送了第一条消息之后,他并没有等待 Client1 的响应。他为消息写了一个空行的“Client1:”,然后立即打开他自己的“Client2:”消息字段。

以上帝的名义,这里有什么问题?

客户端1.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;
}

服务器.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;
}

客户端2.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;
}

结果在屏幕截图中:

客户 2 太专横,不等轮到他说话

4

2 回答 2

1

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

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

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

让我知道这是否有帮助或您需要更多帮助。如果上述情况属实,则应确保连接没有中断等。

于 2016-12-10T17:08:40.580 回答
1

因此,正如之前评论中所承诺的,这是我的解决方案。长话短说:每次我测试 recv 的值是多少。如果等于1,则表示没有收到消息,“线路空闲”,客户端可以键入自己的消息。否则,他必须显示收到的消息,然后才能发送自己的文本。

客户端1.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;
}

服务器.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;
}

客户端2.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;
}
于 2016-12-11T15:50:44.757 回答