基于生产-消费模式,使用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
相关文章:
基于生产-消费模式,使用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 25…...
tortoisegit 使用rebase修改历史提交
在 TortoiseGit 中使用 rebase 修改历史提交(如修改提交信息、合并提交或删除提交)的步骤如下: --- ### **一、修改最近一次提交** 1. **操作**: - 右键项目 → **TortoiseGit** → **提交(C)** - 勾选 **"Amend…...

Python----目标检测(《用于精确目标检测和语义分割的丰富特征层次结构》和R-CNN)
一、《用于精确目标检测和语义分割的丰富特征层次结构》 1.1、基本信息 原文标题:Rich feature hierarchies for accurate object detection and semantic segmentation 中文译名:用于精确目标检测与语义分割的丰富特征层次结构 版本:第5版技…...
Ansible 进阶 - Roles 与 Inventory 的高效组织
Ansible 进阶 - Roles 与 Inventory 的高效组织 如果说 Playbook 是一份完整的“菜谱”,那么 Role (角色) 就可以被看作是制作这道菜(或一桌菜)所需的标准化“备料包”或“半成品组件”。例如,我们可以有一个“Nginx Web 服务器安装配置 Role”、“MySQL 数据库基础设置 Ro…...

极简以太彩光网络解决方案4.0正式发布,“彩光”重构园区网络极简之道
5月28日下午,锐捷网络在京举办以“光,本该如此‘简单’”为主题的发布会,正式发布极简以太彩光网络解决方案4.0。作为“彩光”方案的全新进化版本,极简以太彩光4.0从用户需求出发,聚焦场景洞察,开启了一场从底层基因出发的极简革命,通过架构、部署、运维等多维度的创新升级,以强…...

国芯思辰| 霍尔电流传感器AH811为蓄电池负载检测系统安全护航
在电动车、储能电站、不间断电源(UPS)等设备中,蓄电池作为关键的储能单元,其运行状态直接关系到设备的稳定性和使用寿命。而准确监测蓄电池的负载情况,是保障其安全、高效运行的关键。霍尔电流传感器 AH811凭借独特的技…...

TortoiseSVN账号切换
SVN登录配置及账号切换 本文主要为了解答svn客户端如何进行账号登录及切换不同权限账号的方式。 一、环境准备与客户端安装 安装TortoiseSVN客户端 下载地址:TortoiseSVN官网 安装步骤: 双击安装包,按向导完成安装后&#x…...

2025年05月28日Github流行趋势
项目名称:agenticSeek 项目地址url:https://github.com/Fosowl/agenticSeek项目语言:Python历史star数:10352今日star数:2444项目维护者:Fosowl, steveh8758, klimentij, ganeshnikhil, apps/copilot-pull-…...
精益数据分析(91/126):商业模式与阶段匹配的指标体系构建
精益数据分析(91/126):商业模式与阶段匹配的指标体系构建 在创业的不同阶段,企业面临的核心问题与目标差异显著,这就要求我们依据商业模式和所处阶段,动态调整关键指标体系。今天,我们将深入解…...

篇章五 数据结构——链表(一)
目录 1.ArrayList的缺陷 2. 链表 2.1 链表的概念及结构 2.2 链表结构 1. 单向或者双向 2.带头或者不带头 3.循环或者非循环 2.3 链表的实现 1.完整代码 2.图解 3.显示方法 4.链表大小 5. 链表是否存在 key 值 6.头插法 7.尾插法 8.中间插入 9.删除key值节点 10.…...
一文清晰理解目标检测指标计算
一、核心概念 1.交并比IoU 预测边界框与真实边界框区域的重叠比,取值范围为[0,1] 设预测边界框为,真实边界框为 公式: IoU计算为两个边界框交集面积与并集面积之比,图示如下 IoU值越高,表示预测边界框与真实边界框的对…...
【MySQL】索引下推减少回表次数
一、简述索引下推 “索引下推”是数据库领域的一个术语,主要出现在MySQL(尤其是InnoDB存储引擎)中,英文名叫 Index Condition Pushdown,简称 ICP。就是过滤的动作由下层的存储引擎层通过使用索引来完成,而…...

Artificial Analysis2025年Q1人工智能发展六大趋势总结
2025年第一季度人工智能发展六大趋势总结 ——基于《Artificial Analysis 2025年Q1人工智能报告》 趋势一:AI持续进步,竞争格局白热化 前沿模型竞争加剧:OpenAI凭借“o4-mini(高智能版)”保持领先,但谷歌&…...
DeepSeek模型高级应用:提示工程与Few-shot学习实战指南
引言 在DeepSeek模型的实际应用中,提示工程(Prompt Engineering)和Few-shot学习正成为提升模型性能的关键技术。相比全参数微调,这些技术能以更低成本实现领域适配。本文将深入解析DeepSeek模型的高级提示技巧、动态Few-shot实现方案,以及混合微调策略,帮助开发者在资源受…...
Android高级开发第三篇 - JNI异常处理与线程安全编程
Android高级开发第三篇 - JNI异常处理与线程安全编程 Android高级开发第三篇 - JNI异常处理与线程安全编程引言为什么要关注异常处理和线程安全?第一部分:JNI异常处理基础什么是JNI异常?检查和处理Java异常从C代码抛出Java异常异常处理的最佳…...
企业级应用狂潮:从Spotify到LinkedIn的Llama实战手册
当Spotify用Llama生成的个性化推荐文案让用户播放时长激增30%, 当LinkedIn靠开源框架将社交推荐延迟降低40%—— 企业级AI战场正经历从“技术炫技”到“利润引擎”的残酷蜕变。 核心数据:企业采用率爆发式增长(2025 Gartner调研) 指标2023年2025年增幅开源模型采用率42%87%…...

