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抓包截图





现请求协助排查TCP四次挥手缺失的问题。
内容的提问来源于stack exchange,提问作者S-N
相关产品推荐
相关产品推荐

