如何实现TcpListener分块接收TcpClient发送的大文件?
分块实现C# TCP文件传输
客户端修改代码
替换原一次性加载文件的逻辑,改用分块读取文件流传输,同时新增文件大小元数据传输:
// 分块大小可根据网络情况调整,默认用4KB平衡内存与效率 const int BufferSize = 4096; string fileName = "目标文件路径"; FileInfo fileInfo = new FileInfo(fileName); using (FileStream fileStream = fileInfo.OpenRead()) using (NetworkStream networkStream = client.GetStream()) // client为你的TcpClient实例 { // 1. 发送文件名长度(4字节int) byte[] fileNameBytes = Encoding.UTF8.GetBytes(fileInfo.Name); byte[] fileNameLenBytes = BitConverter.GetBytes(fileNameBytes.Length); await networkStream.WriteAsync(fileNameLenBytes, 0, fileNameLenBytes.Length); // 2. 发送文件名内容 await networkStream.WriteAsync(fileNameBytes, 0, fileNameBytes.Length); // 3. 发送文件总大小(8字节long,支持超大文件) byte[] fileSizeBytes = BitConverter.GetBytes(fileStream.Length); await networkStream.WriteAsync(fileSizeBytes, 0, fileSizeBytes.Length); // 4. 分块发送文件内容 byte[] buffer = new byte[BufferSize]; int bytesRead; while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await networkStream.WriteAsync(buffer, 0, bytesRead); } }
服务器修改代码
改为先解析元数据,再根据文件大小循环接收分块,避免一次性占用大量内存:
const int BufferSize = 4096; string receivedFilePath = "文件保存目录"; using (NetworkStream networkStream = currentClient.GetStream()) // currentClient为已连接的TcpClient { // 1. 读取文件名长度 byte[] fileNameLenBuffer = new byte[4]; await networkStream.ReadAsync(fileNameLenBuffer, 0, fileNameLenBuffer.Length); int fileNameLen = BitConverter.ToInt32(fileNameLenBuffer, 0); // 2. 读取文件名 byte[] fileNameBuffer = new byte[fileNameLen]; await networkStream.ReadAsync(fileNameBuffer, 0, fileNameBuffer.Length); string fileName = Encoding.UTF8.GetString(fileNameBuffer); string fullSavePath = Path.Combine(receivedFilePath, fileName); // 3. 读取文件总大小 byte[] fileSizeBuffer = new byte[8]; await networkStream.ReadAsync(fileSizeBuffer, 0, fileSizeBuffer.Length); long fileSize = BitConverter.ToInt64(fileSizeBuffer, 0); // 4. 分块接收并写入文件 using (FileStream fileStream = new FileStream(fullSavePath, FileMode.Create, FileAccess.Write)) { byte[] buffer = new byte[BufferSize]; long totalReceived = 0; int bytesRead; while (totalReceived < fileSize) { // 计算本次需接收的字节数(取剩余大小与缓冲区的最小值) int receiveSize = (int)Math.Min(BufferSize, fileSize - totalReceived); bytesRead = await networkStream.ReadAsync(buffer, 0, receiveSize); if (bytesRead == 0) break; // 处理连接意外断开的情况 await fileStream.WriteAsync(buffer, 0, bytesRead); totalReceived += bytesRead; } } }
关键改进点
- 分块传输:避免大文件一次性加载到内存,降低内存占用
- 明确协议:通过「文件名长度→文件名→文件大小」的元数据顺序,让服务器精准解析传输内容
- 资源安全:所有流对象使用
using语句自动释放,避免内存泄漏 - 可靠接收:通过已接收字节数与文件总大小的对比,确保完整接收所有数据
内容的提问来源于stack exchange,提问作者Fadzii
相关产品推荐
相关产品推荐

