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

基于生产-消费模式,使用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.lryc.cn/news/2397739.html

相关文章:

  • tortoisegit 使用rebase修改历史提交
  • Python----目标检测(《用于精确目标检测和语义分割的丰富特征层次结构》和R-CNN)
  • Ansible 进阶 - Roles 与 Inventory 的高效组织
  • 极简以太彩光网络解决方案4.0正式发布,“彩光”重构园区网络极简之道
  • 国芯思辰| 霍尔电流传感器AH811为蓄电池负载检测系统安全护航
  • TortoiseSVN账号切换
  • 2025年05月28日Github流行趋势
  • 精益数据分析(91/126):商业模式与阶段匹配的指标体系构建
  • 篇章五 数据结构——链表(一)
  • 一文清晰理解目标检测指标计算
  • 【MySQL】索引下推减少回表次数
  • Artificial Analysis2025年Q1人工智能发展六大趋势总结
  • DeepSeek模型高级应用:提示工程与Few-shot学习实战指南
  • Android高级开发第三篇 - JNI异常处理与线程安全编程
  • 企业级应用狂潮:从Spotify到LinkedIn的Llama实战手册
  • 高效管理 Python 项目的 UV 工具指南
  • QT中子线程触发主线程弹窗并阻塞等待用户响应
  • 初识vue3(vue简介,环境配置,setup语法糖)
  • HarmonyOS NEXT~鸿蒙开发工具CodeGenie:AI驱动的开发效率革命
  • LeetCode-链表操作题目
  • 【ARM】MDK浏览信息的生成对于构建时间的影响
  • Python模块中__all__变量失效问题深度解析
  • py爬虫的话,selenium是不是能完全取代requests?
  • docker B站学习
  • SpringBoot高校宿舍信息管理系统小程序
  • 深度解析 Dockerfile 配置:构建高效轻量的FastAPI 应用镜像
  • ICASSP2025丨融合语音停顿信息与语言模型的阿尔兹海默病检测
  • [蓝桥杯]春晚魔术【算法赛】
  • LeetCode - 965. 单值二叉树
  • LabVIEW杂草识别与精准喷洒