当前位置: 首页 > web >正文

基于生产-消费模式,使用Channel进行文件传输(Tcp方式)

Client端:

#region 多文件传输
public class FileMetadata
{public string FileName { get; set; }public long FileSize { get; set; }
}class Program
{const int PORT = 8888;const int BUFFER_SIZE = 60 * 1024 * 1024;//15s-50  25s-64 33s-32 27s-50 31s-40 25s-60const int MAX_CHANNEL_CAPACITY = 1000;static async Task Main(){Console.WriteLine($"Client ready to send file ...");Stopwatch stopwatch = new Stopwatch();stopwatch.Start();var folderPath = @"D:\cuda";//"D:\TestImage\imagesbaiyou";await SendFolderAsync(folderPath, "192.168.10.147");stopwatch.Stop();Console.WriteLine($"Client Transfer file need {TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds)} Milliseconds");Console.ReadKey();}static async Task SendFolderAsync(string folderPath, string server){using var client = new TcpClient();await client.ConnectAsync(server, PORT);using var stream = client.GetStream();int i = 1;foreach (var filePath in Directory.GetFiles(folderPath)){await SendFileAsync(filePath, stream);Console.WriteLine($"Send file {i++} ...");}}static async Task SendFileAsync(string filePath, NetworkStream stream){var fileInfo = new FileInfo(filePath);var metadata = new FileMetadata{FileName = fileInfo.Name,FileSize = fileInfo.Length};// 发送元数据var metaJson = JsonSerializer.Serialize(metadata);var metaBytes = Encoding.UTF8.GetBytes(metaJson);await stream.WriteAsync(BitConverter.GetBytes(metaBytes.Length));await stream.WriteAsync(metaBytes);// 创建传输通道var channel = Channel.CreateBounded<byte[]>(MAX_CHANNEL_CAPACITY);var readTask = FileToChannelAsync(filePath, channel.Writer);var sendTask = ChannelToNetworkAsync(channel.Reader, stream);await Task.WhenAll(readTask, sendTask);}static async Task FileToChannelAsync(string path, ChannelWriter<byte[]> writer){await using var fs = new FileStream(path, FileMode.Open);var buffer = new byte[BUFFER_SIZE];int bytesRead;while ((bytesRead = await fs.ReadAsync(buffer)) > 0){var chunk = new byte[bytesRead];Buffer.BlockCopy(buffer, 0, chunk, 0, bytesRead);await writer.WriteAsync(chunk);}writer.Complete();}static async Task ChannelToNetworkAsync(ChannelReader<byte[]> reader, NetworkStream stream){await foreach (var chunk in reader.ReadAllAsync()){await stream.WriteAsync(BitConverter.GetBytes(chunk.Length));await stream.WriteAsync(chunk);}}
}#endregion

