多线程TCP大文件传输进度显示异常问题求助
多线程TCP文件传输大文件异常排查
客户端发送代码
// Opened a file using fopen function. int SendPercent = 0; // Value that shows the current progress while (1) { len = fread(buf, 1, BUFSIZE, fp); if (len) { retval = send(sock, buf, len, 0); if (retval == SOCKET_ERROR) { err_display("send()"); break; } SendPercent += len; printf("percent : %2.2f%%\r", (float)SendPercent / (float)AllLen * 100.0f); } else if (SendPercent == AllLen) { printf("\nFinished.\n"); break; } else { printf("\nIt did not end successfully.\n"); break; } } fclose(fp); closesocket(sock); WSACleanup(); return 0;
服务器接收代码
FILE* fp = fopen(filename, "wb"); while (1) { retval = recv(client_sock, buf, sizeof(buf), MSG_WAITALL); if (retval == SOCKET_ERROR) { err_display("recv()"); break; } else if (retval == 0) { printf("\ncurLen : %f, allLen : %f\n", (float)curLen, (float)allLen); break; } curLen += fwrite(buf, 1, retval, fp); memset(&buf, 0, sizeof(buf)); printf("percent : %2.2f%%\r", (float)curLen / (float)allLen * 100.0f); if (curLen == allLen) { printf("\nSuccessfully Received.\n"); break; } } fclose(fp);
异常现象
- 4KB小文件传输正常;
- 77000KB以上大文件传输时:客户端显示进度100%并完成断开,服务器进度停在99.92%,
curLen未触发等于allLen的判断就因连接断开退出循环,但实际接收的文件完整; - 单线程模式运行正常,多线程(通过
CreateThread实现)下出现该问题。
问题根源分析
浮点数精度丢失:
curLen和AllLen为32位整数时,大文件大小(如77000KB=78848000字节)超过float类型的有效精度(约6-7位),转换为float计算百分比时会丢失精度,导致显示的进度未达100%,但实际curLen已经等于allLen。服务器接收逻辑顺序问题:
客户端发送完所有数据后会关闭socket,服务器后续的recv调用会返回0(连接关闭)。此时代码直接触发break退出循环,未先检查curLen是否等于allLen,因此不会打印成功提示,造成“未完成”的假象。多线程下的时序差异:
单线程模式下,最后一次recv可能刚好接收完最后一段数据,触发curLen == allLen的判断并正常退出;多线程模式下,recv可能在连接关闭后才返回0,跳过了成功判断的逻辑。
修复方案
使用高精度数值类型:
将curLen、SendPercent、AllLen改为long long类型,用double计算百分比,避免精度丢失:printf("percent : %2.2f%%\r", (double)curLen / (double)allLen * 100.0);调整服务器接收逻辑:
在recv返回0时,先检查curLen是否等于allLen,再决定是否提示成功:else if (retval == 0) { if (curLen == allLen) { printf("\nSuccessfully Received.\n"); } else { printf("\ncurLen : %lld, allLen : %lld\n", curLen, allLen); } break; }谨慎使用
MSG_WAITALL:
该标志会让recv等待直到接收满指定字节,但若连接提前关闭,可能导致最后一段数据的接收逻辑异常。可考虑去掉该标志,改为循环接收直到获取足够数据,更适配TCP流式传输的特性。
内容的提问来源于stack exchange,提问作者MeoH
相关产品推荐
相关产品推荐

