与服务器和客户端的聊天程序,用C语言进行套接字编程

Chat Program with server and client, socket programming in C

提问人:bekahboo 提问时间:11/6/2023 更新时间:11/6/2023 访问量:97

问:

我打算使用带有 client.c 和 server.c 的套接字编写一个简单的聊天程序 以下是我得到的要求:

服务器:

  • 接受一个连接
  • 通过先接受消息,然后发送用户输入的消息来与客户端聊天。
  • 如果客户端消息为“结束”,服务器将关闭连接。
  • 否则,请永远继续交换消息。 客户:
  • 连接到服务器
  • 通过将用户输入字符串发送到服务器,然后向用户显示服务器响应来开始聊天。
  • 如果用户输入“end”,客户端会将其发送到服务器并终止连接。

这是我为 server.c 想出的代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/ip.h>
#include <string.h>

int main(){

    unsigned short port;
    struct sockaddr_in Client_info;
    socklen_t Client_Info_Len;

    struct sockaddr_in Server_info;
    int Socket_Serv_FD, Socket_Client_FD;
    int result;

    char message[100];
    char Message_From_Client[100];

    port = 23232;

    printf("Server initiating connection ... \n");

    // create socket
    Socket_Serv_FD = socket(AF_INET, SOCK_STREAM, 0);
    // check for failure
    if(Socket_Serv_FD < 0){
        printf("Socket creation failed.");
        return -1;
    }

    // binding information
    Server_info.sin_family = AF_INET;
    Server_info.sin_port = port;
    Server_info.sin_addr.s_addr = INADDR_ANY;


    // bind with port to the socket
    result =  bind(Socket_Serv_FD, (struct sockaddr *)&Server_info, sizeof(struct sockaddr_in));
    if(result < 0){
        printf("Binding socket failed.");
        return -1;
    }

    // listen for connections on socket
    result = listen(Socket_Serv_FD, 0);
    if(result < 0){
        printf("Listen socket failed");
        return -1;
    }

        // accept when a connection occurs
        Socket_Client_FD = accept(Socket_Serv_FD, (struct sockaddr *)&Client_info, &Client_Info_Len);
        if(Socket_Client_FD < 0){
            printf("Socket connection failed.");
            return -1;
        }

    while(1){
        // read message from client
        result = read(Socket_Client_FD, &Message_From_Client, sizeof(Message_From_Client));
        if(result < 0){
            printf("Socket failed.");
            return -1;
        }

        printf("Message from client >> %s \n", Message_From_Client);

        // close socket when user enters 'end'!
        if(strcmp(Message_From_Client, "end") == 0){
            printf("Closing connection ... \n");
            break;
        }

        // prompt for message to send to client
        printf("Type a message to the client : ");
        scanf("%[^\n]", message);
        //fgets(message, 100, stdin);

        // send message to client
        result = write(Socket_Client_FD, &message, strlen(message));
        if(result < 0){
            printf("Message failed.");
            return -1;
        }
    }
    close(Socket_Serv_FD);
    close(Socket_Client_FD);
    return 0;
}

这是我的 client.c 代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include <string.h>

int main(){

    struct sockaddr_in Server_info;
    int Socket_FD;
    int result;
    
    char message[100];
    char Message_From_Server[100];
    
    int port = 23232;
    
    printf("Initiating connection ... \n");
    
    // create a socket
    Socket_FD = socket(AF_INET, SOCK_STREAM, 0);
    if(Socket_FD == -1){
        printf("Socket creation failed.");
        return -1;
    }   
    
    // bind information
    Server_info.sin_family = AF_INET;
    Server_info.sin_port = port;
    Server_info.sin_addr.s_addr = inet_addr("127.0.0.1");
    
    // listen for connections
    result = connect(Socket_FD, (struct sockaddr *)&Server_info, sizeof(struct sockaddr_in));
    if(result < 0){
        printf("Connect socket failed.");
        return -1;
    } 
        
    while(1){
        // get input message from user
        printf("Type a message to server or 'end' to close connection : ");
        scanf("%[^\n]", message);
        //fgets(message, 100, stdin);

        // send to server
        result = write(Socket_FD, &message, sizeof(message));
        if(result < 0){
            printf("Message failed.");
            return -1;
        }
        
        // close socket when user enters 'end'!
        if(strcmp(message, "end") == 0){
            printf("Closing connection ... ");
            close(Socket_FD);
            return 0;
        }
        
        // receive from server
        result = read(Socket_FD, &Message_From_Server, strlen(Message_From_Server));
        if(result < 0){
            printf("Message failed.");
            return -1;
        }
        
        printf("Message from server >> %s \n", Message_From_Server);
        
    }
}

