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

C语言TCP跨平台文件传输工具缺失TCP四次挥手问题求助

跨平台TCP文件传输工具四次挥手缺失问题排查

我使用C语言开发了一款跨平台文件传输工具,采用TCP作为传输协议。目前文件传输过程(包括文件长度、哈希值校验)均正常,但存在TCP四次挥手(four-way connection-close)缺失的问题,请求协助排查。

接收端(Ubuntu 20.04)

#include <stdio.h>
#include <netdb.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
typedef struct sockaddr    SOCKADDR;
typedef struct addrinfo    ADDRINFO;
typedef struct sockaddr_in SOCKADDR_IN;

#define BLOCKLEN 4096

int main(int argc, char **argv)
{
    SOCKADDR_IN *ipv4 = NULL;
    ADDRINFO *result = NULL; // Domain Name System structure
    ADDRINFO hints = { // IPv4
        .ai_family = AF_INET};
    FILE *fp = NULL; // File structure
    SOCKADDR *client = NULL;

    const char *host = "0.0.0.0"; // hostname
    uint64_t fileSize; // file size
    uint64_t tSize; // Single transmission size
    uint16_t port = 49281; // listen port
    uint8_t fileBuf[BLOCKLEN]; // data buffer
    uint8_t fileSizeBuf[8]; // file size buffer

    int sockfd; // listen socket

    // Name Resolution
    getaddrinfo(host, "echo", &hints, &result);

    // Initialize
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(fileBuf, 0, BLOCKLEN);
    memset(fileSizeBuf, 0, 8);
    fp = fopen("xxxxx", "wb");
    client = (SOCKADDR *)malloc(result->ai_addrlen);

    // Initialize IPv4 network structure
    ipv4 = (SOCKADDR_IN *)result->ai_addr;
    ipv4->sin_port = htons(port);

    bind(sockfd, (SOCKADDR *)&ipv4, result->ai_addrlen);
    listen(sockfd, 5);
    printf("Waiting for the client to connect...\n");
    sockfd = accept(sockfd, client, &result->ai_addrlen);

    printf("Successfully connected, starting to receive data.\n");
    // Received file size, Assign file size data to integer
    // variables.
    recv(sockfd, fileSizeBuf, 8, 0);
    memcpy(&fileSize, fileSizeBuf, 8);

    // Subtract the received length from the file length until
    // the file length becomes 0.
    for(; fileSize; fileSize -= tSize) {
        tSize = recv(sockfd, fileBuf, BLOCKLEN, 0);
        fwrite(fileBuf, 1, tSize, fp);
    }

    // Tell the client that the data has been fully received.
    send(sockfd, "done", 4, 0);

    // Release all used items before the program ends.
    fclose(fp);
    freeaddrinfo(result);
    close(sockfd);
    shutdown(sockfd, 2);
    return 0;
}

客户端(Windows 10 x64 22H2)

注:该示例代码存在连接问题,但此非本次问询重点,故未修复。

#include <WS2tcpip.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#pragma comment(lib, "WS2_32.lib")

#define BLOCKLEN 4096

uint64_t GetfileSize(const char *fn)
{
    HANDLE hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ,
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    LARGE_INTEGER W_size;
    GetFileSizeEx(hFile, &W_size);
    
    return W_size.QuadPart;
}

int main(int argc, char **argv)
{
    WSADATA ws;
    WSAStartup(MAKEWORD(2,2), &ws);

    SOCKADDR_IN *ipv4 = NULL; // pointer
    ADDRINFO *result = NULL; // Domain Name System structure
    ADDRINFO hints = { // IPv4
        .ai_family = AF_INET};
    FILE *fp = NULL; // File structure

    const char *fn = "xxxxxx"; // file name
    const char *host = "47.x.x.x"; // hostname
    uint64_t fileSize; // file size
    uint16_t port = 49281; // listen port
    uint64_t quotient; // Quotient of file length divided by block size
    uint64_t leftover; // Remaining length of file
    char fileBuf[BLOCKLEN]; // data buffer
    char fileSizeBuf[8]; // file size buffer
    char message[4]; // Transfer message

    SOCKET sockfd; // listen socket

    // Initialize
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(fileBuf, 0, BLOCKLEN);
    memset(fileSizeBuf, 0, 8);
    fileSize = GetfileSize(fn);
    fp = fopen(fn, "rb");
    memcpy(fileSizeBuf, &fileSize, 8);

    // Name Resolution
    getaddrinfo(host, "echo", &hints, &result);

    // Initialize IPv4 network structure
    ipv4 = (SOCKADDR_IN *)result->ai_addr;
    ipv4->sin_port = htons(port);

    // Connect to the receiving end
    connect(sockfd, (SOCKADDR *)ipv4, result->ai_addrlen);

    // Send file size data
    send(sockfd, fileSizeBuf, 8, 0);

    quotient = fileSize / BLOCKLEN;
    leftover = fileSize % BLOCKLEN;
    for(uint64_t i = 0; i < quotient; ++i) {
        fread(fileBuf, 1, BLOCKLEN, fp);
        send(sockfd, fileBuf, BLOCKLEN, 0);
    }
    if(leftover) {
        fread(fileBuf, 1, leftover, fp);
        send(sockfd, fileBuf, leftover, 0);
    }

    recv(sockfd, message, 4, 0);

    fclose(fp);
    freeaddrinfo(result);
    closesocket(sockfd);
    WSACleanup();
    return 0;
}

整体流程

接收端根据发送端发送的文件大小执行接收逻辑,发送端一次性发送全部文件数据,传输完成后接收端向发送端发送接收完成信号。

Wireshark抓包截图

抓包截图1
抓包截图2
抓包截图3
抓包截图4
抓包截图5

现请求协助排查TCP四次挥手缺失的问题。

内容的提问来源于stack exchange,提问作者S-N

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 11:40:06