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

C++ WinSocket TCP文件发送偶发失败 加Sleep后正常问题排查咨询

问题根因
  • 发送循环结构错误,短发送场景下数据丢失
    TCP协议中send()返回值小于传入的长度是正常现象(内核发送缓冲区不足时就会返回已成功拷贝到内核的字节数,也就是短发送)。你当前的代码把fread()和send()都包在了内层do-while循环中,一旦出现短发送,下一轮内层循环会直接重新读取文件覆盖缓冲区,未发送完成的剩余数据直接丢失。
  • 发送完成后未做TCP优雅关闭,内核缓冲区数据被丢弃
    send()执行成功仅代表数据被拷贝到操作系统内核的发送缓冲区,不代表数据已经通过网络发送到对端。你在发送完最后一批数据后立刻执行WSACleanup()、退出程序,操作系统会直接丢弃还没来得及发送的内核缓冲区数据,直接发送RST强制断开连接,导致对端收不到完整数据。加Sleep或者调试运行时,停顿的时间足够内核把所有数据发送完成,因此问题消失。
  • 类型与错误判断逻辑错误,无法捕获异常
    1. send()返回值为int类型,失败时返回SOCKET_ERROR(值为-1),你用无符号size_t存储返回值,会导致-1被转换为极大正整数,test < 0的错误判断永远不会生效,发送异常无法被感知。
    2. fread()返回值为无符号size_t,bytes_read < 0的判断完全无效,无法捕获文件读取异常。
    3. fopen_s返回值的赋值逻辑存在运算符优先级错误,虽然不影响功能但属于不规范写法。
修复方案
  1. 拆分读取和发送逻辑:先读取一批文件内容到缓冲区,再单独循环发送这批内容,直到全部发完再读取下一批
  2. 所有数据发送完成后调用shutdown(SendSocket, SD_SEND)触发TCP四次挥手,等待对端确认后再关闭socket
  3. 修正变量类型和所有错误判断逻辑
修复后完整代码
#include <iostream>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <string>
#pragma comment(lib, "ws2_32.lib")

int main()
{
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }
    SOCKET SendSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (SendSocket == INVALID_SOCKET) {
        perror("Error at socket: ");
        WSACleanup();
        return 1;
    }

    struct sockaddr_in myAddr;
    memset(&myAddr, '\0', sizeof myAddr);
    myAddr.sin_family = AF_INET;
    myAddr.sin_port = htons(2000);

    inet_pton(AF_INET, "127.0.0.1", &(myAddr.sin_addr)); 
    memset(myAddr.sin_zero, '\0', sizeof myAddr.sin_zero);
    if (connect(SendSocket, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0)
    {
        perror("Error at connect: ");
        closesocket(SendSocket);
        WSACleanup();
        return 1;
    }

    char buffer[512];
    const char fileName[] = "test.txt";
    FILE* fd;
    errno_t openErr = fopen_s(&fd, fileName, "rb");
    if (openErr != 0) {
        perror("File not opened:");
        closesocket(SendSocket);
        WSACleanup();
        return 1;
    }

    size_t bytes_read = 0;
    // 先读文件,再循环发送,读完为止
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), fd)) > 0) {
        size_t total_sent = 0;
        // 同一批数据反复发送直到发完
        while (total_sent < bytes_read) {
            int send_len = send(SendSocket, buffer + total_sent, bytes_read - total_sent, 0);
            if (send_len == SOCKET_ERROR) {
                perror("Error send");
                fclose(fd);
                closesocket(SendSocket);
                WSACleanup();
                return 1;
            }
            total_sent += send_len;
        }
    }
    // 检查文件读取是否出错
    if (ferror(fd)) {
        std::cout << "file read error" << std::endl;
        fclose(fd);
        closesocket(SendSocket);
        WSACleanup();
        return 1;
    }
    fclose(fd);

    // 优雅关闭TCP连接,等待内核发送完所有数据
    shutdown(SendSocket, SD_SEND);
    // 等待对端返回FIN确认所有数据接收完成
    char dummy;
    recv(SendSocket, &dummy, 1, 0);

    closesocket(SendSocket);
    WSACleanup();
    system("PAUSE");
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 02:15:04