高效管理 Python 项目的 UV 工具指南
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 持续学习,不断…...
QT中子线程触发主线程弹窗并阻塞等待用户响应
目录 QT中子线程触发主线程弹窗并阻塞等待用户响应一、使用QMetaObject::invokeMethod实现子线程安全触发主线程弹窗并阻塞等待:🔧 Qt多线程弹窗:安全阻塞等待方案(QMetaObject::invokeMethod详解)🧠 一、核…...

初识vue3(vue简介,环境配置,setup语法糖)
一,前言 今天学习vue3 二,vue简介及如何创建vue工程 Vue 3 简介 Vue.js(读音 /vjuː/,类似 “view”)是一款流行的渐进式 JavaScript 框架,用于构建用户界面。Vue 3 是其第三代主要版本,于 …...
HarmonyOS NEXT~鸿蒙开发工具CodeGenie:AI驱动的开发效率革命
HarmonyOS NEXT~鸿蒙开发工具CodeGenie:AI驱动的开发效率革命 一、CodeGenie概述 DevEco CodeGenie是华为鸿蒙开发生态中的一款AI辅助编程工具,集成于DevEco Studio IDE中,为开发者提供全方位的智能编程支持。这款工具通过AI技术…...

LeetCode-链表操作题目
虚拟头指针,在当前head的前面建立一个虚拟头指针,然后哪怕当前的head的val等于提供的val也能进行统一操作 203移除链表元素简单题 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(…...

【ARM】MDK浏览信息的生成对于构建时间的影响
1、 文档目标 用于了解MDK的代码浏览信息的生成对于工程的构建是否会产生影响。 2、 问题场景 客户在MDK中使用Compiler 5对于工程进行构建过程中发现,对于是否产生浏览信息会对于构建时间产生一定的影响。在Options中Output栏中勾选了Browse Information后&#…...
Python模块中__all__变量失效问题深度解析
文章目录 Python模块中__all__变量失效问题深度解析一、__all__ 的正确作用场景二、__all__ 不起作用的常见原因1. 未使用 from ... import \* 导入2. __all__ 定义不完整或错误3. 子模块未正确导出4. Python 解释器缓存问题5. 相对导入路径错误 三、解决方案1. 确保使用 from …...

py爬虫的话,selenium是不是能完全取代requests?
selenium适合动态网页抓取,因为它可以控制浏览器去点击、加载网页,requests则比较适合静态网页采集,它非常轻量化速度快,没有浏览器开销,占用资源少。当然如果不考虑资源占用和速度,selenium是可以替代requ…...

docker B站学习
镜像是一个只读的模板,用来创建容器 容器是docker的运行实例,提供了独立可移植的环境 https://www.bilibili.com/video/BV11L411g7U1?spm_id_from333.788.videopod.episodes&vd_sourcee60c804914459274157197c4388a4d2f&p3 目录挂载 尚硅谷doc…...

SpringBoot高校宿舍信息管理系统小程序
概述 基于SpringBoot的高校宿舍信息管理系统小程序项目,这是一款非常适合高校使用的信息化管理工具。该系统包含了完整的宿舍管理功能模块,采用主流技术栈开发,代码结构清晰,非常适合学习和二次开发。 主要内容 这个宿舍管理系…...
深度解析 Dockerfile 配置:构建高效轻量的FastAPI 应用镜像
目录 引言 Dockerfile构建FastAPI镜像的示例 一、基础镜像选择:轻量与安全优先 二、元数据声明:镜像维护者信息 三、依赖管理:分层构建与缓存优化 1. 复制依赖文件 2. 安装依赖 四、应用代码复制:最小化镜像内容 五、启动…...

ICASSP2025丨融合语音停顿信息与语言模型的阿尔兹海默病检测
阿尔兹海默病(Alzheimers Disease, AD)是一种以认知能力下降和记忆丧失为特征的渐进性神经退行性疾病,及早发现对于其干预和治疗至关重要。近期,清华大学语音与音频技术实验室(SATLab)提出了一种将停顿信息…...
[蓝桥杯]春晚魔术【算法赛】
目录 输入格式 输出格式 样例输入 样例输出 运行限制 解决思路 代码说明 复杂度分析 问题描述 在蓝桥卫视春晚的直播现场,魔术师小蓝表演了一个红包魔术。只见他拿出了三个红包,里边分别装有 A、B 和 C 个金币。而后,他挥动魔术棒&a…...
LeetCode - 965. 单值二叉树
目录 题目 深度优先搜索方法 正确的写法 题目 965. 单值二叉树 - 力扣(LeetCode) 深度优先搜索方法 什么是深度优先搜索:深度优先搜索(DFS)是一种图或树的遍历算法,它从起始节点开始,尽可能深地沿着一条路径探索&…...