Server端:

 #region 多文件传输2/*优化性能 7.7GB 文件 平均时间约15s完成接受和传送传输时间和硬盘读写速度以及网络硬件成正比关系测试该电脑本地传输速度约15s,固态硬盘将其传输到2.0的U盘当中,传输573MB的图像约46s时间, 和单图直接拷贝的时间差不多±1s的时间*/public class FileMetadata{public string FileName { get; set; }public long FileSize { get; set; }}class Program{const int PORT = 8888;const string SAVE_DIR = @"C:\Users\Leio\Desktop\ServerDownloads";const int BUFFER_SIZE = 1024 * 1024;const int MAX_CHANNEL_CAPACITY = 1000;static Stopwatch stopwatch = new Stopwatch();static async Task Main(){Directory.CreateDirectory(SAVE_DIR);var listener = new TcpListener(IPAddress.Any, PORT);listener.Start();Console.WriteLine("Server started,waiting client connect ...");while (true){var client = await listener.AcceptTcpClientAsync();_ = ProcessClientAsync(client);}}static async Task ProcessClientAsync(TcpClient client){stopwatch.Restart();using (client)using (var stream = client.GetStream()){try{while (true){// 读取元数据var metaSize = BitConverter.ToInt32(await ReadExactlyAsync(stream, 4));var metadata = JsonSerializer.Deserialize<FileMetadata>(Encoding.UTF8.GetString(await ReadExactlyAsync(stream, metaSize)));// 创建传输通道var channel = Channel.CreateBounded<byte[]>(MAX_CHANNEL_CAPACITY);var savePath = Path.Combine(SAVE_DIR, metadata.FileName);// 启动并行任务var receiveTask = ReceiveFileDataAsync(stream, channel.Writer, metadata.FileSize);var saveTask = SaveFileAsync(channel.Reader, savePath);await Task.WhenAll(receiveTask, saveTask);Console.WriteLine($"File saved: {savePath}");//totalTime += stopwatch.ElapsedMilliseconds;}}catch (EndOfStreamException){Console.WriteLine("Connection closed by client");}}stopwatch.Stop();Console.WriteLine($"Client Transfer file need {TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds)} s");}static async Task ReceiveFileDataAsync(NetworkStream stream,ChannelWriter<byte[]> writer,long totalSize){try{long remaining = totalSize;while (remaining > 0){var chunkSize = BitConverter.ToInt32(await ReadExactlyAsync(stream, 4));var chunkData = await ReadExactlyAsync(stream, chunkSize);await writer.WriteAsync(chunkData);remaining -= chunkSize;}}finally{writer.Complete();}}static async Task SaveFileAsync(ChannelReader<byte[]> reader, string savePath){await using var fs = new FileStream(savePath, FileMode.Create);await foreach (var chunk in reader.ReadAllAsync()){await fs.WriteAsync(chunk);}}static async Task<byte[]> ReadExactlyAsync(NetworkStream stream, int count){var buffer = new byte[count];int totalRead = 0;while (totalRead < count){var read = await stream.ReadAsync(buffer, totalRead, count - totalRead);if (read == 0) throw new EndOfStreamException();totalRead += read;}return buffer;}}#endregion

http://www.xdnf.cn/news/9851.html

相关文章:

  • [嵌入式实验]实验四:串口打印电压及温度
  • 嵌赛笔记主控
  • 鸿蒙NEXT应用加固工具哪家更好?国内主流的6款对比
  • 【Redis技术进阶之路】「原理分析系列开篇」探索事件驱动枚型与数据特久化原理实现(文件事件驱动执行控制)
  • 驱动开发学习20250529
  • 贝锐蒲公英工业路由器R300A海外版:支持多国4G频段,全球组网
  • 在Spring Cloud中将Redis共用到Common模块
  • ES中must与filter的区别
  • π0-通用VLA模型-2024.11.13-开源
  • 本地部署大模型llm+RAG向量检索问答系统 deepseek chatgpt
  • linux创建虚拟网卡和配置多ip
  • 【NATURE氮化镓】GaN超晶格多沟道场效应晶体管的“闩锁效应”
  • 关于无法下载Qt离线安装包的说明
  • 《胜算》
  • 力扣每日一题——连接两棵树后最大目标节点数目 ||
  • Relooking:损失权重λ 、梯度权重α、学习率η
  • python + vscode 开发环境搭建
  • [探讨] 如何做好技术文档
  • sourcetree无法获取远程所有的tag
  • C++模板类深度解析与气象领域应用指南
  • Rider崩溃问题终极解决指南
  • 荣誉奖项 | TopOn 荣获 “2025 H1优秀出海产品技术服务” 奖
  • webrtc初了解
  • 【数学】求最大公约数问题
  • mongodb源码分析session接受客户端find命令过程
  • 如何轻松将 iPhone 备份到外部硬盘
  • PostgreSQL学会如何建表
  • 网关Gateway
  • rabbitmq AI复习
  • GB/T 14833-2020 合成材料运动场地面层检测