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

TCP服务器自动重连客户端的C语言代码实现咨询

搞定TCP服务器自动恢复连接的方案(适配你的传感器场景)

嘿,先提个小细节:你贴的代码是TCP服务器端,不是客户端哦~你的核心问题是:当远程传感器(作为客户端)频繁断开后,服务器没法自动重新接受新连接,一直卡着对吧?下面给你一步步修改,让服务器能在客户端断开后自动回到监听状态,完美适配你的场景:

核心问题分析

你的原代码在accept成功后就进入死循环读取数据,但当客户端断开时:

  • read会返回0(客户端正常断开)或者-1(异常断开)
  • 之后代码会一直卡在无效的循环里,无法重新等待新的连接

修改方案步骤

  1. 把连接处理逻辑封装成单独函数:这样客户端断开后可以直接重新调用,复用代码更清晰
  2. 增加连接异常判断:通过read的返回值识别断开状态,及时关闭当前连接并回到监听
  3. 添加重试等待机制:避免频繁重试占用系统资源,断开后等待几秒再重新监听
  4. 优化日志文件逻辑:原代码只在启动时创建一次文件,改成每次新连接创建单独文件(可选,按需调整)
  5. 增加端口重用选项:解决服务器重启时端口被占用的调试痛点

修改后的完整代码

#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h> // 用于sleep函数
#include <errno.h>   // 用于错误信息输出

#define MAX 1000
#define PORT 14344
#define SA struct sockaddr

// 处理单个客户端连接的函数
void handle_client(int connfd) {
    unsigned char buff[MAX];
    int dd, a;
    char timebuffer[80];
    time_t rawtime;
    struct tm *timeinfo;

    // 为每个新连接创建独立日志文件
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    strftime(timebuffer, 80, "/home/%m%d%y_%H%M%S", timeinfo);
    FILE *fil1 = fopen(timebuffer, "wb");
    if (!fil1) {
        printf("Failed to create log file: %s\n", strerror(errno));
        return;
    }
    printf("Log file created: %s\n", timebuffer);

    printf("Client connected, starting data reading...\n");
    while (1) {
        bzero(buff, MAX);
        dd = read(connfd, buff, sizeof(buff));
        
        // 判断连接状态:read返回0=正常断开,返回-1=异常错误
        if (dd <= 0) {
            if (dd == 0) {
                printf("Client disconnected normally.\n");
            } else {
                printf("Read error: %s\n", strerror(errno));
            }
            break;
        }

        // 打印并写入数据
        printf("\nReceived data: ");
        for (a = 0; a < dd; a++) {
            fprintf(fil1, "%c", buff[a]);
            printf("%02X ", buff[a]);
        }
        printf("\n");
        fflush(fil1); // 立即写入文件,避免数据丢失
    }

    // 清理资源
    fclose(fil1);
    close(connfd);
    printf("Connection closed, waiting for new client...\n");
}

int main() {
    int sockfd, connfd, len;
    struct sockaddr_in servaddr, cli;

    printf("Starting TCP server on port %d...\n", PORT);

    // 创建Socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        printf("Socket creation failed: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    printf("Socket successfully created.\n");

    // 设置端口重用选项:避免服务器重启后端口占用问题
    int opt = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
        printf("Setsockopt failed: %s\n", strerror(errno));
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 配置服务器地址
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);

    // 绑定Socket
    if (bind(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) {
        printf("Socket bind failed: %s\n", strerror(errno));
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    printf("Socket successfully binded.\n");

    // 主循环:持续监听和接受新连接
    while (1) {
        // 开始监听
        if (listen(sockfd, 5) != 0) {
            printf("Listen failed: %s\n", strerror(errno));
            sleep(3); // 失败后等待3秒再重试
            continue;
        }
        printf("Server listening for incoming connections...\n");

        len = sizeof(cli);
        // 等待客户端连接
        connfd = accept(sockfd, (SA*)&cli, &len);
        if (connfd < 0) {
            printf("Accept failed: %s\n", strerror(errno));
            sleep(3); // 失败后等待3秒再重试
            continue;
        }
        printf("Server accepted new connection.\n");

        // 处理当前客户端连接,断开后自动回到主循环重新等待
        handle_client(connfd);
    }

    // 理论上不会执行到这里,还是加上资源清理
    close(sockfd);
    return 0;
}

关键修改点说明

  • 封装handle_client函数:把和客户端交互的逻辑抽离,主循环只负责监听连接,代码更易维护
  • 连接状态判断:通过read的返回值精准识别客户端断开,及时退出处理流程
  • SO_REUSEADDR选项:解决服务器重启时端口被占用的常见问题,调试更顺畅
  • 独立日志文件:每个连接的数据存储在单独文件中,避免覆盖旧数据(不需要的话可以改回原逻辑)
  • 重试等待:用sleep降低重试频率,减少系统资源消耗
  • fflush强制写入:确保数据实时写入文件,防止客户端断开时缓冲区数据丢失

额外小建议

如果之后需要同时处理多个传感器连接,可以考虑引入多线程或多路复用(select/poll/epoll),不过单传感器场景下当前方案完全够用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:17:40