You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言Socket单连接聊天程序异常:回复消息后陷入无限循环求助

排查与解决Socket单连接聊天程序的无限循环问题

常见问题根源

1. 换行符残留坑

用fgets()读取用户输入时,会把换行符\n也塞进缓冲区。要是直接把带换行的内容发出去,服务器收到的是xxx\n,和你要判断的"end"完全不匹配,触发不了结束逻辑,循环就一直跑。

2. 没处理recv()/send()的返回值

很多人会忽略这俩函数的返回值:

  • recv()返回0意味着客户端已经关闭连接,返回-1是出错了,要是不管这些继续循环,程序就会无限执行。
  • send()失败后没做处理,也会导致循环卡死。

3. 循环结束逻辑写崩了

比如主循环直接写while(1),但收到"end"后没正确关闭套接字或跳出循环,自然会无限转。

4. 缓冲区没清空

每次接收消息后,没把缓冲区用memset()清干净,旧数据和新数据混在一起,干扰"end"的判断。

解决步骤+修正代码

先解决换行符问题

发送前把fgets()读进来的换行符替换成字符串结束符:

char buf[1024];
fgets(buf, sizeof(buf), stdin);
// 用strcspn找到换行符位置,直接替换成'\0'
buf[strcspn(buf, "\n")] = '\0';

严格处理返回值

每次调用recv()/send()后必须检查返回值:

// 服务器接收示例
ssize_t recv_len = recv(client_fd, buf, sizeof(buf)-1, 0);
if (recv_len <= 0) {
    // 连接断了或出错,直接关套接字跳出循环
    close(client_fd);
    break;
}
buf[recv_len] = '\0'; // 手动加结束符,避免乱码

写对结束逻辑

收到"end"后,立刻关套接字+跳出循环:

if (strcmp(buf, "end") == 0) {
    printf("关闭连接\n");
    close(client_fd);
    break;
}

完整修正代码

server.c

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

#define PORT 8080
#define BUF_SIZE 1024

int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buf[BUF_SIZE];

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置套接字可重用端口/地址
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // 绑定端口
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接,最多排队3个
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 接受客户端连接
    if ((client_fd = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    printf("客户端已连接\n");

    while (1) {
        // 清空缓冲区
        memset(buf, 0, BUF_SIZE);
        // 接收客户端消息
        ssize_t recv_len = recv(client_fd, buf, BUF_SIZE-1, 0);
        if (recv_len <= 0) {
            printf("客户端连接关闭\n");
            close(client_fd);
            break;
        }
        buf[recv_len] = '\0';
        printf("收到客户端消息: %s\n", buf);

        // 判断是否结束
        if (strcmp(buf, "end") == 0) {
            printf("关闭连接\n");
            close(client_fd);
            break;
        }

        // 输入回复
        printf("请输入回复: ");
        fgets(buf, BUF_SIZE, stdin);
        buf[strcspn(buf, "\n")] = '\0';

        // 自己输入end也关闭
        if (strcmp(buf, "end") == 0) {
            send(client_fd, buf, strlen(buf), 0);
            printf("关闭连接\n");
            close(client_fd);
            break;
        }

        // 发送回复
        ssize_t send_len = send(client_fd, buf, strlen(buf), 0);
        if (send_len < 0) {
            perror("send failed");
            close(client_fd);
            break;
        }
    }

    close(server_fd);
    return 0;
}

client.c

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

#define PORT 8080
#define BUF_SIZE 1024

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char buf[BUF_SIZE];

    // 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 转换本地IP地址
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("invalid address");
        exit(EXIT_FAILURE);
    }

    // 连接服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("connection failed");
        exit(EXIT_FAILURE);
    }
    printf("已连接到服务器\n");

    while (1) {
        // 输入消息
        printf("请输入消息: ");
        fgets(buf, BUF_SIZE, stdin);
        buf[strcspn(buf, "\n")] = '\0';

        // 输入end就终止
        if (strcmp(buf, "end") == 0) {
            send(sock, buf, strlen(buf), 0);
            printf("终止连接\n");
            close(sock);
            break;
        }

        // 发送消息
        ssize_t send_len = send(sock, buf, strlen(buf), 0);
        if (send_len < 0) {
            perror("send failed");
            close(sock);
            break;
        }

        // 清空缓冲区接收回复
        memset(buf, 0, BUF_SIZE);
        ssize_t recv_len = recv(sock, buf, BUF_SIZE-1, 0);
        if (recv_len <= 0) {
            printf("服务器连接关闭\n");
            close(sock);
            break;
        }
        buf[recv_len] = '\0';
        printf("收到服务器回复: %s\n", buf);

        // 服务器发end也关闭
        if (strcmp(buf, "end") == 0) {
            printf("服务器关闭连接\n");
            close(sock);
            break;
        }
    }

    return 0;
}

编译运行

# 编译服务器
gcc server.c -o server
# 编译客户端
gcc client.c -o client
# 先开服务器
./server
# 再开客户端
./client

内容的提问来源于stack exchange,提问作者bekahboo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 00:16:10