当我运行该程序时,它起初似乎可以工作,提示客户端向服务器发送消息,然后在我按回车键后将该消息发送到服务器。但是,在我尝试从服务器向客户端发送消息后,代码中断并在终端中输出无限循环。它意味着客户端和服务器相互发送消息,直到客户端进入“结束”。

这是我收到的输出::

首先,我启动程序,它提示客户端输入消息,在此处输入图像描述,接下来我输入消息“hello server”并按回车键,服务器收到消息良好,并提示将消息发送回去,在此处输入图像描述接下来我键入消息“hello client”并按回车键,但这是结果输出,在此处输入图像描述

提前感谢您的任何帮助(:

C 套接字 客户端-服务器

评论

0赞 user207421 11/6/2023
如果返回 -1,则应打印错误号或消息,如果返回 0,则对等方已断开连接,因此应关闭套接字并停止读取:这也意味着您的“结束”消息是多余的。你不能假设你在一次读取中收到了整条消息,也不能假设 null 终止,除非你把它放在那里,但你没有,你得到了整个消息。read()
0赞 user207421 11/6/2023
你也有,这没有任何意义。直到您阅读完它之后,您才知道它的长度,并且消息长度与可用于读取它的空间无关。它应该是 ,就像在服务器代码中一样。read(Socket_FD, &Message_From_Server, strlen(Message_From_Server)read(Socket_FD, &Message_From_Server, sizeof Message_From_Server
0赞 bekahboo 11/6/2023
谢谢!我在每次出现时都将 strlen 更改为 sizeof,但是我不太理解第一条评论。检查读取 = -1 的结果是否以确保没有错误,而用户输入“结束”意味着他们手动关闭聊天吗?如果这不是提示用户结束消息传递的正确方法,我应该如何解决它
0赞 user207421 11/6/2023
如果出现错误,请打印错误。我不明白我怎么能说得更清楚,或者我第一次没有这么说。客户端不必发送,只需关闭套接字即可。此外,您应该使用的地方,您不是:应该是,+1 表示包含尾随的 null 字节。"end"strlen()write(Socket_FD, &message, sizeof(message))write(Socket_FD, &message, strlen(message)+1)
0赞 bekahboo 11/6/2023
哦,我明白了,谢谢!所以我应该在阅读时使用 sizeof(),因为我们直到读取后才会知道长度,但我们在写作时确实知道长度,所以我们使用 strlen?只是重复信息,所以我知道我正在理解推理(:

答:

0赞 vsshhhtttt 11/6/2023 #1

首先,不要使用 scanf 来读取您的输入。我看到你尝试过(也许?)fgets,但显然没有成功,因为它被注释掉了。现在你应该记住,fgets 最多读取 “size”-1 个字符和换行符 (\n) 字符,因此您需要将其从字符串中删除。有不同的方法可以实现这一点,我使用的方法是

message[strcspn(message, "\n")] = 0;

同时,scanf 只会解析与其格式说明符匹配的任何内容,其他所有内容都留在缓冲区中供您管理。一旦我尝试使用 scanf 运行代码,我就像您一样得到了无限循环。 现在,我还想提一下,我没有使用 write/read,而是使用了 send/recv,当函数调用中使用 0 标志时,它应该与 write/read 几乎相同,也许它对你来说会有所不同。 也就是说,在 client.c 中

result = write(Socket_FD, &message, sizeof(message));

成为

result = send(Socket_FD, message, sizeof(message),0);

result = read(Socket_FD, &Message_From_Server, strlen(Message_From_Server);

成为

result = recv(Socket_FD, Message_From_Server, sizeof(Message_From_Server),0);

server.c
中的相同更改 请注意,上述更改只是允许程序按预期运行,您仍然需要考虑其他所有事情,因为该程序可能会以无数种方式崩溃或以非预期方式运行。希望这会有所帮助。

评论

0赞 bekahboo 11/6/2023
非常感谢!我实现了这些更改,不再有那个无限循环。但是,还有另一个问题:我能够从客户端向服务器发送初始消息,然后从服务器向客户端发送消息作为回复但是,当我再次尝试从客户端向服务器发送第二条消息时,它没有收到,并且在我按回车后没有任何反应。如果我输入“end”,则连接在客户端关闭,但同样,在服务器端未收到,因此那里没有任何反应
0赞 user207421 11/6/2023
“也许对你来说会有所不同”:不,它不会。
0赞 bekahboo 11/6/2023
我使用读写,因为这是我的教授告诉我的(“要发送数据,请使用写入系统调用。与管道和文件相同的系统调用。我们还没有了解 recv 和 send!也许他接下来会教这个......
0赞 bekahboo 11/6/2023
知道了!再次感谢您的帮助(: