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

使用C++ Socket传输文件时开头偶发出现随机多余字节问题求助

问题根源

  • 核心原因是TCP是字节流协议,单次send/recv调用不保证传输完指定长度的数据,你的代码没有处理半包/粘包情况,偶发触发逻辑错误:
    1. 发送端传输文件大小的时候,直接发送了整个MAX_BUFFER长度的msg数组,数组未初始化的部分携带栈内存残留的脏数据(包括你之前打印的File Size is这类字符串残留)
    2. 接收端第一次调用recv读取文件大小时,假设单次就能收满MAX_BUFFER字节,但实际可能只收到部分长度的大小包,剩下的大小包字节会被后续接收文件的逻辑当做文件内容写入,就出现了开头随机字节、附带无关字符串的问题
    3. 发送端读取文件内容前多余执行了sprintf(buffer, "%d\0", size);,虽然不直接触发错误,但属于无效代码,极端情况如果fread调用失败会额外发送无效的大小字符串
    4. 所有send/recv调用都没有判断返回值,也没有循环处理确保传输完预期长度的数据,网络波动时很容易出现传输错误

修复步骤

  1. 修正文件大小的传输逻辑,不要发送整个未初始化的MAX_BUFFER数组,建议直接传输4字节固定长度的二进制整型(统一用网络字节序避免大小端问题),避免脏数据,也不需要解析字符串
  2. 封装send_all和recv_all工具函数,循环调用send/recv确保预期长度的数据全部传输完成
  3. 删除发送端读取文件前的无效sprintf代码
  4. 所有IO调用增加错误判断,处理连接断开、读写错误的情况

修正后的核心代码示例

工具函数封装

// 确保发送完指定长度的数据
ssize_t send_all(int sock, void *buf, size_t len) {
    size_t total_sent = 0;
    while (total_sent < len) {
        ssize_t sent = send(sock, (char*)buf + total_sent, len - total_sent, 0);
        if (sent <= 0) return sent; // 出错或连接关闭
        total_sent += sent;
    }
    return total_sent;
}

// 确保接收完指定长度的数据
ssize_t recv_all(int sock, void *buf, size_t len) {
    size_t total_recv = 0;
    while (total_recv < len) {
        ssize_t recvd = recv(sock, (char*)buf + total_recv, len - total_recv, 0);
        if (recvd <= 0) return recvd; // 出错或连接关闭
        total_recv += recvd;
    }
    return total_recv;
}

发送端修正

int Socket::send_file(string path,int socket_){
    if (socket_ == -1 ) {
        socket_ = clientSd ;
    }
    
    FILE *fd = fopen(path.c_str(), "rb");
    if (!fd) {
        cout << "Failed to open file " << endl ;
        exit(0);
    }
    // 获取文件大小
    fseek(fd, 0, SEEK_END);
    int size = ftell(fd);
    fseek(fd, 0, SEEK_SET);

    cout << "File Size is " << size << endl ;
    // 转网络字节序发送4字节固定长度大小
    int net_size = htonl(size);
    send_all(socket_, &net_size, sizeof(net_size));

    char buffer[MAX_BUFFER];
    int bytes_read;
    while ((bytes_read = fread(buffer, 1, MAX_BUFFER, fd)) > 0) {
        send_all(socket_, buffer, bytes_read);
    }
    fclose(fd);

    cout << "End" << endl ;
    return 1 ;
}

接收端修正

int Socket::receive_file(string path,int socket_){
    if (socket_ == -1 ) {
        socket_ = clientSd ;
    }
    
    int net_size = 0;
    // 收4字节大小,转主机字节序
    if (recv_all(socket_, &net_size, sizeof(net_size)) <= 0) {
        cout << "Receive file size failed" << endl;
        return -1;
    }
    int size = ntohl(net_size);
    cout << "File Size is " << size << endl ;

    FILE* fd = fopen(path.c_str(), "wb");
    if (!fd) {
        cout << "Open file for write failed" << endl;
        return -1;
    }

    char buffer[MAX_BUFFER];
    int received = 0 ;
    while (received < size) {
        int to_read = min(MAX_BUFFER, size - received);
        ssize_t datasize = recv_all(socket_, buffer, to_read);          
        if (datasize <= 0) break;
        fwrite(buffer, 1, datasize, fd); 
        received += datasize;
    }

    fclose(fd);
    cout << "End" << endl ;
    return 1 ;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 01:45:06