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

通过TCP发送Zip文件至客户端后文件损坏/无效的问题排查

二进制文件(如Zip)TCP传输问题排查与解决

你的问题核心在于客户端用文本处理方式(StreamWriter+Encoding.ASCII)读取并写入二进制的Zip文件:

  • 普通文本文件(.txt/.cs/.csv)的内容大多在ASCII编码范围内,用ASCII转换不会破坏数据;但Zip文件是二进制格式,包含大量超过ASCII范围(0x80及以上)的字节,Encoding.ASCII会把这些字节强制替换成0x3F(问号),导致文件内容隐性损坏,哈希值自然不同——哪怕文件大小看起来一致。

正确传输二进制文件的注意事项

  • 全程使用二进制流处理,绝对避免任何文本编码转换操作
  • TCP是流协议,不能靠Available判断数据是否就绪,也不能用“最后一包长度是否为1024”作为结束条件(存在刚好整包的情况),最可靠的方式是先发送文件总长度,客户端根据长度精准接收对应字节数
  • 写入文件时用FileStream而非StreamWriter,前者专门处理二进制数据
  • 异步操作必须加await等待完成,否则会出现流程错乱

修正后的服务器代码

using System.Net.Sockets;
using System.Net;
using System.IO.Compression;

string filename = @"C:\BabyServerZip\ServerFiles.zip";

// 重新生成Zip文件
File.Delete(filename);
ZipFile.CreateFromDirectory(@"C:\BabyServerSend", filename);

IPHostEntry ipHostInfo = Dns.GetHostEntry("localhost");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint endpoint = new(ipAddress, 58008);
using Socket listener = new(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(endpoint);
listener.Listen();

// 等待客户端连接
using var handler = await listener.AcceptAsync();

// 先发送文件长度(用4字节int标识)
byte[] fileBytes = File.ReadAllBytes(filename);
int fileLength = fileBytes.Length;
byte[] lengthBuffer = BitConverter.GetBytes(fileLength);
await handler.SendAsync(lengthBuffer, SocketFlags.None);

// 发送文件内容
await handler.SendAsync(fileBytes, SocketFlags.None);

修正后的客户端代码

using System.Net;
using System.Net.Sockets;

string outputPath = @"C:\BabyClientReceive\sent.zip";

IPHostEntry ipHostInfo = Dns.GetHostEntry("localhost");
IPAddress serverIP = ipHostInfo.AddressList[0];
IPEndPoint clientEnd = new(serverIP, 58008);
using Socket clientSocket = new(clientEnd.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

// 等待连接完成
await clientSocket.ConnectAsync(clientEnd);

// 先接收文件长度
byte[] lengthBuffer = new byte[4];
int receivedLength = await clientSocket.ReceiveAsync(lengthBuffer, SocketFlags.None);
if (receivedLength != 4)
{
    Console.WriteLine("接收文件长度失败");
    return;
}
int fileLength = BitConverter.ToInt32(lengthBuffer, 0);

// 接收文件内容
using FileStream fs = new FileStream(outputPath, FileMode.Create);
int totalReceived = 0;
byte[] buffer = new byte[1024];

while (totalReceived < fileLength)
{
    int received = await clientSocket.ReceiveAsync(buffer, SocketFlags.None);
    if (received == 0) break; // 连接断开
    await fs.WriteAsync(buffer.AsMemory(0, received));
    totalReceived += received;
}

Console.WriteLine($"文件接收完成,共接收{totalReceived}字节");

关键修正点说明

  1. 服务器先发送文件总长度,客户端据此精准接收,彻底解决流数据的边界判断问题
  2. 客户端用FileStream直接写入二进制字节,完全跳过文本编码转换,保证数据原样保存
  3. 所有异步操作添加await,确保流程执行顺序正确
  4. 使用using语句自动释放Socket和文件流资源,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 12:21:49