Squashed commit of the following:

commit 42958203ae40e2cd847d26b610eeb855cd7c2de6
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Nov 22 10:57:43 2025 +0800

    优化(Directory.Packages.props, Program.cs): 升级版本并优化文件传输

    升级 TouchSocketVersion 至 4.0.0-rc.51
    替换同步文件保存为异步方法以提升性能
    新增文件传输多线程配置支持
    新增文件传输插件定义代码块

commit d97e838de5dc35780e434dc091e9fcc5af855766
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Nov 21 21:55:30 2025 +0800

    发布:4.0.0-rc.50

commit d67f7eb691498b5a6c467e4f4fa0e98114b51047
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Nov 20 22:40:35 2025 +0800

    文档(说明): 添加获取 Unity 包的 QQ 群信息

    新增一行说明,告知用户由于 Unity 包体积较大,后续版本需通过 QQ 群(群号:234762506)文件获取。此更改旨在优化分发方式,减少直接下载的压力。

commit 6d32ba351e036c2a266faf29ee4e8820a2658ab8
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Nov 20 21:26:34 2025 +0800

    优化(Directory.Packages.props, Program.cs): 更新依赖版本及代码逻辑

    更新 TouchSocketVersion 至 4.0.0-rc.49
    优化 MyUploadBigFileHttpPlugin 中 fileName 判空逻辑

commit f20a14849c136c4717982b948d761b5e1f483382
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Nov 20 21:23:14 2025 +0800

    新增(donate): 增加三条新的捐赠记录

    在 donate.mdx 文件中新增以下捐赠记录:
    - 捐赠者 C**,金额 66¥,日期 2025 年 10 月 21 日
    - 捐赠者 那**,金额 8.8¥,日期 2025 年 10 月 24 日
    - 捐赠者 偷**,金额 50¥,日期 2025 年 11 月 20 日

commit c8584fc35377aa4c8b6500a9144de05218fca95f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Nov 19 22:46:21 2025 +0800

    发布:4.0.0-rc.48

commit 1420aa1c248cf0c27310368bb0de32cd50ed3975
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Nov 12 20:31:47 2025 +0800

    优化(version): 更新TouchSocket版本及泛型支持

    更新TouchSocket版本号至4.0.0-rc.45
    - TouchSocketVersion.props文件中<BaseVersion>从4.0.0-rc.43更新为4.0.0-rc.45
    - Directory.Packages.props文件中<TouchSocketVersion>从4.0.0-rc.42更新为4.0.0-rc.45

    优化MySerializerFormatter类的TrySerialize方法
    - 方法签名增加泛型支持,从TrySerialize(HttpContext state, in object target, out string source)改为TrySerialize<TObject>(HttpContext state, in TObject target, out string source)

commit c4071aaa5b364954849548b8c98a0f5c533ac16a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Nov 12 20:31:33 2025 +0800

    发布:4.0.0-rc.45

commit 88f69f968d315e573dbc2382d668eebc6b3bcea2
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 11:22:12 2025 +0800

    优化(build脚本): 在构建时传递参数以生成代码

commit ebc386028066f6a4ee42788a8c6887265797af7d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 10:45:38 2025 +0800

    新增(program, rpcdispatcher): 增加Rpc调度器支持

    新增并发、队列、立即调度器配置代码示例
    在Program.cs中新增并发调度器、队列调度器和立即调度器的配置代码,展示了如何通过TouchSocket框架实现不同场景下的Rpc调用调度。
    新增IMyRpcServer接口定义及MyRpcServer实现,支持Rpc服务调用。
    文档中新增调度器说明、使用示例、可重入性控制、最佳实践及性能建议,帮助开发者更好地理解和使用Rpc调度器功能。

commit 9bd8973654bfef92e424b03aa05000b2ba99bc6c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 10:37:08 2025 +0800

    新增(rate-limiting): 添加多种限流策略支持

    新增固定窗口、滑动窗口、令牌桶和并发限流策略
    在 Program.cs 中通过 AddRateLimiter 方法配置限流
    在 MyRpcServer 类中新增 EnableRateLimiting 特性
    文档中替换代码块为 CustomCodeBlock 提升可维护性
    新增自定义分区键限流器示例及详细说明
    新增 RpcFixedWindowLimiter 类支持基于 IP 的限流
    添加版权声明并优化代码注释和文档描述

commit b96a065237acef17178b5e5a78d377798d3943fc
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 10:12:16 2025 +0800

    新增(example): 添加 RpcCallContextConsoleApp 示例项目

    新增 RpcCallContextConsoleApp 示例项目,展示 TouchSocket 框架中 RPC 调用上下文的多种使用方式,包括单例服务、瞬态服务、IRpcCallContextAccessor 和任务取消。更新文档以提供更清晰的代码示例和说明,同时新增客户端和服务端代码,支持多种调用上下文场景。

commit 791c688d8a78bdc2b99117dcd1d3744e712f7886
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 09:59:55 2025 +0800

    新增(RpcAopConsoleApp): 添加RPC AOP示例项目

    新增RpcAopConsoleApp项目,展示RpcActionFilter的使用

    - 在解决方案文件中新增RpcAopConsoleApp项目
    - 在文档中扩展RpcActionFilter功能及使用说明
    - 添加完整控制台应用程序示例,包含日志记录、权限验证、异常处理等特性
    - 定义多个特性类,展示AOP功能及互斥特性实现
    - 新增RpcAopConsoleApp.csproj,目标框架为.NET 9.0,引用TouchSocket相关包
    - 在Program.cs中添加版权声明

commit a87cb8d90e9991c7641b8514bcb56a4f0290832f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 09:38:30 2025 +0800

    新增(Program.cs, rpcgenerateproxy.mdx): 增加代理生成示例及文档优化

    在 Program.cs 中新增多个代理生成示例,包括基本示例、直接添加代理类型、按程序集添加、类型排除等,新增自定义 MyRpcAttribute 类及两个代理类 ProxyClass1 和 ProxyClass2,并扩展 MyRpcClass 的 RPC 方法
    在 rpcgenerateproxy.mdx 中引入 CustomCodeBlock 优化代码展示,替换原有代码块,完善文档结构及提示内容,提升可读性

commit 30c3b29e578c5b8ac0dafd8f3f6abca48f01bca0
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 09:31:18 2025 +0800

    新增(Examples-All.sln): 新增RpcRegisterConsoleApp项目

    新增(Examples-All.sln): 添加RpcRegisterConsoleApp项目引用,配置构建设置并关联父项目

    重构(rpcregister.mdx): 优化文档内容,使用CustomCodeBlock组件替换代码示例,添加CardLink组件链接示例代码,更新源生成注册说明

    新增(Program.cs): 添加完整示例程序,展示RPC服务注册与启动,包括单例服务、接口服务、瞬态服务、区域服务及源生成注册

    新增(RpcRegisterConsoleApp.csproj): 配置项目目标框架为.NET 9.0,启用隐式using和可空引用类型,添加TouchSocket依赖项

    优化(整体): 提升文档模块化与可读性,提供完整示例便于快速上手,确保项目可构建性与可运行性

commit b432ade1fe229141a73c230aa663a8ad9dd37bca
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Nov 11 09:12:39 2025 +0800

    新增(DmtpRpcClientConsoleApp, Program): 支持 MemoryPack 序列化

    修复 DmtpRpcClientConsoleApp.csproj 文件中的 BOM 问题
    新增对 MemoryPack 包的引用
    在 Program.cs 中引入 MemoryPack 的 using 指令
    优化 SetMaxPackageSizeExample 类,改用 SetAdapterOption 配置最大包大小
    优化 ConfigureSerializationSelectorExample 类,改用 UseDmtpRpc 的 options 参数配置序列化选择器
    优化 CustomSerializationExample 类,改用 UseDmtpRpc 的 options 参数设置自定义序列化选择器
    实现 MemoryPackSerializationSelector 类的序列化与反序列化逻辑,移除 NotImplementedException 异常
    使用 WriterAnchor 和 ReaderExtension 优化序列化与反序列化实现

commit 6762fcaca7d8d01b107d6a32ae4507c76f45023a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 22:13:34 2025 +0800

    新增(program,文档): 增加WebSocket命令行插件支持

    新增WebSocket命令行插件客户端调用示例
    新增WebSocket命令行插件注册与声明代码块
    更新文档,详细说明插件功能与使用方式
    优化代码逻辑,替换冗余代码与注释

commit a7ad01f0d543da45e3d44241b5c4dbb7c4548f2b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 22:07:43 2025 +0800

    新增(Program,tcpcommonplugins): 添加TCP健康活性检验插件

    新增TCP健康活性检验插件配置`UseTcpSessionCheckClear`,支持`CheckClearType`、`Tick`和`OnClose`回调函数。
    优化`tcpcommonplugins.mdx`文档,更新插件使用说明,替换代码块为`CustomCodeBlock`,并新增示例代码和教学视频链接。
    新增`websocketclient.mdx`中的Bilibili视频卡片,介绍WebSocket心跳数据包使用。
    删除`websocketheartbeat.mdx`文档及其侧边栏配置项,调整`wscommandlineplugin`文档顺序。

commit 670a837a6487e7aeaa96b5866ef6bcb796daf147
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 21:54:25 2025 +0800

    新增(文档生成规则): 更新示例代码链接描述

    更新文档生成规则,新增示例代码链接路径格式说明,明确多示例链接的添加方式
    在 Program.cs 中新增 TcpCommandLine 创建服务器和命令行插件的代码片段,包含监听地址配置、数据处理适配器选择及异常测试命令
    更新 tcpcommandlineplugin.mdx 文档,扩展 TcpCommandLinePlugin 的特性说明,新增命令方法和调用方式的详细描述,补充高级用法及示例代码链接

commit 96513ebc12ecbdb925bc4c18ccb970488a8d5238
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 21:43:44 2025 +0800

    新增(文档生成.prompt.md, Program.cs, natservice.mdx): 增强文档与代码示例支持

    新增示例 Demo 链接要求,优化文档结构与内容
    - 在文档生成.prompt.md 中新增示例 Demo 链接格式要求
    - Program.cs 中新增 NatService 服务类与多种转发实现
    - natservice.mdx 中引入 CardLink 和 CustomCodeBlock 组件
    - 替换代码块为动态引用,新增示例章节,优化语言表达

commit 9de7d20de4cadacfac061f10a4a90093e2b0ebcf
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 21:32:44 2025 +0800

    新增(示例): 更新插件控制台应用程序,添加插件管理器创建及插件添加示例

commit e32702be2fe655bf9624e1766947fa6cd782573f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 20:58:40 2025 +0800

    新增(示例): 添加其他核心功能控制台应用程序及相关示例代码
    重构(文档): 更新侧边栏,移除数据加密文档

commit bdba014db567d733928d1aea52525760c9094a84
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 20:28:40 2025 +0800

    发布:4.0.0-rc.43

commit 168299775aaa04b261b42da7fdf56e09a05817ff
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 13:31:16 2025 +0800

    重构(docs): 移除Json序列化文档及更新侧边栏

    移除 `jsonserialize.mdx` 文件中关于 JsonFast 和 Newtonsoft.Json 的说明、性能测试代码及对比图。
    更新 `sidebars.ts` 文件,删除 `jsonserialize` 文档引用,并调整后续文档的标签编号以保持顺序连续。

commit f6f874aab69ff15a471a431cc3d8285d9a1c33a0
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 13:29:32 2025 +0800

    新增(示例): 添加依赖属性控制台应用程序及相关示例代码

commit 4216ab2ad8808e41616eb735e3d175c8e550ea5e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 13:21:20 2025 +0800

    新增(示例): 添加AppMessenger控制台应用程序示例及相关文档

commit c79c176631067efa9501af92bb89a326a8b4407d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 13:07:18 2025 +0800

    新增(日志): 增加日志记录器示例及文档优化

commit 25452637f7e09ed606bb68df67ad7e5de20b270d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 12:51:53 2025 +0800

    新增(Program, 文档): 增加文件传输取消功能测试及相关文档示例

commit 6b59c4c62c786a688945c9441f6efeb8a388f92a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 10 12:25:48 2025 +0800

    新增(dmtprpc): 增加DmtpRpc功能与文档优化

    新增DmtpRpc客户端请求与推送流数据功能
    - 添加`RunRpcPullChannel`和`RunRpcPushChannel`方法,支持流数据处理

    新增DmtpRpc限制代理接口声明与配置
    - 声明`IRpcClient1`和`IRpcClient2`接口
    - 添加`MyDmtpRpcActor`类及相关示例

    新增DmtpRpc配置功能
    - 添加路由配置、最大包大小设置、序列化选择器配置
    - 支持自定义序列化类型与Metadata使用

    新增DmtpRpc客户端与服务端功能
    - 支持客户端互相调用与服务端流数据处理
    - 添加`RpcPullChannel`和`RpcPushChannel`方法

    优化文档与示例
    - 更新代码示例,使用`CustomCodeBlock`组件
    - 增加功能示例链接,提升文档可读性

commit f84a415bc15249723655035750f1caa0782c4e1c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 22:12:32 2025 +0800

    修复(generateCodesModule): 修复路径排除逻辑

    修复 `findCsFiles` 函数中路径排除的逻辑问题。原逻辑通过检查整个路径字符串是否包含排除模式来决定是否排除,但这种方式可能导致误判。更新后改为逐个检查路径分段是否与排除模式匹配,从而提高匹配准确性。

commit 5b59f37e1f41317a007a29fa14b39529ed08a3e4
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 22:05:13 2025 +0800

    新增(program,文档): 增加FastBinaryFormatter示例与文档优化

    新增SimpleUsage方法,展示简单序列化与反序列化
    新增内存池块与值类型内存池块使用示例
    新增AddConverter方法,支持自定义转换器
    新增MyClass4类,支持特性优化序列化体积
    新增兼容类型支持示例MyClass2与MyClass3
    新增自定义转换器示例MyClass5与其实现
    新增包模式序列化示例MyClass6
    文档中统一代码示例为<CustomCodeBlock>组件
    移除性能测试章节,优化文档结构与可读性
    调整MyClass3中P2属性为可空类型

commit 36089da4bdd7a75a7fc8e5c84f071f5b3c3a00e3
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 21:33:24 2025 +0800

    新增(container): 增加高级IOC容器示例及生命周期支持

    重构 `NormalContainer.cs`,新增单例、瞬态、作用域生命周期方法,移除属性和方法注入,优化类型定义
    修改 `Program.cs`,调用 `AdvancedContainer.Run` 展示高级功能
    新增 `AdvancedContainer.cs`,提供 ASP.NET Core 容器集成、接口映射、泛型注册等高级示例
    优化 `ioc.mdx` 文档,补充 DI 说明、生命周期管理、高级功能及 API 参考

commit 9542ab711937b38fc259b0fc1f4e1ba58b79402e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 21:12:56 2025 +0800

    重构(udpsession): 整合组播广播及大数据传输内容

    移除 `udpbroadcast.mdx` 和 `udptransmitbigdata.mdx`,将组播、广播及大数据传输内容整合到 `udpsession.mdx` 中,优化文档结构。
    引入 `<CustomCodeBlock>` 组件替代代码块展示,提升代码示例的模块化管理。
    新增 `UdpSessionDocExamples.cs` 文件,提供多种 `UdpSession` 使用场景的代码示例,包括服务器、客户端、组播、广播及大数据传输。
    更新 `sidebars.ts`,简化侧边栏分类,突出 `UdpSession` 组件核心内容。
    移除 `udpwaitingclient.mdx` 和 `webapi.mdx.backup`,精简冗余内容。

commit 08a9c89bde6bed55b6f8e3e61ba825c15629f4e7
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 20:44:16 2025 +0800

    新增(program, waitingclient): 增加WaitingClient使用示例

    增加WaitingClient_FilterFuncRetrigger异步方法,展示筛选函数返回false时触发插件的用法
    增加WaitingClient_WrongUsageInReceived方法,展示Received事件中错误使用WaitingClient的示例
    增加WaitingClient_CorrectUsageInReceived方法,展示Received事件中正确使用WaitingClient的示例
    在waitingclient.mdx中,将原代码示例替换为CustomCodeBlock组件,引用相关代码块

commit 210e4639eb71ba1f3b59143162ec71d4fc7da80f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 20:38:38 2025 +0800

    新增(program,文档): 增强PlcBridge功能演示与文档说明

    新增对PlcBridgeService的初始化、配置和使用示例,包括:
    - 初始化服务,配置Modbus TCP、UDP和串口设备连接器与驱动器
    - 映射虚拟地址到物理设备地址,启动服务,释放资源
    - 定义MyPlcObject类,展示继承PlcObject类并使用PlcField特性
    - 自定义MyModbusHoldingRegistersDrive类,扩展读写逻辑
    - 文档中使用CustomCodeBlock替换代码块,优化结构与说明
    - 新增设备桥接、数据访问、自定义驱动器实现等详细描述

commit f431d7142ae92ebcc1b9b46169bc896593f7967e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 20:31:51 2025 +0800

    新增(program,文档): 支持路由包传输及文档优化

    新增 #region 标记以模块化代码
    新增 MyPlugin1 插件实现路由包响应逻辑
    优化注释内容,提升代码可读性
    更新文档,使用 CustomCodeBlock 和 CardLink
    新增组件引用,增强文档功能性

commit de83e93c8a6a4251db8f3cb2e6f0e975f706f6c6
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 20:24:03 2025 +0800

    新增(Form1, Program, 文档): 增加远程文件系统支持

    在 Form1.cs 中:
    - 添加远程文件系统客户端配置,启用 DmtpRemoteAccess 插件
    - 增加异步连接逻辑及目录信息获取功能

    在 Program.cs 中:
    - 配置服务器端远程文件系统插件,新增 MyRemoteAccessPlugin 插件
    - 实现 IDmtpRemoteAccessingPlugin 接口处理远程访问请求

    在 dmtpremoteaccess.mdx 文档中:
    - 使用 CustomCodeBlock 优化代码示例展示
    - 新增隐私性警告,强调访问许可的重要性
    - 替换示例 Demo 链接为 CardLink 组件

commit f4cd6a604e396cc211b02b194cd788be24d08dc4
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 20:10:10 2025 +0800

    新增(settings, Program, 文档): 添加远程流映射支持及配置优化

    新增 cSpell 拼写检查配置,优化 Git 提交及文件编码设置
    新增远程流映射功能,包括请求端和响应端插件实现
    优化文档结构,使用自定义代码块组件展示示例
    新增多种代码片段,提升 Markdown 和代码编写效率

commit 7da2b3a3d712a463650cb0aac103ff6953f5990a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 19:54:10 2025 +0800

    新增(program,文档): 增加Redis支持及相关文档说明

    新增Redis客户端和服务器配置代码,支持缓存持久化
    优化文档生成路径定义,明确src和examples结构
    新增Redis特性、使用方法、缓存持久化及序列化说明
    新增代码示例链接,完善Redis相关文档内容

commit d46ebe5ae9c89fe782618804ddbd0542f44f624e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 15:16:35 2025 +0800

    优化(packages): 更新 TouchSocket 版本

    将 Directory.Packages.props 文件中的 <TouchSocketVersion> 属性值从 4.0.0-rc.38 更新为 4.0.0-rc.42

commit 29ca8d21aa9951da83947c8580fe232228dd3639
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 15:14:38 2025 +0800

    新增(solution): 添加ConsoleActionConsoleApp项目

    新增ConsoleActionConsoleApp项目到解决方案,配置相关构建设置
    优化consoleaction.mdx文档,重构内容并使用CustomCodeBlock引用示例代码
    新增示例代码,展示ConsoleAction功能,使用region标签包裹
    定义文档生成规则,确保代码示例规范并与示例工程一致

commit bb73ced3a575b1092a4e97d29e6fe1b3453b8c9e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 14:59:58 2025 +0800

    优化(文档): 优化文档代码规范与示例引用

    更新文档代码规范,统一使用CustomCodeBlock标签替换代码示例,确保与示例工程一致;优化region标签命名规则,增加多线程协作与数据转换示例;更新示例工程链接与API参考,提升文档可读性与一致性。

commit a0d368fc40fa33b2b1f792a259dd54511240f6f8
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 14:36:07 2025 +0800

    文档(webapi-client): 替换代码块为CustomCodeBlock引用

    优化文档生成模式,明确禁止直接包含C#代码块,所有代码示例需在示例工程中编写并使用region包裹;在文档中统一使用CustomCodeBlock引用代码示例,确保内容清晰且与示例工程一致;新增对WebApiClient和WebApiClientSlim的核心优势、适用场景和配置说明的描述;删除重复代码示例,优化代码生成部分,明确服务端代码生成和客户端代理使用流程;完善文档生成规则,规范region标签命名和代码示例编写要求。

commit ae5c9ae31e9d53b37b8bfa6b51284bd4bce7a5e5
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 13:58:07 2025 +0800

    新增(ApiServer,MyApiServer,webapi-context): 增加WebAPI功能及文档更新

    新增多个WebAPI方法,支持自定义响应状态码、设置响应头、设置Content-Type、流式响应、获取客户端信息及条件响应;在MyApiServer中新增WebSocket升级功能;更新webapi-context文档,使用CustomCodeBlock替换代码示例,优化文档结构及内容。

commit 100ae035967a486de50367d413c614cd418dedd7
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 13:03:12 2025 +0800

    新增(core): 增加异常处理、插件及WebAPI支持

    新增异常处理类和插件:
    - 添加CloseException类,用于触发异常
    - 添加ClosePlugin插件,拦截异常并关闭连接
    - 添加MyPluginClass和MyServicePluginClass插件

    新增服务和客户端创建方法:
    - 新增CreateCustomService、CreateDefaultService等服务创建方法
    - 新增CreateDefaultTcpClient、CreateReconnectionTcpClient等客户端方法

    新增WebAPI支持:
    - 增加多种路由配置,包括默认、自定义和正则路由
    - 新增文件上传、下载及流式响应方法
    - 添加跨域配置支持,支持全局、类级和方法级CORS策略

    优化代码结构与文档:
    - 重构部分方法,提升代码可读性
    - 新增CustomCodeBlock标签,规范文档代码引用
    - 补充参数绑定、路由配置等最佳实践

commit 4730de41be0cf16b37b16ba652581d496b035666
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 12:56:30 2025 +0800

    发布:4.0.0-rc.42

commit a45f3154d3bac0abefbeb93e04a83e7c214e4875
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Nov 9 08:33:04 2025 +0800

    文档(webapi): 拆分WebAPI文档并新增多模块

    重构WebAPI文档结构,新增路由、参数绑定、调用上下文、客户端调用、数据序列化、鉴权与授权、跨域配置、AOT支持、静态文件服务等模块。更新侧边栏以反映新的文档结构,优化内容组织和可读性。

commit 4176127f178558a920f5dafc148dbd96fbe779db
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Nov 8 16:01:32 2025 +0800

    优化(Program.cs): 重构方法逻辑与代码结构

    重构 `Program.cs` 中多个方法,提升代码可读性与健壮性:
    - 优化 `Main` 方法,添加命令注册逻辑
    - 重构 `SimpleRun`、`Performance`、`MultiParameters` 等方法,使用 `#region` 分块,统一变量命名
    - 增强异步方法 `TaskRun` 和 `TaskObjectRun` 的逻辑处理

    新增多个功能模块,扩展项目功能:
    - 新增 `MethodCache` 静态类,提供推荐的缓存方式
    - 新增 `ApiServer`、`DemoApiServer`、`MyApiServer` 等 Web API 示例
    - 新增 `AuthenticationPlugin` 和 `CustomResponseAttribute`,支持鉴权与自定义响应
    - 新增 `MyActionFilterAttribute` 和 `MySerializerFormatter`,支持扩展点与日志记录

    优化文档与注释,增加版权声明,提升开发者体验。

commit 4cf01340e7768a8e9c9afd13b7b14dc65ccd4ded
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Nov 8 14:33:56 2025 +0800

    新增(动态方法调用): 增加示例代码与文档优化

    新增多个动态方法调用示例,包括同步、异步、`out` 和 `ref` 参数、自定义特性标记方法调用等;提供性能测试代码,展示缓存 `Method` 实例的优化方式;重组文档结构,新增“说明”、“特性”、“快速开始”等章节;更新动态方法调用模块说明,强调源生成器优先级及 AOT 环境优势;移除冗余内容,使用 `<CustomCodeBlock>` 提升文档可维护性;新增注意事项,明确标记方法要求及源生成器限制;更新示例项目链接以便快速访问。

commit 15a9798e785875fcc188780f42c28fb00b38672a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Nov 7 22:54:57 2025 +0800

    优化(packages): 更新 TouchSocket 版本

    将 Directory.Packages.props 文件中的 <TouchSocketVersion> 属性值从 4.0.0-rc.54 修改为 4.0.0-rc.38,回退版本以满足兼容性需求。

commit 0c17c2570e966725b62a7952a66031a6f14a065f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Nov 7 22:52:46 2025 +0800

    发布:4.0.0-rc.38

commit f21e2cf9f36e99cefd20ab331358772cc681d481
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Nov 7 22:42:54 2025 +0800

    重构(Program.cs): 提取命令注册逻辑并优化示例

    重构主程序逻辑,提取命令注册到独立方法,新增全局异常处理,优化性能测试与异步调用逻辑。
    更新 MyClass 方法,添加注释与更清晰的输出,移除冗余代码。
    升级 TouchSocket 至 4.0.0-rc.54,优化重连逻辑,改用 UseDmtpCheckAction。
    改进大数据 HTTP 写入逻辑,支持 PipeWriter,新增 System.IO.Pipelines 引用。

commit 3c6f862fcdf8e6871fe2fc5cc73ce9fb8239b261
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Nov 6 10:40:43 2025 +0800

    新增(Program): 增加基于容器的TcpService创建方法

    增加两个方法CreateService_AspNetCoreContainer和CreateService_Container,分别支持基于AspNetCore容器和普通容器的TcpService实例创建
    修改Main方法以支持多端口监听(8848和8849)
    在CreateService_AspNetCoreContainer中集成AspNetCore IOC容器并添加作用域插件MyScopedPlugin
    在CreateService_Container中配置普通容器,支持日志记录器并添加插件MyScopedPlugin
    新增插件类MyScopedPlugin,支持从IOC容器中获取并实现Tcp相关接口

commit 987619f588d389df458d125fd68417ba72cd6674
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Nov 3 22:30:55 2025 +0800

    发布:4.0.0-rc.37

commit 995f8a54d83027390176c11bf745ebde5003fbb5
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Nov 1 09:15:26 2025 +0800

    发布:4.0.0-rc.15

commit f0649c91ba06f20f89f6bc4ee8eb344de3638c54
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 30 22:04:24 2025 +0800

    优化(program, dmtpbase): 优化通道逻辑与文档内容

    ### 变更内容
    - 升级 TouchSocketVersion 至 4.0.0-rc.11
    - 优化 TcpDmtpClient 通道创建与写入逻辑
      - 使用 using 管理资源释放
      - 增加通道可写性检查与写入超时设置
    - 新增 Dmtp 心跳重连插件
      - 配置重连间隔与自定义连接检查逻辑
    - 新增 MyPlugin 插件,支持订阅与处理 Channel 数据
      - 持续读取数据并支持超时与状态处理
    - 删除 dmtpbase.mdx 冗余代码示例
      - 简化 Channel 终止语句说明
      - 优化心跳与断线重连文档内容
    - 提供示例代码链接,提升文档可读性

commit 4948cf3699d2fd698e20b75ba101705b34ecbaef
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 30 20:17:37 2025 +0800

    优化(packages, program, dmtp): 更新依赖与代码改进

    更新 TouchSocket 版本至 4.0.0-rc.10
    新增 Dmtp 消息发送功能示例,避免协议冲突
    优化 ModbusMaster 接口操作与代码风格
    调整文档 Id 同步与协议发送数据说明
    补充 Flags 使用限制,提升文档可读性

commit 7bec9c511e75a55cdfca4eb1a703b40c2527c219
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 30 20:09:35 2025 +0800

    发布:4.0.0-rc.10

commit e6ad87ae81238bb6d62988b439a1f80eee69c491
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Oct 28 08:53:31 2025 +0800

    优化(VotingModal): 修改弹窗显示状态存储方式,使用 sessionStorage 替代 localStorage

commit 3722712e21c451d7b104d890e7a63df29d438967
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Oct 27 16:32:07 2025 +0800

    优化(config, footer): 更新统计链接及脚本标识

    更新导航栏中“统计”链接地址,指向新的统计页面
    更新脚本标签中的 data-website-id,匹配新的统计配置

commit 518b3b7a7303c7c62440fda45248cff9b44d6a86
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Oct 27 14:53:59 2025 +0800

    优化(config, footer): 更新统计链接及脚本配置

    更新导航栏中“统计”链接地址,指向新的资源配置
    更新脚本标签的 data-website-id 属性值

commit 78545f2177b530485758a9706f41c21de04a73c3
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Oct 27 12:36:36 2025 +0800

    优化(docs): 更新 enterprise.mdx 和 websocketclient.mdx

    更新 enterprise.mdx 中 Pro 组件的导入路径
    补充 websocketclient.mdx 中 WebSocket 断线重连内容,包括代码示例和视频资源链接
    优化文档内容展示,帮助用户更好理解相关功能

commit 0bdabe5b7f73c9e9343468e3c3ed889004a2a34c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Oct 27 10:33:44 2025 +0800

    优化(config, index): 更新统计链接及脚本标识

    更新内容:
    - 修改 `docusaurus.config.ts` 中导航栏 "统计" 的链接地址
      - 原链接:`https://touchsocket.net:10086/share/xrJem0HUaiTQjMHS/touchsocket.net`
      - 新链接:`https://touchsocket.net:10086/share/52srUBHSadfSOngf/touchsocket.net`
    - 修改 `index.tsx` 中 `<script>` 标签的 `data-website-id` 属性值
      - 原值:`1944f8fa-c237-4d42-9fb2-ee1ee6d5c973`
      - 新值:`9a4065f2-8c32-4727-9b5f-bc6a92843fa5`

commit 34b7833375beb144f292992643c96bcabe67384e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Oct 26 20:41:27 2025 +0800

    文档(reconnection): 移除断线重连相关内容

    移除文档中关于断线重连和Polling轮询连接插件的所有内容,包括说明、代码示例、注意事项和提示。删除了标题和导入的组件代码(`Tag` 和 `TouchSocketDefinition`),以及 `UseReconnection` 插件的相关描述。

commit 9edd654f554ca98a645b3ec1444bce3654c5143f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Oct 26 19:38:46 2025 +0800

    文档(modbus): 更新Modbus协议文档内容

    新增Modbus总线协议特性章节,详细描述主从架构、共享通信媒介、半双工通信等特性,补充典型应用场景及与点对点协议对比内容。优化Modbus TCP报文格式,新增MBAP头解释、报文结构表及完整报文示例。更新docusaurus.config.ts文件中的统计链接地址,调整index.tsx文件中的脚本配置,移除百度统计脚本。

commit 12d0c360d90542905fb92080e53240a903b5f229
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Oct 26 11:42:29 2025 +0800

    新增(voting-modal): 添加投票弹窗功能

    新增 VotingModal 组件及样式文件,支持全局显示投票弹窗
    - VotingModal.module.css: 定义弹窗样式,支持暗色主题和移动端适配
    - VotingModal.tsx: 实现弹窗逻辑,支持延迟显示、关闭及投票操作
    - Root.tsx: 在根组件中集成 VotingModal,确保全局显示
    弹窗通过 localStorage 控制显示频率,优化用户体验

commit 1e7ced6cf9b8b30f47aad82387bcad0e74a6ae95
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Oct 26 11:34:05 2025 +0800

    优化(modbus): 优化Modbus协议描述及错误处理

    对Modbus协议文档进行全面优化,主要包括:
    - 更新TouchSocket版本至4.0.0-rc.2
    - 补充Modbus RTU报文格式的详细说明,新增字段表和示例
    - 增加功能码响应格式详解,提供C#代码示例及数据长度计算规则
    - 优化异常响应处理,补充功能码识别逻辑及异常代码说明
    - 增加TouchSocket特有错误处理逻辑及扩展错误代码
    - 调整Modbus TCP报文格式字段表,优化数据域描述

commit 5e42a7326be70a2d8c2fc340c67fbb51d37178b4
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 25 22:21:23 2025 +0800

    文档(upgrade-to-4-0): TouchSocket 4.0升级指南更新

    更新升级指南以适配TouchSocket 4.0版本
    - 重命名WebSocket插件接口
    - 数据接收参数从ByteBlock改为Memory
    - 自定义适配器泛型化支持
    - 优化二进制数据读写方式
    - 提升内存管理与性能优化建议
    - 增加常见问题解答与升级检查清单

commit cc5625f03d54e9ea5e7001abbff96a59e979cfd3
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 25 22:01:15 2025 +0800

    文档(upgrade): 添加 TouchSocket 4.0 升级指南

    新增 TouchSocket 4.0 升级指南文档,详细说明从 3.x 到 4.0 的主要语法差异和升级方法。更新 index.mdx 文件中的链接地址,指向新升级指南。移除对 .NET Framework 4.5 的支持,最低支持版本调整为 .NET Framework 4.6.2。异步方法不再提供同步版本,所有异步方法需使用 await 调用。重构核心字节流处理系统和数据适配器架构,提升性能和数据处理能力。

commit dbb8d8c0fc0d9eb151b222af221100092e7cc754
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 25 19:40:12 2025 +0800

    新增(index): 支持.NET 9.0及新增WebSocket功能

    调整 `index.mdx` 文件标题及内容:
    - 移除对 `.NET Framework45` 的支持,最低支持 `.NET Framework462`
    - 异步方法不再提供同步版本,需使用 `await` 调用
    - 新增 `WebSocket` 异步读取、分包传输、自定义帧等功能
    - 新增 `DMTP` 协议多传输协议支持
    - 升级至 `.NET 9.0` 框架

    优化 `WaitPool` 内部结构,支持高并发场景

    新增 `TouchSocket.Http & WebSocket` 多项功能:
    - `HttpClientBase2` 重构版本
    - 新增 `ContentCompletionStatus` 枚举、零拷贝内存块读取等

    移除项目管理优化及示例项目相关内容:
    - 包括中央包管理、自动化脚本、示例项目等

    调整 WebSocket 插件接口及方法命名:
    - `IWebSocketHandshakingPlugin` → `IWebSocketConnectingPlugin`
    - `OnWebSocketHandshaking` → `OnWebSocketConnecting`

    新增 `v3-1.mdx` 中 `v3.1.19` 版本更新:
    - 修复 `TcpClient` 连接失败时未释放资源问题

commit 52e9c05a38c12d0dc298a11daf951baabc9ece35
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 25 12:28:48 2025 +0800

    文档(index): 替换升级文档并新增 v4.0.0 更新内容

    移除 `upgrade.mdx` 文件,新增 `index.mdx` 文件以替代,记录 TouchSocket v4.0.0 更新内容。
    新增模块更新说明,涵盖 WebSocket、DMTP、JsonRpc 等协议支持与改进。
    引入中央包管理和 .NET 9.0 框架升级,提供迁移指南与示例项目。
    调整 WebSocket 插件接口命名与配置方式,优化开发体验。

commit 983d92509a33f403e3ff929888eccc52c289a304
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 24 15:06:48 2025 +0800

    新增(description): 增加投票活动与课程宣传内容

    在 `description.mdx` 文件中:
    - 引入 `CustomCodeBlock` 模块。
    - 添加 Gitee 2025 最受欢迎开源软件投票活动的提示块,包含投票链接及说明。
    - 添加 C# TouchSocket 网络通信开发课程上线的提示块,详细介绍课程内容、适用人群及学习支持。

commit 2e7590727e99534bf85124f0a2149a239103149b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Oct 22 22:29:50 2025 +0800

    新增(sidebars, modbusdescription): 更新Modbus文档结构

    在 `Program.cs` 中优化 `SetListenIPHosts` 方法调用,简化配置
    在 `sidebars.ts` 中调整侧边栏,新增和重命名Modbus相关项目
    新增 `modbusdescription.mdx` 文件,详细介绍Modbus协议

commit b4913a2a93bfc74d8240100ae8cfdbaf71bf90a2
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Oct 22 20:43:59 2025 +0800

    优化(program,form1,dmtprpc):优化DmtpRpc功能与文档说明

    统一DmtpRpc相关代码风格,优化插件配置方式
    移除冗余代码,提升代码可读性与维护性
    新增反向DmtpRpc服务与代理调用支持
    更新文档示例,增强Rpc调用与配置说明
    升级TouchSocket版本至4.0.0-rc.1

commit 3b2a84d838f6be4b39d344c83cbd02df6db91383
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Oct 22 20:37:39 2025 +0800

    发布:4.0.0-rc.1

commit f51fd5cf5fa39602b7d141b35ee0d011752df587
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 18 15:26:09 2025 +0800

    发布:4.0.0-beta.140

commit 7201a0ae5fbb642dbdfdab1f4f7956513b4b16c0
Author: Diego <82756760+kimdiego2098@users.noreply.github.com>
Date:   Sat Oct 18 14:49:51 2025 +0800

    AsyncWaitData token回调释放 (#92)

    * pref: 热点路径减少acition对象

    * pref: 热点路径减少acition对象

    * AsyncWaitData池化

    * AsyncWaitData池化

    * AsyncWaitData token回调释放

    * AsyncWaitData 池化性能优化

    * AsyncWaitData

commit 90c394a20f9db5a5b94ab066c1582c12aabedbb7
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 18 11:34:19 2025 +0800

    优化(mqttclient): 优化Mqtt客户端文档与代码示例

    更新TouchSocket版本号至4.0.0-beta.137
    调整技术文档写作规范,明确内容组织逻辑
    重构Mqtt客户端代码示例,使用CustomCodeBlock模块化
    新增Mqtt客户端功能描述,包括自动重连与插件机制
    优化注意事项格式,突出协议兼容性与最佳实践

commit f168ded803f5233f1e72a2f382e2502ce97369c4
Author: Diego <82756760+kimdiego2098@users.noreply.github.com>
Date:   Sat Oct 18 08:59:51 2025 +0800

    AsyncWaitData池化 (#91)

    * pref: 热点路径减少acition对象

    * pref: 热点路径减少acition对象

    * AsyncWaitData池化

    * AsyncWaitData池化

commit 5791379b1b65066be6012aa96db1178fc76488b9
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 17 21:39:50 2025 +0800

    重构(program): 重构重连逻辑并新增MQTT功能

    重构 `Program.cs` 和 `Form1.cs` 中的重连逻辑,统一使用新的 `UseReconnection` 配置选项,支持更灵活的轮询间隔和检活策略。
    新增 MQTT 客户端功能,包括订阅主题、检查连接状态、发布消息(支持高性能发布)、取消订阅等。
    新增多个 MQTT 插件类,优化客户端和服务器的插件配置。
    重构 TCP 和 HTTP 客户端的重连逻辑,统一使用新配置。
    优化代码格式,修复缩进问题,替换部分同步调用为异步调用。
    新增 `InitIdPluginWithIpPort` 插件,用于 TCP 服务器连接时以 `IPPort` 作为 ID。

commit ffe9998943b6aee4748c9e6a2e1fd0dc78fb60a9
Author: Diego <82756760+kimdiego2098@users.noreply.github.com>
Date:   Fri Oct 17 21:31:35 2025 +0800

    pref: 热点路径减少acition对象 (#90)

    * pref: 热点路径减少acition对象

    * pref: 热点路径减少acition对象

commit 5f0d095025ca92a3a79d778dca1c03fca30e3499
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 17 21:05:19 2025 +0800

    发布:4.0.0-beta.135

commit f115373baedee96aa3bf23f888c55a3eab7781dc
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 16 21:33:57 2025 +0800

    发布:4.0.0-beta.130

commit aae51b3810071ab3b27bcb026e7b53a782f82002
Author: Sunny <53289193+yhuse@users.noreply.github.com>
Date:   Thu Oct 16 16:04:28 2025 +0800

    修改 ConcurrentList.cs 一处错误代码,移除一处不必要的引用。 (#88)

    * Update ConcurrentList.cs

    修改错误的代码

    * Remove unused Newtonsoft.Json.Linq using directive

    移除不必要的引用

commit 5cec2b4c908ad568f338c6ddfd28f8befc4abb09
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Oct 14 22:08:32 2025 +0800

    重构(program): 重构Mqtt服务器逻辑并优化文档

    重构Mqtt服务器的创建逻辑,移除内联配置代码,改为通过`TouchSocketConfig`对象配置,提升模块化和可读性。
    新增服务器停止和资源释放功能,支持获取和断开客户端连接。
    新增插件化消息接收逻辑,支持通过`IMqttReceivingPlugin`和`IMqttReceivedPlugin`处理Mqtt消息。
    优化文档结构,替换代码示例为引用代码块,新增功能模块说明,移除冗余内容。

commit f57b36294a9309769064a7543f5e633f235fabba
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 10 23:00:01 2025 +0800

    优化(styles): 更新样式和依赖版本

    更新 TouchSocketVersion 至 4.0.0-beta.112
    优化 index.css 样式:
    - 更新容器背景为渐变,添加模糊效果
    - 移除旧代码高亮样式,新增暗色模式支持
    - 调整代码高亮行样式

commit 51639dfb8b0a48ceef00059faf75514a82c08f45
Merge: 6ba0cc5b0 ae5464e98
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 9 23:21:54 2025 +0800

    Merge branch 'v4.0.0-Alpha' of https://github.com/RRQM/TouchSocket into v4.0.0-Alpha

commit 6ba0cc5b082f9eeda5bf7e5ecf91816446fd07d1
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 9 23:21:40 2025 +0800

    发布:4.0.0-beta.100

commit cc5be2e90db20cf9eb86e4647e810270a629202c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 9 23:20:26 2025 +0800

    重构(Program.cs): 调整DmtpRpc调用方式以支持更多配置

    调整DmtpRpc调用方式,新增options参数以支持序列化器配置(如FastSerializerContext和System.Text.Json)。
    优化SetDmtpOption调用格式,统一代码风格。
    调整DmtpRedis和DmtpFileTransfer调用方式,支持缓存和小文件限制配置。
    新增对SetCreateDmtpRpcActor和SerializationSelector的支持,增强自定义能力。
    微调代码格式和参数空格,提升代码可读性。

commit ae5464e984eb02072f2d6161a3616d9a98704c7b
Author: 若汝棋茗 <76547834+RRQM@users.noreply.github.com>
Date:   Thu Oct 9 07:29:25 2025 +0800

    更新 description.mdx

commit f371c952ee6fe0176204d551ef7656398509819f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Oct 7 16:11:32 2025 +0800

    新增(program, namedpipeclient): 增强NamedPipe客户端功能

    对Program.cs中的Program类进行功能增强:
    - 添加无限循环以发送数据
    - 新增RunAsyncReceived方法实现异步阻塞接收及断线重连控制
    - 抽取NamedPipeClient配置逻辑至GetConfig方法
    - 新增插件类MyNamedPipeReceived处理接收数据
    - 新增继承类MyNamedPipeClient自定义接收逻辑

    对namedpipeclient.mdx文档进行优化:
    - 修改代码块区域标识符
    - 删除数据包大小限制、缓冲区设置等冗余内容
    - 删除部分示例代码块,添加NamedPipe重连插件相关内容
    - 调整文档结构以提升简洁性

commit a437991e7179b9adeb74edd0da8a8d624731e85d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Oct 7 11:16:38 2025 +0800

    新增(CustomCodeBlock): 增加构建环境检测及优化错误处理

    新增构建环境检测函数`isBuildEnvironment`,用于判断是否为构建环境,在构建阶段捕获关键错误并阻止发布。优化`CustomCodeBlock`组件的错误处理逻辑,构建环境中抛出异常,开发环境中提供更友好的调试信息。调整`showAvailableRegions`默认值为`false`以减少不必要提示。更新`namedpipeclient.mdx`文档,模块化代码示例,新增多项配置说明及高级示例,提升文档可读性与动态性。

commit db456779c9f1d7ac83da508796e80b8dced78395
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Oct 6 21:50:20 2025 +0800

    文档(mdx): 统一定义部分为组件化格式

    对多个 `.mdx` 文件进行文档优化:
    - 移除标题 `### 定义`,替换为 `<TouchSocketCoreDefinition />` 或其他相关组件
    - 调整部分文件标题内容,如 `datasecurity.mdx` 改为 `## 一、3DES`
    - 移除部分文件中 `BilibiliCard` 的导入
    - 在部分文件中新增或调整 `<Pro />` 标签
    - 统一文档结构和内容格式,提升可读性和一致性

commit f2f4716d0c0aa4fa839e35eb2dc9569fae6cada3
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Oct 6 21:36:53 2025 +0800

    重构(UnityRpcProxy): 重构RPC接口及数据模型

    重构`UnityRpcProxy_HttpDmtp.cs`、`UnityRpcProxy_Json_HttpDmtp.cs`和`UnityRpcProxy_TcpDmtp.cs`中的RPC接口和实现类,优化命名空间`using`指令,移除版权声明注释。
    更新`Directory.Packages.props`文件中的TouchSocket版本号至`4.0.0-beta.101`。
    重写扩展方法和数据模型类,添加`[AsyncToSyncWarning]`特性标记。

commit f20ad06f5ad11ffd7edbbf6faf4b8a951bed0a80
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Oct 6 15:25:18 2025 +0800

    重构(RpcProxy): 重构RpcProxy代码结构和功能

    对RpcProxy.cs文件进行重构,优化接口和类定义,新增扩展方法以增强功能,调整代码格式以提升可读性
    - 删除版权声明注释,调整using语句顺序
    - 重新定义IXmlServer接口,新增[AsyncToSyncWarning]特性
    - 重构XmlServer类,保留Sum和TestClass方法及其异步版本
    - 新增XmlServerExtensions静态类,提供扩展方法Sum和TestClass
    - 移动MyClass类至文件末尾

    注释掉docusaurus.config.ts中的future配置项,暂时禁用Docusaurus v4相关功能
    - 注释v4和experimental_faster设置

    更新package.json依赖,支持性能优化
    - 新增@docusaurus/faster依赖,版本^3.9.1
    - 删除overrides配置,移除对特定依赖版本的覆盖

commit 75447a4ddd986f4dbaad8f4ecbbf2f2ee3eb63d8
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Oct 5 22:08:55 2025 +0800

    优化(program, props, docs): 调整XmlRpc调用方式及文档改进

    调整Program.cs中XmlRpc调用方式,优化代码结构
    升级TouchSocket版本至4.0.0-beta.98
    改进jsonrpc.mdx和xmlrpc.mdx文档内容,增加示例
    优化文档排版,补充核心特点及使用说明
    新增对反向RPC、序列化配置及AOT支持的说明

commit d4a7e4a3bb39db19008f333098cffa1ca180a334
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Oct 5 17:55:51 2025 +0800

    发布:4.0.0-beta.96

commit 7da9464943e522557b25fea23104b8211524d30a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Oct 5 00:07:46 2025 +0800

    优化(package.json): 升级依赖版本

    升级以下依赖版本:
    - `@easyops-cn/docusaurus-search-local` 从 `^0.40.1` 升级到 `^0.52.1`
    - `node-gyp` 从 `^10.1.0` 升级到 `^11.4.2`
    - `react` 和 `react-dom` 从 `^18.0.0` 升级到 `^19.2.0`
    - 开发依赖 `@docusaurus/module-type-aliases`、`@docusaurus/tsconfig` 和 `@docusaurus/types` 从 `^3.8.1` 升级到 `^3.9.1`
    - `typescript` 从 `~5.2.2` 升级到 `^5.9.3`

commit 5713b9445f5944ac0ec2d36aa2837cd26b1e4831
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 4 22:28:04 2025 +0800

    优化(project): 更新依赖版本与配置调整

    更新 TouchSocket 版本至 4.0.0-beta.95
    调整 Swagger 配置以提升可读性
    更新文档编辑链接至 GitHub
    优化导航栏 Gitee 标签名称

commit 9eacd8d45ecebd1a8423931d218764006f1e753b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Oct 4 14:12:07 2025 +0800

    优化(program): 优化JsonRpc配置与TouchSocket版本更新

    更新TouchSocket版本至4.0.0-beta.94

    - 优化JsonRpc客户端配置,统一使用SetJsonRpcOption链式调用
    - 调整HttpJsonRpc插件配置,替换SetJsonRpcUrl为SetAllowJsonRpc
    - 新增JsonRpc序列化器配置区域,支持AOT类型
    - 重命名Modbus相关属性为DataLocater,更新相关调用
    - 优化命名管道配置方法,调整方法命名
    - 优化WebApi插件配置,增强灵活性
    - 新增JsonRpc序列化配置文档,完善Newtonsoft.Json与System.Text.Json配置说明
    - 清理冗余代码与注释,提升代码可读性

commit c55e014f9ee12db153c32f783b280fc1a3f0af1a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 3 14:42:48 2025 +0800

    新增(program): 增加JsonRpc客户端与反向Rpc支持

    新增对TouchSocket.Rpc和Sockets的引用,优化代码结构,添加JsonRpcInvoke和RpcTestJsonRpc方法,支持直接调用与代理调用。新增反向Rpc服务ReverseJsonRpcServer及插件MyPluginClass,支持服务器主动调用客户端。更新文档,使用CustomCodeBlock优化示例,补充反向Rpc说明。清理冗余代码,提升可读性。

commit 44b04fc15d80642575e81472a9b7015eaa96ba6d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 3 13:55:16 2025 +0800

    重构(Program, JsonRpcProxy, 文档): 重构客户端与服务端代码

    重构客户端代码以支持异步调用,优化服务端配置逻辑,提升代码可读性与复用性。
    重构 `JsonRpcProxy` 接口与类,统一代码风格,添加异步调用警告标记。
    更新文档,使用 `CustomCodeBlock` 提升模块化与可维护性,优化示例代码展示。

commit 2e4f75a0b485d63fa46a36606298a034c789f857
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 3 08:44:32 2025 +0800

    重构(scripts): 删除无用脚本和配置清理

    删除多个与 .mdx 文件处理相关的脚本,包括 replace-links.js、debug-definition.js、fix-definition-imports.js、replace-definitions-precise.js、replace-definitions.js、test-precise-detailed.js、test-precise.js、test-single-file.js 和 validate-imports.js。这些脚本涉及递归文件处理、定义解析、组件生成、导入修复和验证逻辑,可能已不再需要或功能被重构到其他地方。

    修改 tsconfig.json,移除 "ignoreDeprecations": "6.0" 配置,恢复默认 TypeScript 配置行为。

commit 40b731d61549da154ca8fac92c6681c5c76944ec
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Oct 3 08:10:45 2025 +0800

    重构(Program, Touch_JsonWebSocket): 统一JsonRpc配置方式

    重构多个文件中的JsonRpc插件调用方式,统一使用options参数配置,提升代码可读性与扩展性:
    - 将UseHttpJsonRpc、UseWebSocketJsonRpc、UseTcpJsonRpc从链式调用改为options配置方式
    - 统一UseSystemTextJsonFormatter的配置逻辑,插入TypeInfoResolverChain
    - 调整SetAllowJsonRpc为options.SetAllowJsonRpc方式,保留注释说明
    - Touch_JsonWebSocket与Touch_JsonWebSocket_2D类中同步调整调用方式
    - 提升代码结构清晰度与风格一致性

commit a13bb6740cb6e440bcf75683f2cae3caafd48660
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 2 23:43:47 2025 +0800

    重构(styles): 简化样式设计移除动态效果

    移除渐变背景、阴影和毛玻璃效果,改为纯色背景
    删除过渡动画和伪元素装饰,简化组件视觉复杂度
    优化响应式设计,调整字体大小和布局样式
    统一暗色主题颜色方案,减少动态交互效果
    删除多余注释和样式规则,提升代码可维护性

commit d18b16fa5ac418118c0567ddf1506a2891142832
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 2 23:16:00 2025 +0800

    新增(css): 自定义主题样式与修复导航栏问题

    添加全局 CSS 注释,定义主题颜色变量与代码字体大小
    新增代码高亮样式 `.docusaurus-highlight-code-line`
    新增 `.like-button` 样式及其伪类(悬停、点击、禁用)
    修复移动端导航栏菜单项高度不一致问题

commit b053c3aca74fbc26f1e703dddc22bffd5d402ca3
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 2 23:06:57 2025 +0800

    修复(css): 修复移动端导航栏菜单项高度不一致

    删除与导航栏、按钮、侧边栏菜单相关的样式规则,优化导航栏在不同屏幕尺寸下的布局。新增针对移动端导航栏菜单项高度不一致问题的修复,统一小屏幕下菜单项的最小高度和行高,确保内容垂直居中,避免影响子菜单结构。

commit dcdee27ee17b623932efcac2d2bc101c7d47b252
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 2 22:09:27 2025 +0800

    优化(core): 重构配置逻辑并更新依赖版本

    重构 Program.cs 中 JSON RPC 和 NamedPipe 配置逻辑,使代码更具灵活性和可读性
    更新 Directory.Packages.props 中 TouchSocketVersion 至 4.0.0-beta.87
    调整 docusaurus.config.ts 中 Markdown 配置,增强文档生成灵活性
    新增 tsconfig.json 中 ignoreDeprecations 配置,兼容依赖版本

commit 5146d3dbf3a2428a8f53b360e860bfba026a39a8
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 2 17:43:22 2025 +0800

    修复(css): 修复导航栏与按钮样式问题

    修复按钮圆角样式注释问题,提升代码可读性
    重新定义`.like-button:disabled`样式,确保禁用状态一致性
    修复文档页面导航栏在小屏模式下的换行问题,新增媒体查询优化不同屏幕宽度下的导航栏布局
    优化版本下拉菜单样式,调整字体大小与间距
    确保导航栏项目在所有桌面尺寸下不换行,优化悬停效果避免布局抖动
    压缩导航栏空间以适应更多导航项,调整 logo 和标题大小
    新增备用方案,允许导航栏在必要时增加高度并保持整齐布局
    修复侧边栏菜单项宽度不一致问题,统一菜单项样式与交互体验
    调整分类菜单与普通菜单样式一致性,确保箭头图标对齐

commit 9c3971c16f00a70959dd0249a712454ffee74e3e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Oct 2 17:29:29 2025 +0800

    新增(program,namedpipeservice,tcpservice): 增强NamedPipeService功能

    更新TouchSocket版本至4.0.0-beta.86,增强NamedPipeService功能,支持动态监听、Id重置、数据接收与发送。新增异步方法、插件扩展及自定义服务实现。完善文档,补充连接架构、Scoped生命周期、配置示例及清理释放资源的说明,统一代码示例格式。

commit 09d1d26a0418e89df4345c9c6b810243da33a0ed
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Oct 1 22:14:36 2025 +0800

    新增(program,文档): 增加TCP ID重置功能及文档更新

    新增TCP服务器和客户端ID重置功能,支持通过`ResetIdAsync`方法修改ID,并新增插件`InitIdPluginWithIpPort`以IP和端口作为ID。
    更新文档,新增ID重置和AOT支持内容,删除旧文档中相关内容。
    调整文档侧边栏配置,删除无效条目并优化编号。

commit 32bb9944cc7b2c4ade890199261bed297cc6c973
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Oct 1 17:54:25 2025 +0800

    新增(description): 添加国庆优惠活动及新课程公告

    在 `description.mdx` 文件中:
    - 新增国庆优惠活动提示,包含活动时间、优惠内容及相关链接:
      - [立即报名(课程)](https://www.bilibili.com/cheese/play/ss489296905)
      - [立即购买(Pro)](https://touchsocket.net/docs/current/enterprise)
    - 添加新课程公告,介绍 **C# TouchSocket 网络通信开发课程** 的上线信息,涵盖课程内容包括:
      - TCP/IP 协议原理与 Socket 编程核心技术
      - 开发环境搭建、插件机制、12 种消息适配器实战
      - 企业级聊天系统案例(更新中)
      - 支持多端学习,适合零基础及技术进阶开发者

commit 9353cfd803e93dca65e69d91eb5acdd67a72b192
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Oct 1 13:55:19 2025 +0800

    重构(构建配置): 迁移集中式包版本管理至独立文件

    将集中式包版本管理从 Directory.Build.props 文件迁移至新的 Directory.Packages.props 文件:
    - 删除 Directory.Build.props 中的 <ManagePackageVersionsCentrally> 和 <TouchSocketVersion> 定义
    - 删除集中式包版本管理的 <ItemGroup>
    - 新增 Directory.Packages.props 文件,重新定义集中式包版本管理,包括 TouchSocket 核心包、TouchSocketPro 包、Microsoft 包及第三方包
    - 在 Examples-All.sln 文件中添加对 Directory.Packages.props 的引用

    此更改优化了构建配置的组织结构,使包版本管理更加清晰。

commit ad52d4aebd029343ac7ac91914038d905165f58e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Oct 1 13:45:01 2025 +0800

    重构(Program.cs, Examples-All.sln): 移除ReuseAddressServerConsoleApp

    移除ReuseAddressServerConsoleApp相关代码及配置
    - 删除Program.cs中ReuseAddressServerConsoleApp的TCP服务实现
    - 注释通道创建与数据写入相关代码块
    - 从Examples-All.sln中移除ReuseAddressServerConsoleApp项目引用
    - 删除ReuseAddressServerConsoleApp.csproj文件
    - 更新Examples-All.sln中的Visual Studio版本信息
    - 保留其他项目的相关配置

commit a7b2ca07ddae04a0392755510c75244c48078550
Author: Diego2098 <82756760+kimdiego2098@users.noreply.github.com>
Date:   Tue Sep 30 21:25:16 2025 +0800

    AsyncWaitData改为ValueTask实现 (#87)

commit 51edda191a6dfd24af3b94700d98660567612310
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Sep 29 22:57:52 2025 +0800

    优化(props, program, docs): 更新TouchSocket版本及代码优化

    更新TouchSocket版本至4.0.0-beta.82,优化通道创建逻辑,调整数据写入大小,增强代码可读性;简化文档示例,引用自定义代码块

commit 4587dbf7926505255dda1d0c7dd6bc4e70a1a56c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 27 22:22:15 2025 +0800

    新增(program): 增加多种Dmtp客户端及动态验证插件

    新增多种Dmtp客户端创建方法,包括WebSocketDmtpClient、NamedPipeDmtpClient、TcpDmtpClientFactory和HttpDmtpClientFactory,支持详细配置步骤
    新增动态验证连接插件MyVerifyPlugin和接收数据插件MyFlagsPlugin
    新增Dmtp基础Flag协议输出日志,便于调试
    优化代码切片操作,使用C# 8.0索引和范围操作符
    新增Dmtp配置方法CreateConfig,提供通用配置示例
    更新文档,使用自定义代码块展示示例代码,新增工厂模式和Ping操作示例,移除冗余代码
    新增NamedPipeDmtpClient示例及多种Demo链接,提升开发者体验

commit cae989e874c6dfaac952dd3b994b2220dc96071f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 27 08:34:32 2025 +0800

    修复(package.json): 升级依赖版本至 ^3.9.1

    升级 @docusaurus/core、@docusaurus/preset-classic 和 @docusaurus/theme-mermaid 的版本号至 ^3.9.1
    新增 v3.1.18 更新日志,包含以下内容:
    - 修复 TCP 数据分片发送问题,确保大数据包完整传输
    - 调整 RPC 全局筛选器注册与解析机制,支持按类型注册
    - 完善 WebSocket 关闭帧处理,增强标准兼容性
    - 优化 Dmtp RPC 调用上下文清理逻辑,降低内存占用风险
    - 升级基础版本号至 3.1.18

commit de7c660670403c6a930d3d735e5184d20f558d02
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 27 07:47:10 2025 +0800

    发布:4.0.0-beta.70

commit 0c4bcc818e7e8687e591c61cdefa91a646e22690
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 27 07:42:40 2025 +0800

    新增(program,文档): 支持多协议客户端与服务端示例

    新增 TouchSocket 客户端创建逻辑,支持 TCP、UDP、HTTP 等多协议配置与连接
    更新 Program.cs,添加服务端与客户端创建示例,提升代码封装性
    更新 dmtpclient.mdx 和 dmtpservice.mdx,重构文档结构,新增架构图与示例代码
    更新 Examples-All.sln,支持 Visual Studio 18
    更新 package.json,升级 @docusaurus 相关依赖至 3.9.0
    更新 index.tsx,调整横幅内容,新增对 .NET6.0 的支持
    优化文档展示,新增 BilibiliCard 和 CustomCodeBlock 组件

commit 2ea4bf38e24cdb193f23dd2511c89e25122c5e2e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Sep 24 23:09:15 2025 +0800

    优化(program,文档): 重构ModbusSlave配置并完善文档

    重构Program.cs中ModbusSlave的配置方式,支持多站点配置,明确IgnoreSlaveId规则,增加插件示例及本地读写操作示例。
    更新modbusslave.mdx文档,增加Modbus协议定义、插件机制说明及示例,使用<CustomCodeBlock>优化代码展示,强调多站点配置注意事项,完善本地读写操作说明。
    更新TouchSocket版本至4.0.0-beta.67。

commit 3f8935d815f8614d337a7d22bb3a522f06d1699b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Sep 23 23:12:57 2025 +0800

    优化(modbus): 统一异步方法及增强功能支持

    - 更新 TouchSocket 版本至 4.0.0-beta.65
    - 替换 SendAsync 为 WriteAsync 统一异步写入方式
    - 新增 Modbus 操作的详细实现与异常处理逻辑
    - 优化串口配置代码,提升可读性与一致性
    - 新增自定义 Modbus 主站类 MyModbusMaster
    - 移除冗余 using 引用,减少不必要依赖
    - 增强文档与示例,新增注意事项与最佳实践
    - 提供 Modbus Rtu 主站与从站的完整配置示例
    - 提升代码风格与文档结构的一致性

commit 2052445af49ba7a146d658444dbe3bc5fe08f187
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 21 23:08:16 2025 +0800

    重构(Program.cs): 优化跨域服务与Modbus主站配置

    重构 Program.cs 中跨域服务配置,使用 #region 标记代码区域,调整 UseCors 调用顺序并添加默认 HTTP 服务插件。重构 Modbus 主站方法,分离配置与连接逻辑,提升代码可读性与模块化。

    文档(cors.mdx): 使用 CustomCodeBlock 优化代码展示,替换原有代码块并添加提示信息,提升文档清晰度。

    文档(modbusmaster.mdx): 使用 CustomCodeBlock 优化 Modbus 主站创建代码展示,统一代码风格并优化文档结构。

commit 38a1eeff4620c8e14796708f056571ce9c4e59ca
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 21 20:56:44 2025 +0800

    重构(Program.cs): 提取静态页面配置方法

    重构 HttpService 配置逻辑,提取静态页面插件配置到 ConfigureStaticPage 方法,提升代码可读性与模块化。升级 TouchSocket 版本至 4.0.0-beta.58,优化 MyCustomDownloadHttpPlug 类代码,使用切片语法简化逻辑。改进文档 httpstaticpageplugin.mdx,使用 CustomCodeBlock 组件重构代码示例,完善静态页面插件使用说明。

commit da8c4853e532695c5273cd593f5a4b932e0a2dec
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 21 19:09:26 2025 +0800

    新增(donate): 增加新的捐赠记录

    在 donate.mdx 文件中新增以下捐赠记录:
    - 匿名用户捐赠 66 元,日期为 2025 年 8 月 12 日
    - *楠 捐赠 10 元,日期为 2025 年 8 月 15 日
    - i** 捐赠 888 元,日期为 2025 年 9 月 9 日

commit 6a52aba184f7d94815b28ce57bb723b5e93792bb
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 21 17:05:32 2025 +0800

    新增(program,httpclient): 增加Http客户端代理配置功能

    在Program.cs中新增SetProxy和SetSystemProxy方法
    支持自定义HTTP代理和系统代理配置
    调整断线重连插件代码结构
    在httpclient.mdx文档中补充代理配置说明及示例代码

commit a618e773cf2ef087d6070be27949eaa095cd898b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 21 16:30:56 2025 +0800

    重构(Program, MyPlugin, Touch_HttpDmtp, Touch_TcpDmtp): 优化通道数据处理逻辑

    统一 SetDmtpOption 的代码格式,提升代码规范性
    将 await foreach 替换为 while (channel.CanRead)
    引入 CancellationTokenSource 设置超时时间
    更新通道数据读取逻辑为 channel.ReadAsync
    调整日志记录格式,优化代码可读性
    升级 TouchSocketVersion 至 4.0.0-beta.57

commit 9a6fa87062dc108a7c8fa0ea2a0883efb498dae3
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 21 15:29:23 2025 +0800

    发布:4.0.0-beta.55

commit 23be6c90f163dd9002600d7fb090501c3a9dc0b3
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Sep 18 20:14:45 2025 +0800

    优化:文档

commit 635e7a9bf25924dbe1162e544ca73c508a311b06
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Sep 18 20:01:03 2025 +0800

    优化:文档

commit dabd230108a00d280e4f29e7a73d22193b90f6f9
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Sep 17 19:50:58 2025 +0800

    发布:4.0.0-beta.28

commit eca738ea386d936d80e31b0281bfa52139521bbb
Author: Diego2098 <82756760+kimdiego2098@users.noreply.github.com>
Date:   Wed Sep 17 16:13:58 2025 +0800

    GetSign bug (#82)

    超限时返回的sign依然可能时超出的限值

commit 5e3cb064156464ccc006f711d941fe477176a879
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Sep 17 11:01:59 2025 +0800

    更新(vscode): 修改图片粘贴配置,指定文件名格式

commit a5eb69e46ee4e6bee15dca96f5cc7aff5cfbae19
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Sep 17 10:48:41 2025 +0800

    更新(vscode): 优化设置,添加图片粘贴配置和文件关联配置

commit ea2f8e4cd1ca7e21ab2107d736222637119d7806
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Sep 9 21:49:23 2025 +0800

    文档(更新): 添加 v3.1.17 更新信息

    添加 v3.1.17 更新的标题、更新日期和更新描述,更新日期为 2025.9.9,更新描述为“兼容性修复更新”。在更新详情中,新增关于 `SerialPortClient` 的修复信息,指出在某些情况下会导致程序崩溃的 bug。更新 v3.1.16 的标题和更新日期,更新日期为 2025.8.21

commit 05777cdfc0302cfa25674236dab5302a277b4fe4
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 7 22:42:04 2025 +0800

    新增(dmtp): 更新TouchSocket版本并添加服务支持

    更新 `Directory.Build.props` 中的 `TouchSocketVersion` 为 `4.0.0-beta.25`,在 `CreateDmtpConsoleApp.csproj` 中新增对 `TouchSocketPro.AspNetCore` 和 `Microsoft.AspNetCore.App` 的引用,修改 `Program.cs` 中的 `Main` 方法为异步并添加多个服务创建方法以支持不同类型的 Dmtp 服务

commit dafa047e816a591c2b4d3904e85502ab946b483c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 7 16:34:10 2025 +0800

    更新(项目): 更新TouchSocket版本并重构代码

    - 更新了 `Directory.Build.props` 文件中的 `TouchSocketVersion`,将其从 `4.0.0-beta.20` 更改为 `4.0.0-beta.22`
    - 在 `Program.cs` 文件中,多个地方的 `SetDmtpOption` 方法的实现方式进行了修改,原来的 `new DmtpOption()` 被替换为使用 `options =>` 的方式来设置 `VerifyToken`
    - 在 `DmtpConsoleApp.csproj` 文件中,移除了对 `Newtonsoft.Json` 和其他库的引用,改为使用 `PackageReference` 引用 `TouchSocketPro.Dmtp` 包
    - 新增了 `CreateDmtpConsoleApp` 项目,包含了基本的项目结构和示例代码
    - 在多个 `Program.cs` 文件中,更新了日志信息的内容,使其更具可读性
    - 在 `Form1.cs` 文件中,更新了用户界面提示信息,确保其中文提示更加准确和友好
    - 在 `Examples-All.sln` 解决方案文件中,添加了新的项目引用

commit 8723b23299ff8519752246928139736ad89ea42e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Sep 7 09:39:20 2025 +0800

    新增(项目): 添加 MultipacketAdapterConsoleApp 项目

    更新 TouchSocket 版本至 4.0.0-beta.20
    在 Examples-All.sln 中添加新的 MultipacketAdapterConsoleApp 项目
    定义 MultipacketAdapterConsoleApp.csproj 的基本属性
    实现控制台应用程序以支持 TCP 通信
    新增数据包结构类 MyPackBase、MyPack1 和 MyPack2
    实现 MyAdapter 类以处理数据的发送和接收

commit 37eaf82d39ef2ef3bf1eb4b96b80643385243ed8
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 6 17:04:45 2025 +0800

    新增(video.mdx): 添加课程内容和选项卡功能

    在 `video.mdx` 文件中,导入 `BilibiliCard` 和 `Tabs` 组件,新增课程核心优势、主要课程内容和课程结构,整合并展示不同课程视频链接,删除部分原有文本内容

commit 0261bf9509ae21fb45ca32d02d803f7d1732395a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 6 13:26:28 2025 +0800

    增强 WebSocket 客户端功能和稳定性

    在 `Program.cs` 中,修改了 WebSocket 客户端的接收和发送逻辑,增加了对 `ReadAsync` 方法的使用,并设置了接收超时。同时,添加了 WebSocket 断线重连的配置,提升了连接稳定性和数据处理能力。

    删除了 `MyReadTextWebSocketPlugin` 类,替换为 `MyReadWebSocketPlugin` 类,简化了数据接收流程,并增强了对接收到数据的处理。

    更新了 `dmtpbase.mdx` 和 `dmtpclient.mdx` 中的插件接口名称,从 `IDmtpHandshakingPlugin` 改为 `IDmtpConnectingPlugin`,以更好地反映其功能。

    在 `websocketclient.mdx` 和 `websocketservice.mdx` 中,更新了关于使用插件接收数据的描述,强调了插件的解耦和灵活性,并更新了相关的注意事项。

    最后,在 `launchSettings.json` 中添加了 WSL 的配置,以支持在 Windows 子系统 Linux 中运行应用程序。

commit 4e475a3b6dcf449ae2a9290ebd1b4e070e6bb436
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 6 10:44:49 2025 +0800

    新增(WebSocket): 添加多种WebSocket连接实现

    在 `Program.cs` 文件中,添加了多个 WebSocket 连接的实现,包括直接连接、带查询参数连接、使用特定 Header 连接和使用 Post 方式连接。每种连接方式都使用了新的 `WebSocketClient` 实例,并进行了相应的配置和连接。通过这些改动,代码的可读性和可维护性得到了提升,同时也增强了 WebSocket 客户端的功能。此外,添加了一个名为 `MyWebSocketClient` 的内部类,继承自 `WebSocketClient`,并重写了 `OnWebSocketReceived` 方法,以便于扩展和自定义 WebSocket 的接收逻辑。

    在 `websocketclient.mdx` 文件中,更新了文档内容,增加了关于如何从 `WebSocketClient` 继承的说明,并对创建 WSS 客户端的部分进行了调整,提供了更清晰的连接说明和注意事项

commit db82b86994ac56d216ae5426c95ca0935da018f1
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 6 10:24:23 2025 +0800

    重构(插件接口): 更新插件接口名称和版本

    更新多个文件以更改插件接口的名称,从 IDmtpHandshakingPlugin 和 IDmtpHandshakedPlugin 更改为 IDmtpConnectingPlugin 和 IDmtpConnectedPlugin,影响相关类的实现。更新 Directory.Build.props 中的 TouchSocketVersion 至 4.0.0-beta.17,并在文档中同步更新 WebSocket 插件接口名称

commit 131331f6af1e8632f26681ca6c1d68c985538453
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 6 09:52:07 2025 +0800

    重构(构建配置): 更新TouchSocket包版本管理

    在 Directory.Build.props 文件中,将 TouchSocket 相关的包版本从固定版本改为使用变量,更新为 4.0.0-beta.16

    在 Program.cs 文件中,多个类的接口实现从 IWebSocketHandshakedPlugin 改为 IWebSocketConnectedPlugin,更新 WebSocket 连接处理逻辑

    调整插件注册方式,使用 AddWebSocketConnectedPlugin 方法,确保与新的接口实现一致

commit d0a9c21b719215089d10930eaf6fa9bd07ee1436
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 6 09:30:24 2025 +0800

    重构(项目管理): 移除TouchSocket包版本号

    所有项目文件中的 `TouchSocket` 及其相关包的版本号从 `4.0.0-beta.15` 移除,改为使用集中式包管理。更新 `Directory.Build.props` 文件以确保所有相关包使用相同版本。添加 PowerShell 脚本以自动更新项目文件,简化包管理过程

commit 67332adbc69b4b142a173f1514e10d908889f576
Merge: e9e787e3a c8d57d414
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Sep 6 09:02:29 2025 +0800

    Merge branch 'v4.0.0-Alpha' of https://github.com/RRQM/TouchSocket into v4.0.0-Alpha

commit e9e787e3aff846a71ae78ccfc201f5d231847524
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Sep 5 22:05:14 2025 +0800

    更新依赖: 升级 TouchSocket 版本至 4.0.0-beta.15

    新增 WebSocket 相关功能,调整配置方式
    在多个项目中添加连接验证逻辑,确保连接安全
    更新文档示例代码,反映最新 API 变化
    增强 WebSocket 服务器的连接管理和数据处理逻辑

commit c8d57d414cb6a04231c73b03ad71321cd2b8d3d4
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Sep 5 22:05:14 2025 +0800

    更新依赖: 升级 TouchSocket 版本至 4.0.0-beta.15

    新增 WebSocket 相关功能,调整配置方式
    在多个项目中添加连接验证逻辑,确保连接安全
    更新文档示例代码,反映最新 API 变化
    增强 WebSocket 服务器的连接管理和数据处理逻辑

commit 51228b3f3605643b3f2d879598557c3261cbd195
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Sep 4 20:49:35 2025 +0800

    优化(依赖): 更新TouchSocket库至4.0.0-beta.13

    更新所有项目文件中的TouchSocket及相关包版本至4.0.0-beta.13,增强Http客户端的断线重连配置,提升网络连接稳定性,更新文档以提供断线重连的最佳实践和注意事项

commit dc0b35aef88a951969ca33a63d821ab37478152b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Sep 3 22:42:31 2025 +0800

    新增(tcp客户端): 添加断线重连功能和文档更新

    在 Program.cs 中添加 CreateReconnectionTcpClient 方法,实现 TCP 客户端的断线重连功能,支持暂停和恢复重连。在 TcpConsoleApp.csproj 中添加 LangVersion 属性以支持预览语言特性。在 tcpclient.mdx 中更新断线重连的文档,清晰说明重连机制及使用注意事项

commit f1e2590c89b621d5c399a7fb48fec3c62e6a0950
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Sep 3 22:08:25 2025 +0800

    更新依赖: 升级TouchSocket相关包版本

    更新所有项目中TouchSocket及其相关包的版本至4.0.0-beta.11
    重构Program.cs中的插件使用方式,替换为UseReconnection
    增强Tcp、Udp、WebSocket等项目的连接和重连实现
    更新WebApi相关项目的引用版本
    确保所有项目使用最新库版本和最佳实践

commit c8026fcf3ffc7316082682384fabfed209a398cb
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Sep 1 22:26:09 2025 +0800

    更新依赖: 更新TouchSocket相关包版本

    修复所有项目中`TouchSocket`及其相关包的版本为`4.0.0-beta.7`
    优化`Form1.cs`中的UDP会话图像处理逻辑,增加异常处理
    更新`ScreenUdpReceiver`和`ScreenUdpSender`项目中的`TouchSocketPro.Dmtp`版本
    确保多个项目中对`TouchSocket`相关包的引用一致

commit e8cbd316dd359b5e65ffc2971b500b87994bfef9
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Sep 1 21:42:47 2025 +0800

    更新依赖: 更新TouchSocket相关包版本

    更新所有项目文件中TouchSocket及其相关包的版本至4.0.0-beta.6
    在Program.cs中添加TouchSocket.Core和TouchSocket.NamedPipe引用
    更新TcpService和TcpClient的配置方法
    移除旧版本引用并添加新版本引用
    更新多个项目中的TouchSocket.Http、TouchSocket.WebApi、TouchSocket.XmlRpc等包的版本

commit 4340165dcddf167575053fa28fc329fe6e518a74
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Sep 1 21:32:37 2025 +0800

    重构(核心): 重构多个类和逻辑以提升性能

    更新 `TouchSocketVersion.props` 的版本号,添加 `TouchSocketConfig` 实例化和配置,重构多个类以优化连接管理和资源清理,更新文档和注释以增强可读性,移除过时接口,确保代码整洁性和现代化

commit 1c34030d69ccd6570432e59cfe692d439c7d2120
Author: Diego2098 <82756760+kimdiego2098@users.noreply.github.com>
Date:   Mon Sep 1 20:37:21 2025 +0800

    feat: add Basic auth 认证插件 (#79)

    * 修复swagger获取类型属性重复的情况

    * feat: add Basic auth 认证插件

commit a4c6e8c97cf5d77b032795084cfc86daec9637a2
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 30 22:54:02 2025 +0800

    新增(Program): 添加TCP连接管理功能

    在Program.cs文件中,添加清理当前所有连接、清理指定连接、停止监听、停止服务器和释放服务器资源的异步方法。更新文档示例,强调使用异步发送以提高性能

commit 202009a3fbbb2dbff7235c0b7999dedb7add8f4a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 30 22:09:29 2025 +0800

    新增(httpclient): 添加异步方法支持HTTP操作

    在 Program.cs 文件中,添加多个异步方法以支持 HTTP 客户端的创建、请求和文件上传功能,包括 CreateClient、CreateClient2、UploadStream、PostJson、GetString、GetFile 和 GetBytesArray 方法,并修改了 Request1 和 Request2 方法以使用新的 HTTP 客户端实例。同时,增加流操作器以监控上传进度和速度。

    在 httpclient.mdx 文件中,更新文档内容以反映新的 HTTP 客户端功能和用法,修改 HttpClient 的描述,添加新的代码示例和说明,并增加关于连接管理和性能优化的提示

commit 2b03c15e462f3f28e8173b2de38a6c176ed639b4
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Aug 29 09:50:23 2025 +0800

    升级依赖库版本

    升级所有项目中 TouchSocket 相关库版本至 4.0.0-beta.5
    重构 WebApiProxy.cs,增加异步方法支持并添加注释

commit 64611d59e311005087c53bb3e7e3735bc164ff4d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Aug 29 09:13:16 2025 +0800

    更新(dependencies): 更新所有TouchSocket相关包版本

    更新多个项目的TouchSocket相关NuGet包版本,从3.8.0.10升级至4.0.0-beta.4,移除旧版本包并添加新版本,增强项目兼容性和功能性

commit b198f24448d7b34c77e16b8ae749cdf3a3b35e52
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Aug 28 23:04:55 2025 +0800

    发布:4.0.0-beta.4

commit da4a1d0f023d98ebfa0470c851409ce4031d49ff
Author: Diego2098 <82756760+kimdiego2098@users.noreply.github.com>
Date:   Wed Aug 27 14:48:55 2025 +0800

    修复swagger获取类型属性重复的情况 (#77)

commit 576d7b220798f5bdfc2ad7eebd96191d74146a13
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 26 22:23:22 2025 +0800

    优化(代码): 重构代码结构和增强可读性

    - 添加版权声明和相关链接,明确使用协议和作者信息
    - 使用 `var` 关键字替代具体类型声明,提升代码简洁性
    - 调整 `Program.cs` 中异步方法调用方式,确保一致性
    - 捕获更具体的异常类型,提升代码健壮性
    - 使用 `await` 确保异步操作正确执行,避免潜在问题
    - 简化数据读取和写入方式,减少冗余代码
    - 增加 `TcpService` 和 `UdpService` 对插件的支持
    - 扩展 `UnityRpcStore` 接口,增加登录和性能测试功能
    - 引入必要的命名空间,确保代码整洁性
    - 优化 `Task` 和 `async` 的使用,提升性能和响应性

commit 894186e733c81bab5c76aa0e2fda171bb7d39364
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 26 22:21:37 2025 +0800

    新增(http服务): 增强HTTP服务功能和插件支持

    引入Newtonsoft.Json库以支持JSON处理
    新增CreateHttpService1方法以创建SSL的HTTP服务器
    增强MyHttpPlugin4类以支持持续读取大数据和小文件
    新增MyHttpPlug1和MyHttpPlug11类以处理特定HTTP请求
    新增MyHttpPlugin22和MyHttpPlugin33类以响应大数据
    更新MyCustomDownloadHttpPlug类以修改日志记录方式
    更新httpservice.mdx文档以增加插件描述和示例
    增加对SSL/TLS加密的支持并提供配置示例

commit 7087543dcaeab1501f33be46066c5d7c983e21f7
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 26 09:18:12 2025 +0800

    升级依赖: 更新TouchSocket库版本

    优化所有项目文件中TouchSocket及其相关库的版本至3.8.0.10
    重构Program.cs中的HttpClient使用方式
    调整BigDataHttpContent类的WriteContent方法参数格式
    确保所有依赖项保持一致以提高稳定性和安全性

commit 0d81ee584937d95201e4ebbd893cd742298266c6
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 21:59:15 2025 +0800

    新增(httpservice): 创建并配置 HTTP 服务

    在 Program.cs 中新增 CreateHttpService 方法以启动 HTTP 服务
    更新 MyHttpPlug1 类以处理 HTTP 请求
    修复 MyDelayResponsePlugin2 类的代码格式
    更新 httpservice.mdx 文档以强调 HttpService 的重要性和特性
    详细描述 HttpService 的应用场景和架构设计
    提供 SSL/TLS 加密配置示例

commit 1d07bf568d65dda3904f399e8bfb7c15659f8fdd
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 21:26:19 2025 +0800

    优化(sidebars): 调整侧边栏标签编号并删除链接

    将侧边栏中的多个标签的编号向前移动一位,删除原有的 "02、历史更新" 链接

commit 567ff258dfb1f4b615023fd3a97322fdb0befed9
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 20:56:23 2025 +0800

    优化(GiteeIcon): 替换SVG图标为更复杂版本

    将 GiteeIcon 组件的 SVG 图标进行了替换,新的图标具有更大的视图框(1024x1024),并且包含了更复杂的路径定义,可能提供了更丰富的视觉效果

commit 5bab0f1d166380cf2d31b227b86852e961f834b5
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 20:45:19 2025 +0800

    优化(css): 调整样式和背景渐变效果

    在 `Tag.module.css` 中,调整 `.label` 类的内边距为 `4px 12px`。
    更新 `index.css` 中 `.TouchSocket-banner-description` 和 `.TouchSocket-banner-description.dark` 类的背景渐变颜色及注释,改善文本阴影效果。
    在 `index.tsx` 中,修改 `QuickStart` 函数的 `StepCard` 组件,增加服务启动时的端口参数。

commit 1a80817b3bc6bbf8b841804c82c3eead6f83a922
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 17:32:49 2025 +0800

    新增(index.tsx): 添加多个功能组件以丰富页面内容

    在 `index.tsx` 文件中,`Home` 函数的返回值中添加了 `Features`、`UseCases` 和 `QuickStart` 组件,增强页面的功能性和可读性。新增的 `Features`、`UseCases` 和 `QuickStart` 函数分别展示核心特性、应用场景和快速开始步骤,使用了相应的卡片组件来渲染内容。保留了 `Banner` 函数的原有结构,确保组件正常导出和使用

commit 65d4e7cd95e2e7f3ef543311133b565c8dfb87e5
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 17:19:03 2025 +0800

    重构(index.tsx): 统一函数定义和更新内容

    在 index.tsx 文件中,修改多个函数的定义,增加括号以统一代码风格。更新 Banner 函数中的文本内容和列表项描述,反映组件库的特性。更新 Gitee 函数中的统计数据,调整 CodeSection 函数的逻辑以支持更灵活的内容替换。SystemWindow 函数结构保持不变

commit c1d66b7030204314f5344d9ac4265932a3482df6
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 17:03:50 2025 +0800

    优化(document): 更新enterprise.mdx文件内容

    在enterprise.mdx文件中更新多个<Pro/>和<Tag>Pro</Tag>组件引用,去掉特定链接,简化内容并修改授权条款描述,提升文档清晰度和可读性

commit 3b60c5168a01ce165ef41a37f671c1327d7bde4b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 16:49:12 2025 +0800

    更新(文档): 替换多个mdx文件中的CardLink链接

    更新多个 `.mdx` 文件中的 `CardLink` 组件链接,将绝对链接替换为相对路径以便于本地使用。具体更改包括:
    - 在 `bytepool.mdx` 中,添加关于 `ByteBlock` 的说明
    - 在 `dmtpbase.mdx` 中,设置 `channel.Timeout` 为 30 秒
    - 更新 `dmtptransferfile.mdx` 中的示例代码
    - 更新 `dynamicmethod.mdx` 中获取 `CustomService` 方法的示例
    - 更新 `httpclient.mdx` 中的文件上传示例
    - 更新 `httpservice.mdx` 中关于 HTTPS 服务器的说明
    - 更新 `ipackage.mdx` 中的 `MyGeneratorConvertPackage` 类示例
    - 更新 `jsonrpc.mdx` 中的 `MyPluginClass` 示例
    - 更新 `packageadapter.mdx` 中的 `CreateService` 方法示例
    - 更新 `plcbridgemodbus.mdx` 中关于 TouchSocket PLC Bridge 的说明
    - 更新 `serialportclient.mdx` 中的示例链接
    - 更新 `singlethreadstreamadapter.mdx` 中多个适配器的示例链接
    - 更新 `tcpclient.mdx` 和 `tcpservice.mdx` 中的示例链接
    - 更新 `udpsession.mdx` 中的 UDP 服务示例
    - 更新 `waitingclient.mdx` 中的 TCP 等待客户端示例
    - 更新 `webapi.mdx` 中的 `AppJsonSerializerContext` 示例
    - 更新 `websocketclient.mdx` 和 `websocketservice.mdx` 中的 WebSocket 关闭示例
    - 添加 `replace-links.js` 脚本用于替换链接

commit 100eed33bb41eadba6e0ddc4c29c6caaee232008
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 16:32:03 2025 +0800

    新增(CardLink): 添加 Gitee 和 GitHub 链接按钮

    在 CardLink.js 中,添加 Gitee 和 GitHub 图标的导入,重构 getLastPathSegment 函数以支持相对路径和完整 URL 的处理,新增 buildRepoUrls 函数构建完整仓库 URL,更新 CardLink 组件以包含链接按钮和调整 Pro 标签显示逻辑
    在 CardLink.css 中,新增双链接按钮样式
    在 GiteeIcon.js 和 GitHubIcon.js 中,添加 Gitee 和 GitHub 图标的 SVG 组件

commit d25ac6b6fb47d79c7997ff10e765b13ebb89f88a
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 16:01:49 2025 +0800

    新增(Examples-All.sln): 添加WaitingClientConsoleApp项目

    在解决方案中添加新的项目 `WaitingClientConsoleApp`,配置调试和发布设置
    更新 `waitingclient.mdx` 文件,替换示例代码并引入 `CustomCodeBlock`
    在 `Program.cs` 中添加版权信息和基本结构示例
    设置 `WaitingClientConsoleApp.csproj` 的 SDK、输出类型和NuGet包引用

commit 7702a17aed08045bc125548d21fa5b831b8222de
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 14:39:03 2025 +0800

    新增(Program, Form1): 添加串口发送和服务管理功能

    在 `Program.cs` 中,添加向串口发送数据的功能,接收到数据后异步发送 "hello" 字符串
    在 `Form1.cs` 中,添加 `CancellationTokenSource` 和 `TcpClient` 字段,修改 `Form1_Load` 方法以创建服务并更新按钮 UI
    移除 `button1_Click` 方法中的冗余代码,简化连接逻辑并重命名为 `button4_Click`,负责关闭 TCP 客户端和释放服务
    修改 `button2_Click` 和 `button3_Click` 方法中的响应变量名,提高代码可读性
    添加 `IsConnected` 方法检查 TCP 客户端连接状态并设置接收事件处理程序
    更新 `UpdateServiceButtonUI` 方法以在服务为空时更新按钮文本为 "启动服务"

commit 9260501d3a0029e23aa0d4a6523679cd4fd48a75
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 14:13:31 2025 +0800

    新增(项目): 添加串口客户端和相关功能

    - 在 `Examples-All.sln` 中添加新项目 `WaitingClient` 和 `TcpWaitingClientWinFormsApp`
    - 更新 `Program.cs`,实现串口客户端的初始化和连接逻辑
    - 修改 `Form1.cs` 和 `Form1.Designer.cs`,增强 UI 组件的事件处理
    - 更新 `Form1.resx` 资源文件结构以匹配新 UI
    - 更新 `TcpWaitingClientWinFormsApp.csproj`,确保使用最新的 `TouchSocket` 包
    - 引入插件机制,支持自定义数据接收和处理逻辑
    - 更新 `serialportclient.mdx` 文档,提供更清晰的使用指南

commit d68142e1c00e88a60aa3b60dffcdbc39a822c04d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 13:12:18 2025 +0800

    升级(TouchSocket): 更新多个项目的NuGet包版本

    更新多个项目文件中的 TouchSocket 相关 NuGet 包版本,从 3.7.2.41 升级到 3.8.0.9,确保使用最新功能和修复
    在 RpcProxy.cs 和相关代理类中,将接口方法参数类型从 IInvokeOption 更改为 InvokeOption,统一接口定义
    更新 WebApiProxy 和 JsonRpcProxy 中的方法签名,确保所有方法使用新的参数类型
    更新 upgrade.mdx 文件中的版本说明,标记为 v4.0,提示用户选择预发布版本进行尝鲜

commit 9491716a36f0ec2ee3fcff8b4541d2c4fbd17786
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 13:01:44 2025 +0800

    重构(upgrade.mdx): 移除Tag导入并添加Highlight导入

    在upgrade.mdx文件中移除对Tag组件的导入,添加对Highlight组件的导入,更新版本信息并提醒用户备份代码以防破坏性变更

commit 5e7e6b26f63b0e7473142d70c007e3de7aa01aaa
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 12:59:43 2025 +0800

    版本更新(upgrade.mdx): 更新至4.0.0并添加变更说明

    在 `upgrade.mdx` 文件中,更新版本号至 4.0.0,添加更新描述和可能的破坏性变更警告。重构 SSL 配置,改进安全性,优化代码格式,新增多个接口和类,增强数据处理能力和流操作能力。支持多种传输模式和适配器组,提升多线程数据适配器测试能力。重构 HTTP 客户端、TCP 和 UDP 传输实现,增加 SSL 配置类和事件参数类等

commit f6e37f027eaf2fcdf499354db7784a04d8261115
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 25 10:24:18 2025 +0800

    版本更新(package.json): 升级至4.0并更新文档

    更新 `package.json` 文件中的版本号,从 `3.1` 升级至 `4.0`
    在 `upgrade.mdx` 文件中,更新版本信息,添加新的更新记录
    在 `v3-1.mdx` 文件中,详细列出各个版本的更新内容
    新增多个功能并修复若干bug,提升代码可读性和稳定性
    版本更新涉及多个模块,如 `TouchSocket.Core`、`TouchSocket.Http`、`TouchSocket.Mqtt` 等

commit 301097683131c1b9a801842f0d1ecf324ea96e0c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 24 13:26:08 2025 +0800

    更新(文档): 更新多个项目说明和效果展示

    在多个文档中添加和删除内容,主要涉及项目说明、技术点、效果展示等方面的更新。具体变化包括:
    - 在 `cooperation.mdx` 中添加商业合作的联系方式和支付方式
    - 在 `dataforwarding.mdx` 中更新数据转发项目的说明和效果图
    - 在 `engineertoolbox.mdx` 中删除部分界面展示的效果图
    - 在 `filesynchronization.mdx` 中更新文件同步系统的说明和效果图
    - 在 `pipelinedatahandlingadapter.mdx` 中删除关于Pipeline适配器的示例代码
    - 在 `remotemonitoring.mdx` 中更新远程监测和控制项目的功能说明和效果图
    - 在 `rpcoption.mdx` 中删除关于调用配置的示例代码
    - 在 `tlvdatahandlingadapter.mdx` 中更新三元组编码适配器的说明和使用示例
    - 在 `webdataforwarding.mdx` 中添加Web数据转发项目的说明和效果图
    - 在 `wpfuifiletransfer.mdx` 中更新WPF界面和文件传输项目的说明
    - 在 `sidebars.ts` 中对项目分类进行调整,更新项目的标签和顺序

commit 7968cc4d37d2b04ad5c9a18cf62a6a469d42cb34
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 24 13:18:11 2025 +0800

    优化(内存管理): 更新接收逻辑使用Memory类型

    在多个文件中将接收和处理方式从ByteBlock转为Memory,提升内存管理效率和灵活性
    更新适配器相关文件以反映新的内存处理方式
    调整客户端和服务端的接收逻辑,确保数据处理一致性
    提升代码可读性和维护性

commit 0171089649e0fd80d443a81eab82ee61222ca9e8
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 24 13:05:00 2025 +0800

    重构(Rpc): 更新InvokeOption并支持取消操作

    在多个文件中重构代码以支持新的InvokeOption类型,增加CancellationToken参数以实现操作取消,更新SSL配置以增强安全性,简化SSL认证逻辑

commit 50cb5207f9bd01b2dbd722df988da408f8ce6aae
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 24 11:52:59 2025 +0800

    新增(文档): 添加自定义数据包结构描述

    在 `singlethreadstreamadapter.mdx` 文件中新增了 `packet-beta` 数据包结构的详细描述,包括指令类型、数据类型、数据长度、载荷数据和 CRC16 校验码等字段

commit 3eff34cd6323d552a64250ea5910d644ee5b73dd
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 24 11:00:04 2025 +0800

    文档(README.md, usage-example.md): 更新CodeBlock组件使用指南

    更新`README.md`和`usage-example.md`文件,详细说明`CodeBlock`组件的使用指南、组件属性、工作流程和注意事项,增加组件特性和文件结构描述,提供具体使用示例和代码格式要求

commit 08d85dacb9e2d6bf83bacac79806bdae5e4a4164
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 24 10:55:20 2025 +0800

    新增(Examples-All.sln): 添加TouchSocketBitConverterConsoleApp项目

    在解决方案中添加了新的项目 `TouchSocketBitConverterConsoleApp`,并配置了调试和发布的构建设置。
    在 `Program.cs` 文件中实现了多个示例方法,演示如何使用 `TouchSocketBitConverter` 类进行字节序转换和数据处理。
    在项目文件中设置输出类型为可执行文件,目标框架为 .NET 9.0,并添加了对 `TouchSocket.Core` 包的引用

commit 01d20099d074e31aad54187adfb139ab0e98e1ce
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 24 10:18:39 2025 +0800

    重构(Program): 增强适配器支持和代码可读性

    - 在 `Program.cs` 中添加自定义区间适配器接收逻辑
    - 增加对自定义大数据非固定包头适配器的支持
    - 引入 JSON 数据处理适配器以解析 JSON 消息
    - 进行类重命名和结构调整以提高可读性
    - 添加详细注释和文档说明以帮助开发者
    - 更新示例代码和文档以提供更多使用案例

commit a149be230cb78a8beb651669122d57c956d778e4
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 23:05:56 2025 +0800

    重构(数据处理): 替换MyRequestInfo为MyDataClass

    更新数据处理逻辑,使用MyDataClass替代MyRequestInfo,调整接收适配器和日志记录内容
    新增多个自定义数据处理适配器,优化数据解析和CRC校验逻辑
    增强适配器对大数据和非固定包头的支持,提升系统稳定性和可靠性

commit ecc0f93f5b727963896a746f12bb0be08113f00f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 18:19:44 2025 +0800

    新增(RawAdapterConsoleApp): 添加新的控制台应用程序

    在项目中添加 `RawAdapterConsoleApp` 控制台应用程序,配置项目文件并引用相关包。实现 TCP 客户端和服务端功能,添加自定义数据处理适配器 `MyRawDataHandleAdapter`,并提供适配器配置示例。移除原有的 `AdapterConsoleApp` 项目及其相关配置

commit 005a2fd56a200a2f740607503b874fc5f582ba99
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 15:04:10 2025 +0800

    重构(sidebars): 更新单线程流式适配器文档

    在sidebars.ts中删除旧的单线程流式适配器类别并添加新文档项singlethreadstreamadapter,更新其标签为12.2 单线程流式适配器;在singlethreadstreamadapter.mdx中新增文档元数据

commit c9f31a7bf1f4c58ecd9ac54c6a7780fb6972279b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 13:00:33 2025 +0800

    优化(CustomCodeBlock): 去除尾随空白字符

    修改 finalCode 的赋值方式,去除尾随的所有空白字符,防止显示时多出一行

commit 42c2cf0ef2a5c413bcef6f1e3727e79e39590c84
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 12:44:22 2025 +0800

    新增(tcp客户端): 添加支持断线重连的TCP客户端方法

    在 Program.cs 中添加多个异步方法以创建 TCP 客户端,支持断线重连和轮询重连配置。修改 RunClientForReadAsync 方法以使用新连接字符串格式并实现异步阻塞接收数据。更新 tcpclient.mdx 文档,使用 CustomCodeBlock 组件提升可读性,增加关于重连策略的详细说明。添加 TcpClientReceivedPlugin 插件类以处理接收到的数据并记录日志。更新示例代码以保持一致性并提供更清晰的使用说明

commit 946128547fb767968e281f7f8e9a97251a00163c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 12:12:28 2025 +0800

    新增(tcpclient): 新增TCP客户端配置方法和文档

    在 `Program.cs` 文件中,新增 `CreateTcpClientConfig` 方法以配置 TCP 客户端的参数,并新增 `RunClientForReadAsync` 方法用于异步读取数据

    在 `tcpclient.mdx` 文件中,更新文档内容,详细说明 TCP 客户端配置项,并引入 `CustomCodeBlock` 组件展示代码块

commit 2b5716353de45a3afa2518166e46b92139ef5477
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 11:40:14 2025 +0800

    重构(codesData.js): 删除冗余注释和文件信息

    在 .gitignore 文件中,添加对 `handbook/docs/CodeBlocks/codesData.js` 的忽略规则。
    在 `codesData.js` 文件中,删除大量注释行和文件信息,移除不再需要的功能,简化代码结构,提高可读性和维护性

commit 0b80260d25580c6876204198e173722932fc387d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 10:31:46 2025 +0800

    重构(CustomCodeBlock): 修改组件导入路径和实现逻辑

    - 修改 `CustomCodeBlock` 组件的导入路径为相对路径
    - 更新 `generate-codes` 命令的路径以反映项目结构变化
    - 删除 `CustomCodeBlock.js` 和 `generateCodesModule.js` 中的冗余代码
    - 在 `codesData.js` 中添加 `fileInfos`、`searchDirectories` 和 `validDirectories` 常量
    - 增加高亮规则解析和区域提取功能
    - 更新 `README.md` 和 `usage-example.md` 文档以反映新功能

commit bfc219f848345fd0d1039503c586fe973f34af3b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sat Aug 23 10:26:22 2025 +0800

    重构(components): 更新CustomCodeBlock组件实现

    将CustomCodeBlock的导入路径更改为新的实现,确保所有文件使用最新版本。删除旧的实现并添加新的逻辑以支持高亮规则解析、代码加载和错误处理,提升组件功能性和用户体验

commit f979703142f34a9128aee2ab5779e50fb089e1cc
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Aug 22 22:44:12 2025 +0800

    优化(文档): 更新文档链接和API说明

    - 移除方法异常抛出,改为返回结果
    - 调整插件配置方式,简化用户体验
    - 新增WebSocket同步非阻塞读取功能
    - 增加WSDataFrame新属性,增强数据帧功能
    - 新增静态网页插件委托,支持请求重定向和header设置
    - 整体功能迁移至TouchSocket(Pro).Dmtp,简化模块
    - 调整RpcActionFilter执行策略和顺序,优化RPC调用流程
    - 新增RealityProxy和DispatchProxy透明代理及AOP调用功能
    - TouchRpc全系改名为Dmtp,更新调用选项
    - 修复JsonRpc内联数组调用问题,提升稳定性
    - WebApi新增Swagger页面,方便查看API文档
    - 修复WebSocket代码差异,确保兼容性
    - 新增JsonPackageAdapter适配器,解决Json粘分包问题
    - IByteBlock新增WriteNormalString方法,增强字符串写入功能
    - 所有组件支持Scoped容器,提升依赖注入灵活性

commit d627960cb086febfae9b3b90d695e141bf4e34ee
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Aug 22 22:01:50 2025 +0800

    新增(TcpService): 添加TcpService和MyService配置示例

    在Program.cs中添加TcpService和MyService的配置与使用示例,展示异步接收数据和发送消息功能
    新增CreateDefaultService2方法以动态添加和移除监听配置
    更新GetTouchSocketConfig方法确保配置生成策略正确
    在TcpServiceReceivedPlugin中添加接收数据处理逻辑
    重写MyService中的LoadConfig和NewClient方法以支持自定义配置
    更新文档以说明动态添加和移除监听配置的灵活性
    展示如何使用插件处理接收数据并提供异步阻塞接收示例
    强调发送数据时使用异步发送的优势并提供示例

commit f3e9d1616b9711c4aa59fda590097419d4a7afb5
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Aug 22 21:09:02 2025 +0800

    新增(升级文档): 添加 v3.1.16 更新内容

    在 upgrade.mdx 中添加 v3.1.16 更新内容,包括 SSL 配置重构、安全性改进、代码格式优化和版本号更新。更新 v0.mdx、v1.mdx、v2-0.mdx、v2-1.mdx、v3-0.mdx 和 v3-1.mdx 文件,详细描述各版本的更新和优化措施,强调兼容性更新

commit a5e2069d638436ea95232b15ce88e7736d4cca63
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Aug 22 13:14:40 2025 +0800

    文档(upgrade): 更新历史记录和版本信息

    在 `upgrade.mdx` 中添加 `Tag` 和 `Highlight` 组件的导入,更新历史记录,增加版本号、更新日期和更新描述等信息,详细列出每个版本的更新详情

    在 `v0.mdx` 中记录版本 0.7.0 到 0.1.0 的更新,描述兼容性修复、性能优化和新增功能

    在 `v1.mdx` 中记录 v1 系列更新,强调兼容性更新和新增功能

    在 `v2-0.mdx` 中记录 v2.0 系列更新,列出每个版本的更新日期和描述

    在 `v2-1.mdx` 中记录 v2.1 系列更新,描述修复和优化内容

    在 `v3-0.mdx` 中记录 v3.0 系列更新,列出每个版本的更新日期和描述

    在 `v3-1.mdx` 中记录 v3.1 系列更新,描述安全性改进、代码格式优化和版本号更新

commit d95535b7160610f7178772db22acf02f0e11857d
Author: 若汝棋茗 <505554090@qq.com>
Date:   Fri Aug 22 11:23:12 2025 +0800

    文档: 更新升级文档和版本日志

    移除对 Tag.js 和 Highlight.js 的导入,简化依赖
    更新升级文档中的提示信息,强调破坏性标签类型
    修改版本号规则描述,明确发版规则
    增加各版本更新的详细描述,包括修复和优化
    更新多个版本的更新日志,涵盖 v1.0 到 v3.1
    增加新特性说明,如异步方法支持和性能优化
    更新侧边栏文档链接,确保用户访问更新信息

commit 08097e2fddeafd9eb742149fb766698f132c7d93
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Aug 21 23:11:35 2025 +0800

    新增(tcpservice): 添加SSL支持和事件处理逻辑

    在Program.cs中添加对SSL证书的支持,新增CreateDefaultService方法以处理TcpService的连接和接收事件。更新GetTouchSocketConfig方法以配置服务器参数。更新tcpservice.mdx文档,增加代码示例并删除过时内容

commit dbea997a8edf5267381875b8987fea9a55af251f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Thu Aug 21 13:39:17 2025 +0800

    文档:更新日志

commit cba9a4de91b25092fe0aa08d4f73a265c01b256f
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Aug 20 23:19:10 2025 +0800

    新增(文档): 添加TcpService最大连接数说明

    在tcpservice.mdx文件中,添加关于TcpService最大连接数的说明,指出可以通过SetMaxCount方法设置最大连接数,默认值为10000

commit 2bb583c1cecb4d331f96590baac0dcfcd8dc6668
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Aug 20 22:31:40 2025 +0800

    更新(版本管理): 更新版本和增强配置示例

    更新 `TouchSocketVersion.props` 文件中的 `BaseVersion` 属性,修改 `Program.cs` 中的 TCP 服务器监听配置,增加示例代码和详细说明,更新 `AnalyzerReleases.Shipped.md` 文件,添加新规则,增强 `CoreAnalyzer.cs` 对插件接口的支持,简化 `ContainerAttribute.cs` 和 `ContainerCodeBuilder.cs` 中的代码,更新序列化逻辑,重构方法调用生成器,增加对异步方法的支持,确保 RPC 函数参数标识 `[FromServices]`,增强 `Utils.cs` 对可管理类型的支持,更新 Web API 客户端代码生成逻辑,升级 `Microsoft.CodeAnalysis.CSharp` 的引用版本

commit fd67ae13e206803d880bd4ef39629cca1a49e42f
Merge: 60da12241 318f71efb
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Aug 20 22:29:49 2025 +0800

    Merge branch 'v4.0.0-Alpha' of https://github.com/RRQM/TouchSocket into v4.0.0-Alpha

commit 318f71efbef86d2b45f9bd007a775665ac33c9d4
Author: Diego2098 <82756760+kimdiego2098@users.noreply.github.com>
Date:   Wed Aug 20 22:16:45 2025 +0800

    修复管道读取处理逻辑 (#74)

    * 修复适配器缓存

    * 修复管道读取处理逻辑

commit 60da12241270112c30d6e0e38aa48341a00b986c
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Aug 20 21:20:32 2025 +0800

    新增(Program): 添加GetTouchSocketConfig方法

    更新tcpservice.mdx文件中的TcpService和SessionClient描述,使用反引号提高可读性

commit de2d8a6eb085e5d436e46b796db0afffa6154f33
Author: Diego2098 <82756760+kimdiego2098@users.noreply.github.com>
Date:   Wed Aug 20 16:46:23 2025 +0800

    修复适配器缓存 (#73)

commit 3d953b9190e2be26f57ce9c3676dd8d167e312e1
Author: 若汝棋茗 <505554090@qq.com>
Date:   Wed Aug 20 13:03:49 2025 +0800

    新增(Program, doc, bilibili-card-test, custombetweenanddatahandlingadapter): 新增区间字符实体类及相关代码片段

    在 `Program.cs` 文件中,新增 `MyBetweenAndRequestInfo` 内部类,实现 `IRequestInfo` 接口,并添加 `MyCustomBetweenAndDataHandlingAdapter` 类。
    在 `doc.code-snippets` 中,添加 `importCustomCodeBlock` 和 `CustomCodeBlock` 代码片段。
    在 `bilibili-card-test.mdx` 中,删除原有 BilibiliCard 组件测试内容。
    在 `custombetweenanddatahandlingadapter.mdx` 中,导入 `CustomCodeBlock` 组件并插入示例

commit 9536f6c4137d2bca46c8c226e9716aa13830519e
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 22:57:53 2025 +0800

    新增(文档): 更新多个文档和示例代码

    - 在 `docusaurus.config.ts` 中更新版本信息
    - 在多个 `.mdx` 文件中添加适配器、服务、插件等的定义和使用示例
    - 增加对 WebSocket、XmlRpc、Dmtp 等组件的详细说明
    - 更新赞助信息和博客链接
    - 增加对文件传输、数据同步等项目的介绍

commit 912d2a5131c606af3bedc2759e0d4ad6ee2c0336
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 22:39:49 2025 +0800

    Implement feature X to enhance user experience and fix bug Y in module Z

commit 1eacc270bc686e66975855c02672d91634663585
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 22:29:43 2025 +0800

    升级(TouchSocket): 更新TouchSocket相关包版本

    更新多个项目文件中的TouchSocket相关包版本,从3.7.2.40升级到3.7.2.41,确保与新版本兼容
    在Program.cs中添加MemoryPack和TouchSocket命名空间引用
    更新MemoryPackSerializationSelector.cs中的序列化和反序列化逻辑
    更新多个控制台应用程序和库项目以支持新版本
    更新Form1.cs中的Udp客户端使用方式
    确保Tcp和Udp相关项目使用最新TouchSocket库
    更新WebApi相关项目中的TouchSocket.WebApi和TouchSocket.WebApi.Swagger引用
    更新XmlRpc相关项目中的TouchSocket.XmlRpc引用

commit 9c27cf41bb74b40e9f8a600b30b90bd462360b14
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 21:54:48 2025 +0800

    优化(TouchSocket): 更新TouchSocket包版本至3.7.2.40

    - 所有项目的 `TouchSocket` 相关 NuGet 包版本从 `3.7.2.34` 更新至 `3.7.2.40`,以确保使用最新的功能和修复
    - 移除 `Program.cs` 中 `MyFixedSizePackageAdapter` 类的 `PreviewSendAsync` 方法,简化代码
    - 重构多个项目中的 `TouchSocket` 相关类和方法,使用现代异步编程模式
    - 修改 `DmtpRpcConsoleApp` 中 `DmtpInvokeOption` 构造函数,增加超时参数
    - 在 `Modbus` 相关项目中使用新的 `ValueByteBlock` 类,改进内存管理和数据处理效率
    - 更新多个项目中的 `TouchSocket` 插件和适配器实现,支持新功能和性能改进
    - 更新 `WebApi` 相关项目中的 `TouchSocket.WebApi` 和 `TouchSocket.WebApi.Swagger` 版本,确保与最新API规范兼容
    - 调整 `Udp` 相关项目中的适配器实现,支持更灵活的数据处理方式
    - 其他项目也进行了类似的版本更新和代码重构,提高整体代码质量和性能

commit c65684898af1e95da29869d22da6fe60ef675588
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 21:32:18 2025 +0800

    优化(Form1, Program, TcpService): 更新事件处理和异常管理

    在 `Form1.Designer.cs` 中,移除多余注释和控件初始化代码,简化代码结构
    在 `Form1.cs` 中,改进 TCP 服务和客户端的事件处理逻辑,增强异常处理和日志记录
    在 `Program.cs` 中,优化异步操作和请求超时设置
    更新 `TLVWinFormsApp.csproj` 中的 TouchSocket 包引用版本
    改进多个类的方法参数和返回值,提升代码可读性和性能
    更新 `MemoryPackSerializationSelector.cs` 中的序列化和反序列化方法,确保兼容性
    增强 `TcpServiceController` 和 `TcpServiceReceiveAsyncPlugin` 中的 TCP 客户端处理能力
    更新 `Touch_HttpDmtp.cs` 和 `Touch_WebSocket.cs` 中的日志记录方式,确保准确性
    优化 `BigDataHttpContent` 类的内容写入方法,提升异步处理性能
    更新 `TcpStressTestingConsoleApp` 中的通道创建和数据发送逻辑,增强异常处理能力

commit f355e2741a87699e830e7adf99b35867c6638b78
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 20:54:42 2025 +0800

    优化(Program): 优化ByteBlock管理和异步操作

    在Program.cs中优化ByteBlock的生命周期管理,移除using语句并确保在finally块中调用Dispose方法。修改MyCustomDataHandlingAdapter类的Filter方法,移除tempCapacity参数并调整逻辑。更新SimpleDmtpRpcActor类的方法签名,增加CancellationToken参数以支持异步取消。调整MySerializationSelector类的泛型约束,确保与IBytesReader和IBytesWriter接口兼容。使用await替换同步调用,提升异步操作的响应性。修改RpcPushChannel和RpcPullChannel方法,使用await foreach处理异步流。调整多个方法的返回值类型,提升可读性和可维护性。增加DmtpOption配置中的超时设置,确保远程调用的超时处理。更新MyClass5FastBinaryConverter中的读取值方法,确保与新的泛型约束匹配。修改Form1.cs中对PingAsync方法的调用,确保客户端在线状态判断的准确性

commit d593cb782f3f207704f8181bea73e53ced560a24
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 20:11:54 2025 +0800

    更新 .gitignore 和 package.json,添加代码生成命令

commit e175c59be705b75c83469e1833d77bcdcaace8dc
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 19:55:48 2025 +0800

    重构: 更新 Git 提交模板路径并重新添加模板文件

commit fc9067038abdedd98caaf1fe8f7792e8c98b4e49
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 19:54:18 2025 +0800

    feat: 添加 Git 提交配置和 Copilot 设置

commit 265e94d7bdcf4c1325bf9ed3d741b96c9364eda6
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 16:02:58 2025 +0800

    feat: add syntax highlighting support for code regions

    - Enhanced the `extractCodeRegion` function to support highlighting specific lines within code regions using a new syntax.
    - Introduced a `parseHighlightSyntax` function to parse highlight strings like "{1,2-3,5}" into an array of line numbers.
    - Updated the region start regex to optionally capture highlight syntax.
    - Modified the output of `extractCodeRegion` to include an array of highlighted lines.

commit e91da8b2217ecf30f4b098cd19557b6b9911d1cd
Author: 若汝棋茗 <505554090@qq.com>
Date:   Tue Aug 19 14:15:45 2025 +0800

    feat: Add CodeBlocks component and code generation module

    - Implemented a new CodeBlocks component that extracts code snippets from a generated codes.cs file based on region titles.
    - Created a generateCodesModule.js script to recursively search for .cs files, read their content, and merge them into a single module.
    - Added functionality to handle regions within the code, allowing for extraction and display of specific code blocks.
    - Documented usage examples and component parameters in usage-example.md for clarity on implementation.

commit 25835e05eb1fa1e1ff6573d55f9e11b0b1bb77ef
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 18 23:03:57 2025 +0800

    重构(Program): 优化字节读写方法和内存管理

    在 `Program.cs` 中替换字节读写方法为 `WriterExtension` 和 `ReaderExtension`,提高代码可读性和一致性
    将 `MyCustomBetweenAndDataHandlingAdapter` 中的 `m_startCode` 和 `m_endCode` 类型改为 `ReadOnlyMemory<byte>`,优化内存管理
    更新 `MyBigUnfixedHeaderRequestInfo` 的解析方法,增强灵活性
    优化 `MyPackage` 和相关类的数据打包解包逻辑,确保一致性
    整理多个文件的 `using` 语句顺序,提升整洁性
    更新项目的程序集信息和元数据,反映最新状态

commit 08ff7b79d4aa68ce183f68f9cdf4faab85c33b2b
Author: 若汝棋茗 <505554090@qq.com>
Date:   Mon Aug 18 22:24:25 2025 +0800

    重构(程序): 移除ByteBlock,改用Memory处理数据

    - 代码中移除了对 `ByteBlock` 的使用,改为使用 `Memory` 进行数据处理,涉及多个类和方法
    - 在 `Program.cs` 中添加了对 `TcpDataAdapterTester` 的异步支持,更新测试逻辑
    - 增加异常处理支持,确保接收数据时能够正确捕获异常
    - 更新多个插件类,确保使用 `Memory` 提高性能和内存管理
    - 更新 `Form1.cs` 中的 UI 相关代码,确保正确处理和显示图像
    - 其他地方的代码也进行了相应更新,确保数据处理一致性

commit e8eb99b78d661878ea65a12ec0082b62033b83d6
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 17 22:51:10 2025 +0800

    升级(TouchSocket): 更新多个TouchSocket包版本

    更新所有项目文件中的TouchSocket相关包版本至3.7.2.34以利用新功能和修复错误
    在Program.cs中优化TcpService的Received事件处理方式
    确保项目设置与新版本兼容

commit e7664903e8ab365745ee2da860b8ab58fe121ee6
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Aug 17 22:32:14 2025 +0800

    发布:4.0.0-Alpha.12

commit 1cdfae1f6420f49c2d7d8860e1b23dc937d12249
Author: 若汝棋茗 <505554090@qq.com>
Date:   Sun Jul 27 21:51:09 2025 +0800

    发布:预发行版4.0.0
This commit is contained in:
若汝棋茗
2025-11-23 12:16:30 +08:00
parent fa89562f9d
commit ac7e87affb
1612 changed files with 82358 additions and 63311 deletions

View File

@@ -0,0 +1,36 @@
---
mode: agent
---
# 前提
你是一个CSharp编程文档生成专家精通各种类型的文档写作包括技术文档、用户手册、项目报告等。你能够根据用户提供的信息和要求生成结构清晰、内容详实、语言流畅的文档。
# 文档生成前置工作
1. 阅读用户提供的需求,理解文档的主题、目标读者和预期用途。
2. 你需要先阅读源代码内容他们都在src文件夹下src文件夹下有多个子文件夹每个子文件夹代表一个独立的模块。每个模块中包含若干CSharp源代码文件.cs和一个README.md文件。README.md文件中包含该模块的简要介绍和使用说明。
3. 在生成文档时你还需要参考一些示例代码这些示例代码都在examples文件夹下examples文件夹下有多个子文件夹每个子文件夹代表一个独立的示例。每个示例中包含若干CSharp源代码文件.cs文件中包含该示例的简要介绍和使用说明。
# 在文档中的代码要求(绝对必须)
- 在生成的文档中所有csharp代码绝对不要直接包含代码块。
- 把需要包含的代码示例,全部在**示例工程中**编写并使用region包裹在文档中只需要使用`CustomCodeBlock`引用即可。
- 如果需要引用的代码示例在示例工程中不方便使用region或者不能简洁地表达可以在**示例工程中**新建一个文件,或方法,专门用于放置这些代码示例。
# 示例代码
示例代码工程(整个解决方案)在文档编写完成后,必须保证能够编译通过。
# region 标签生成规则
- region 标签的命名必须简洁明了,能够准确表达代码示例的内容。
- region 标签的命名主体使用中文。
- region 标签的命名格式为:`<当前文档个主题>`+`<功能描述>`。例如:`Http启用跨域``WebApi使用FromQuery传参``Rpc使用调用上下文`等。
- region 标签中(即`CustomCodeBlock`只填充region即可不用写filePath等其他东西。
- region 标签格式:<CustomCodeBlock region="region名称"/>
# 任务
- 你的任务是把文档中的代码示例提取到示例工程中或者直接使用示例工程中的代码并使用region包裹然后在文档中使用`CustomCodeBlock`引用这些代码示例。你需要确保生成的文档符合用户的要求,内容准确无误,语言表达清晰流畅。
- 如果文档中已经有`CustomCodeBlock`,则不再修改这些`CustomCodeBlock`,只需要处理没有`CustomCodeBlock`的代码示例即可。

45
.github/prompts/文档生成.prompt.md vendored Normal file
View File

@@ -0,0 +1,45 @@
---
mode: agent
---
# 前提
你是一个CSharp编程文档生成专家精通各种类型的文档写作包括技术文档、用户手册、项目报告等。你能够根据用户提供的信息和要求生成结构清晰、内容详实、语言流畅的文档。
# 文档生成前置工作
1. 阅读用户提供的需求,理解文档的主题、目标读者和预期用途。
2. 你需要先阅读源代码内容他们都在src文件夹下src文件夹下有多个子文件夹每个子文件夹代表一个独立的模块。每个模块中包含若干CSharp源代码文件.cs和一个README.md文件。README.md文件中包含该模块的简要介绍和使用说明。
3. 在生成文档时你还需要参考一些示例代码这些示例代码都在examples文件夹下examples文件夹下有多个子文件夹每个子文件夹代表一个独立的示例。每个示例中包含若干CSharp源代码文件.cs文件中包含该示例的简要介绍和使用说明。
# 在文档中的代码要求(绝对必须)
- 在生成的文档中所有csharp代码绝对不要直接包含代码块。
- 把需要包含的代码示例,全部在**示例工程中**编写并使用region包裹在文档中只需要使用`CustomCodeBlock`引用即可。
- 如果需要引用的代码示例在示例工程中不方便使用region或者不能简洁地表达可以在**示例工程中**新建一个文件,或方法,专门用于放置这些代码示例。
# 示例代码
示例代码工程(整个解决方案)在文档编写完成后,必须保证能够编译通过。
# region 标签生成规则
- region 标签的命名必须简洁明了,能够准确表达代码示例的内容。
- region 标签的命名主体使用中文。
- region 标签的命名格式为:`<当前文档个主题>`+`<功能描述>`。例如:`Http启用跨域``WebApi使用FromQuery传参``Rpc使用调用上下文`等。
- region 标签中(即`CustomCodeBlock`只填充region即可不用写filePath等其他东西。
- region 标签格式:<CustomCodeBlock region="region名称"/>
# 视频链接规则
- 如果文档中包含视频链接,在重写文档时,链接必须保持。
- 不要生成不存在的视频链接。
# 任务
- 1. 提取关键信息,组织内容结构,撰写文档内容。如果文档已存在,则需要适当润色和扩展内容。
- 2. 根据用户提供的需求生成相应的CSharp编程文档。你需要根据源代码和示例代码提取关键信息组织内容结构撰写文档内容。
- 3. 确保生成的文档符合用户的要求,内容准确无误,语言表达清晰流畅。
- 4. 在生成的文档中添加示例Demo的链接链接格式为<CardLink link="示例代码相对路径"/>。其中link属性表示示例代码的相对路径这路径都是从`examples`文件夹开始的,例如:<CardLink link="examples/Tcp/TcpCommandLineConsoleApp"/>。如果一个文档中包含多个示例代码链接,则需要分别在对应章节中添加多个`CardLink`标签。

2
.gitignore vendored
View File

@@ -340,3 +340,5 @@ ASALocalRun/
# BeatPulse healthcheck temp database
healthchecksdb
handbook/package-lock.json
handbook/src/components/CodeBlocks/codesData.js
handbook/docs/CodeBlocks/codesData.js

266
.vscode/doc.code-snippets vendored Normal file
View File

@@ -0,0 +1,266 @@
{
// Place your handbook 工作区 snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
"mdx": {
"prefix": "mdx",
"body": [
"---",
"id: upgrade",
"title: 历史更新",
"---"
],
"description": "mdx"
},
"code": {
"prefix": "code",
"body": [
"```csharp {1,4-6,11} showLineNumbers",
"$0",
"```"
],
"description": "code"
},
"note": {
"prefix": "note",
"body": [
":::note",
"",
"$0",
"",
"::: "
],
"description": "note"
},
"tip": {
"prefix": "tip",
"body": [
":::tip",
"",
"$0",
"",
"::: "
],
"description": "tip"
},
"info": {
"prefix": "info",
"body": [
":::info",
"",
"$0",
"",
"::: "
],
"description": "info"
},
"caution": {
"prefix": "caution",
"body": [
":::caution",
"",
"$0",
"",
"::: "
],
"description": "caution"
},
"danger": {
"prefix": "danger",
"body": [
":::danger",
"",
"$0",
"",
"::: "
],
"description": "danger"
},
"img": {
"prefix": "img",
"body": [
"![]($0)",
],
"description": "img"
},
"imgstatic": {
"prefix": "imgstatic",
"body": [
"![](\"$0\")",
],
"description": "imgstatic"
},
"imgLink": {
"prefix": "imgLink",
"body": [
"<img src={require('@site/static/img/docs/$0').default} width=\"500\" />",
],
"description": "imgLink"
},
"link": {
"prefix": "link",
"body": [
"[$1]($0)",
],
"description": "link"
},
"linkstatic": {
"prefix": "linkstatic",
"body": [
"[$1](\"./$0\")",
],
"description": "linkstatic"
},
"importHighlight": {
"prefix": "importHighlight",
"body": [
"import Highlight from '@site/src/components/Highlight.js';"
],
"description": "importHighlight"
},
"importCustomCodeBlock": {
"prefix": "importCustomCodeBlock",
"body": [
"import CustomCodeBlock from './CodeBlocks/CustomCodeBlock';"
],
"description": "importCustomCodeBlock"
},
"importBilibiliCard": {
"prefix": "importBilibiliCard",
"body": [
"import BilibiliCard from '@site/src/components/BilibiliCard.js';"
],
"description": "importBilibiliCard"
},
"importTag": {
"prefix": "importTag",
"body": [
"import Tag from \"@site/src/components/Tag.js\";"
],
"description": "importTag"
},
"importPro": {
"prefix": "importPro",
"body": [
"import Pro from \"@site/src/components/Pro.js\";"
],
"description": "importPro"
},
"importCardLink": {
"prefix": "importCardLink",
"body": [
"import CardLink from \"@site/src/components/CardLink.js\";"
],
"description": "importCardLink"
},
"CardLink": {
"prefix": "CardLink",
"body": [
"<CardLink link=\"$0\" isPro=\"true\"/>"
],
"description": "CardLink"
},
"CustomCodeBlock": {
"prefix": "CustomCodeBlock",
"body": [
"<CustomCodeBlock region=\"$0\"/>"
],
"description": "CustomCodeBlock"
},
"BilibiliCard": {
"prefix": "BilibiliCard",
"body": [
"<BilibiliCard title=\"$0\" link=\"$1\" isPro=\"true\"/>"
],
"description": "BilibiliCard"
},
"Tag": {
"prefix": "Tag",
"body": [
"<Tag>$0</Tag>"
],
"description": "importTag"
},
"Highlight": {
"prefix": "Highlight",
"body": [
"<Highlight color=\"#25c2a0\">Docusaurus 绿</Highlight>"
],
"description": "tagHighlight"
},
"details": {
"prefix": "details",
"body": [
"<details>",
"<summary>$1</summary>",
"<div>",
"",
"$0",
"",
"</div>",
"</details>"
],
"description": "details"
},
"ahref": {
"prefix": "ahref",
"body": [
"<a href=\"$1\">$0</a>"
],
"description": "ahref"
},
"table": {
"prefix": "table",
"body": [
"| 表头 | 表头 |",
"| ---- | ---- |",
"| 单元格 | 单元格 |",
"| 单元格 | 单元格 |",
],
"description": "table"
},
"importTab": {
"prefix": "importTab",
"body": [
"import Tabs from \"@theme/Tabs\";",
"import TabItem from \"@theme/TabItem\";"
],
"description": "importTab"
},
"Tabs": {
"prefix": "Tabs",
"body": [
"<Tabs",
" defaultValue=\"tab1\"",
" values=",
" {[",
" { label: \"tab1\",value: \"tab1\"},",
" { label: \"tab2\", value: \"tab2\" }",
" ]}",
">",
"<TabItem value=\"tab1\">",
"</TabItem>",
"<TabItem value=\"tab2\">",
"</TabItem>",
"</Tabs>",
],
"description": "importTab"
},
"Mermaid": {
"prefix": "mermaid",
"body": [
"```mermaid",
"graph TD;",
"\tA-->B;",
"\tA-->C;",
"\tB-->D;",
"\tC-->D;",
"```"
],
"description": "mermaid"
}
}

64
.vscode/settings.json vendored
View File

@@ -1,3 +1,65 @@
{
"commentTranslate.targetLanguage": "en",
"cSpell.enableFiletypes": [
"mdx"
],
"cSpell.words": [
"appsettings",
"Avalonia",
"Bilibili",
"Boolens",
"bools",
"cref",
"Dmtp",
"endregion",
"Handshaked",
"modbus",
"Multifile",
"netstandard",
"Newtonsoft",
"Querys",
"Reenterable",
"Responsed",
"RRQM",
"Spliter",
"touchsocket",
"typeparam",
"Unpackage",
"ushort",
"winform"
],
"editor.wordWrap": "on",
// "editor.wordWrapColumn": 80,
// 文件编码设置
"files.encoding": "utf8",
"files.autoGuessEncoding": false,
// Git 提交配置
"git.inputValidationLength": 50,
"git.inputValidationSubjectLength": 50,
"git.verboseCommit": true,
"scm.inputFontFamily": "Consolas, 'Courier New', monospace",
"scm.inputFontSize": 14,
// TouchSocket 项目提交规范提示
"git.commitTemplate": "../../gitmessage-template.txt",
// Copilot 配置
"github.copilot.enable": {
"*": true,
"plaintext": true,
"markdown": true,
"scminput": true
},
// Git 提交相关的 Copilot 提示
"github.copilot.editor.enableAutoCompletions": true,
// Paste Image 插件配置
"pasteImage.path": "${projectRoot}/static/img/docs/",
"pasteImage.basePath": "${projectRoot}",
"pasteImage.forceUnixStyleSeparator": true,
"pasteImage.prefix": "",
"pasteImage.suffix": "",
"pasteImage.insertPattern": "<img src={require('@site/${imageFilePath}').default} width=\"500\" />",
"pasteImage.namePrefix": "",
"pasteImage.nameSuffix": "",
"pasteImage.encodePath": "urlEncodeSpace",
"pasteImage.showFilePathConfirmInputBox": false,
"pasteImage.filePathConfirmInputBoxMode": "onlyName",
"pasteImage.defaultName": "${currentFileNameWithoutExt}-YYYYMMDDHHmmss"
}

View File

@@ -1,8 +1,9 @@
<Project>
<Project>
<PropertyGroup>
<BaseVersion>3.1.19</BaseVersion>
<BaseVersion>4.0.0-rc.50</BaseVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<TouchSocketVersion>$(BaseVersion)</TouchSocketVersion>
</PropertyGroup>

View File

@@ -1,273 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace AdapterConsoleApp;
internal class Program
{
private static async Task Main(string[] args)
{
var service = await CreateService();
var client = await CreateClient();
ConsoleLogger.Default.Info("输入任意内容回车发送将会循环发送10次");
while (true)
{
var str = Console.ReadLine();
for (var i = 0; i < 10; i++)
{
await client.SendAsync(str);
}
}
}
private static async Task<TcpClient> CreateClient()
{
var client = new TcpClient();
//载入配置
await client.SetupAsync(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetTcpDataHandlingAdapter(() => new MyDataHandleAdapter())
.ConfigureContainer(a =>
{
a.AddConsoleLogger();//添加一个日志注入
}));
await client.ConnectAsync();//调用连接,当连接不成功时,会抛出异常。
client.Logger.Info("客户端成功连接");
return client;
}
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
service.Received = (client, e) =>
{
//从客户端收到信息
var mes = e.ByteBlock.Span.ToString(Encoding.UTF8);
client.Logger.Info($"已从{client.Id}接收到信息:{mes}");
return Task.CompletedTask;
};
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
.SetTcpDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromSeconds(1) })
.ConfigureContainer(a =>
{
a.AddConsoleLogger();//添加一个控制台日志注入注意在maui中控制台日志不可用
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}));
await service.StartAsync();//启动
service.Logger.Info("服务器已启动");
return service;
}
}
internal class MyDataHandleAdapter : SingleStreamDataHandlingAdapter
{
/// <summary>
/// 包剩余长度
/// </summary>
private byte m_surPlusLength;
/// <summary>
/// 临时包,此包仅当前实例储存
/// </summary>
private ByteBlock m_tempByteBlock;
public override bool CanSendRequestInfo => false;
public override bool CanSplicingSend => false;
protected override async Task PreviewReceivedAsync(ByteBlock byteBlock)
{
//收到从原始流式数据。
var buffer = byteBlock.TotalMemory.GetArray().Array;
var r = byteBlock.Length;
if (this.m_tempByteBlock == null)//如果没有临时包,则直接分包。
{
await this.SplitPackageAsync(buffer, 0, r);
}
else
{
if (this.m_surPlusLength == r)//接收长度正好等于剩余长度,组合完数据以后直接处理数据。
{
this.m_tempByteBlock.Write(new ReadOnlySpan<byte>(buffer, 0, this.m_surPlusLength));
await this.PreviewHandleAsync(this.m_tempByteBlock);
this.m_tempByteBlock = null;
this.m_surPlusLength = 0;
}
else if (this.m_surPlusLength < r)//接收长度大于剩余长度,先组合包,然后处理包,然后将剩下的分包。
{
this.m_tempByteBlock.Write(new ReadOnlySpan<byte>(buffer, 0, this.m_surPlusLength));
await this.PreviewHandleAsync(this.m_tempByteBlock);
this.m_tempByteBlock = null;
await this.SplitPackageAsync(buffer, this.m_surPlusLength, r);
}
else//接收长度小于剩余长度,无法处理包,所以必须先组合包,然后等下次接收。
{
this.m_tempByteBlock.Write(new ReadOnlySpan<byte>(buffer, 0, r));
this.m_surPlusLength -= (byte)r;
}
}
}
protected override async Task PreviewSendAsync(ReadOnlyMemory<byte> memory)
{
//在发送流式数据之前
var length = memory.Length;
if (length > byte.MaxValue)//超长判断
{
throw new OverlengthException("发送数据太长。");
}
//从内存池申请内存块因为此处数据绝不超过255所以避免内存池碎片化每次申请1K
//ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。
using (var byteBlock = new ByteBlock(1024))
{
byteBlock.WriteByte((byte)length);//先写长度
byteBlock.Write(memory.Span);//再写数据
await this.GoSendAsync(byteBlock.Memory);
}
}
protected override async Task PreviewSendAsync(IList<ArraySegment<byte>> transferBytes)
{
//使用拼接模式发送,在发送流式数据之前
var dataLen = 0;
foreach (var item in transferBytes)
{
dataLen += item.Count;
}
if (dataLen > byte.MaxValue)//超长判断
{
throw new OverlengthException("发送数据太长。");
}
//从内存池申请内存块因为此处数据绝不超过255所以避免内存池碎片化每次申请1K
//ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。
using (var byteBlock = new ByteBlock(1024))
{
byteBlock.WriteByte((byte)dataLen);//先写长度
foreach (var item in transferBytes)
{
byteBlock.Write(new ReadOnlySpan<byte>(item.Array, item.Offset, item.Count));//依次写入
}
await this.GoSendAsync(byteBlock.Memory);
}
}
protected override async Task PreviewSendAsync(IRequestInfo requestInfo)
{
//使用对象发送,在发送流式数据之前
if (requestInfo is MyClass myClass)
{
var data = myClass.Data ?? Array.Empty<byte>();
if (data.Length > byte.MaxValue)//超长判断
{
throw new OverlengthException("发送数据太长。");
}
//从内存池申请内存块因为此处数据绝不超过255所以避免内存池碎片化每次申请1K
//ByteBlock byteBlock = new ByteBlock(dataLen+1);//实际写法。
using (var byteBlock = new ByteBlock(1024))
{
byteBlock.WriteByte((byte)data.Length);//先写长度
byteBlock.WriteByte((byte)myClass.DataType);//然后数据类型
byteBlock.WriteByte((byte)myClass.OrderType);//然后指令类型
byteBlock.Write(data);//再写数据
await this.GoSendAsync(byteBlock.Memory);
}
}
}
/// <summary>
/// 处理数据
/// </summary>
/// <param name="byteBlock"></param>
private async Task PreviewHandleAsync(ByteBlock byteBlock)
{
try
{
await this.GoReceivedAsync(byteBlock, null);
}
finally
{
byteBlock.Dispose();//在框架里面将内存块释放
}
}
/// <summary>
/// 分解包
/// </summary>
/// <param name="dataBuffer"></param>
/// <param name="index"></param>
/// <param name="r"></param>
private async Task SplitPackageAsync(byte[] dataBuffer, int index, int r)
{
while (index < r)
{
var length = dataBuffer[index];
var recedSurPlusLength = r - index - 1;
if (recedSurPlusLength >= length)
{
var byteBlock = new ByteBlock(length);
byteBlock.Write(new ReadOnlySpan<byte>(dataBuffer, index + 1, length));
await this.PreviewHandleAsync(byteBlock);
this.m_surPlusLength = 0;
}
else//半包
{
this.m_tempByteBlock = new ByteBlock(length);
this.m_surPlusLength = (byte)(length - recedSurPlusLength);
this.m_tempByteBlock.Write(new ReadOnlySpan<byte>(dataBuffer, index + 1, recedSurPlusLength));
}
index += length + 1;
}
}
}
internal class MyClass : IRequestInfo
{
public OrderType OrderType { get; set; }
public DataType DataType { get; set; }
public byte[] Data { get; set; }
}
internal enum DataType : byte
{
Down = 0,
Up = 1
}
internal enum OrderType : byte
{
Hold = 0,
Go = 1
}

View File

@@ -7,6 +7,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -31,7 +31,7 @@ internal class Program
Console.WriteLine(obj.Message);
}
private static void TcpDataAdapterTester()
private static async Task TcpDataAdapterTester()
{
//Tcp适配器测试
//bufferLength的作用是模拟tcp接收缓存区例如
@@ -45,8 +45,8 @@ internal class Program
{
var isSuccess = true;
var data = new byte[] { 0, 1, 2, 3, 4 };
var tester = TouchSocket.Sockets.TcpDataAdapterTester.CreateTester(new FixedHeaderPackageAdapter()
, bufferLength, async (byteBlock, requestInfo) =>
var tester = TouchSocket.Core.TcpDataAdapterTester.CreateTester(new FixedHeaderPackageAdapter()
, async (byteBlock, requestInfo) =>
{
//此处就是接收如果是自定义适配器可以将requestInfo强制转换为实际对象然后判断数据的确定性
if (byteBlock.Length != 5 || (!byteBlock.ToArray().SequenceEqual(data)))
@@ -63,8 +63,7 @@ internal class Program
//随后的两个参数10,10是测试次数和期望次数一般这两个值是相等的。
//意为本次数据将循环发送10次且会接收10次。不然此处会一直阻塞。
//最后一个参数是测试的最大超时时间。
var time = tester.Run(data, 10, 10, 1000 * 10);
Thread.Sleep(1000);
var time = await tester.RunAsync(data, 10, 10, bufferLength, 1000 * 10);
Console.WriteLine($"测试结束,状态:{isSuccess},用时:{time}");
}
Console.WriteLine("测试结束");

View File

@@ -9,6 +9,6 @@
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -18,22 +18,6 @@ namespace BetweenAndConsoleApp;
internal class Program
{
private static async Task Main(string[] args)
{
var service = await CreateService();
var client = await CreateClient();
ConsoleLogger.Default.Info("按任意键发送10次");
while (true)
{
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
await client.SendAsync("**12##12##");
}
}
}
private static async Task<TcpClient> CreateClient()
{
var client = new TcpClient();
@@ -54,6 +38,7 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region
service.Received = (client, e) =>
{
//从客户端收到信息
@@ -64,7 +49,7 @@ internal class Program
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
.SetTcpDataHandlingAdapter(() => new MyCustomBetweenAndDataHandlingAdapter())
@@ -80,6 +65,44 @@ internal class Program
service.Logger.Info("服务器已启动");
return service;
}
private static async Task Main(string[] args)
{
var service = await CreateService();
var client = await CreateClient();
ConsoleLogger.Default.Info("按任意键发送10次");
while (true)
{
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
await client.SendAsync("**12##12##");
}
}
}
}
#region
internal class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter<MyBetweenAndRequestInfo>
{
private readonly ReadOnlyMemory<byte> m_endCode;
private readonly ReadOnlyMemory<byte> m_startCode;
public MyCustomBetweenAndDataHandlingAdapter()
{
this.MinSize = 5;//表示实际数据体不会小于5例如“**12##12##”数据解析后会解析成“12##12”
this.m_startCode = Encoding.UTF8.GetBytes("**");//可以为0长度字节意味着没有起始标识。
this.m_endCode = Encoding.UTF8.GetBytes("##");//必须为有效值。
}
public override ReadOnlyMemory<byte> EndCode => this.m_endCode;
public override ReadOnlyMemory<byte> StartCode => this.m_startCode;
protected override MyBetweenAndRequestInfo GetInstance(ReadOnlySpan<byte> body)
{
return new MyBetweenAndRequestInfo(body.ToArray());
}
}
internal class MyBetweenAndRequestInfo : IRequestInfo
@@ -91,26 +114,4 @@ internal class MyBetweenAndRequestInfo : IRequestInfo
public byte[] Body { get; private set; }
}
internal class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter<MyBetweenAndRequestInfo>
{
public MyCustomBetweenAndDataHandlingAdapter()
{
this.MinSize = 5;//表示实际数据体不会小于5例如“**12##12##”数据解析后会解析成“12##12”
this.m_startCode = Encoding.UTF8.GetBytes("**");//可以为0长度字节意味着没有起始标识。
this.m_endCode = Encoding.UTF8.GetBytes("##");//必须为有效值。
}
private readonly byte[] m_startCode;
private readonly byte[] m_endCode;
public override byte[] StartCode => this.m_startCode;
public override byte[] EndCode => this.m_endCode;
protected override MyBetweenAndRequestInfo GetInstance(ReadOnlySpan<byte> body)
{
return new MyBetweenAndRequestInfo(body.ToArray());
}
}
#endregion

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -29,22 +29,27 @@ internal class Program
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
var myRequestInfo = new MyRequestInfo()
var myRequestInfo = new MyDataClass()
{
Body = Encoding.UTF8.GetBytes("hello"),
Data = Encoding.UTF8.GetBytes("hello"),
DataType = (byte)i,
OrderType = (byte)i
};
//构建发送数据
using (var byteBlock = new ByteBlock(1024))
var byteBlock = new ByteBlock(1024);
try
{
byteBlock.WriteByte((byte)(myRequestInfo.Body.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
byteBlock.WriteByte(myRequestInfo.DataType);//然后数据类型
byteBlock.WriteByte(myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Body);//再写数据
WriterExtension.WriteValue(ref byteBlock, (byte)(myRequestInfo.Data.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.DataType);//然后数据类型
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Data);//再写数据
await client.SendAsync(byteBlock.Memory);
}
finally
{
byteBlock.Dispose();
}
}
}
}
@@ -69,17 +74,17 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region 使 {3}
service.Received = (client, e) =>
{
//从客户端收到信息
if (e.RequestInfo is MyRequestInfo myRequest)
if (e.RequestInfo is MyDataClass myRequest)
{
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Body)}");
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Data)}");
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
.SetTcpDataHandlingAdapter(() => new MyCustomDataHandlingAdapter())
@@ -97,77 +102,106 @@ internal class Program
}
}
internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter<MyRequestInfo>
#region
/// <summary>
/// 第1个字节表示指令类型
/// 第2字节表示数据类型
/// 第3字节表示后续数据的长度。使用ushort(大端)表示最大长度为65535
/// 后续字节表示载荷数据
/// 最后2字节表示CRC16校验码
/// </summary>
internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter<MyDataClass>
{
/// <summary>
/// 筛选解析数据。实例化的TRequest会一直保存直至解析成功或手动清除。
/// <para>当不满足解析条件时,请返回<see cref="FilterResult.Cache"/>,此时会保存<see cref="ByteBlock.CanReadLen"/>的数据</para>
/// <para>当数据部分异常时,请移动<see cref="ByteBlock.Pos"/>到指定位置,然后返回<see cref="FilterResult.GoOn"/></para>
/// <para>当完全满足解析条件时,请返回<see cref="FilterResult.Success"/>最后将<see cref="ByteBlock.Pos"/>移至指定位置。</para>
/// </summary>
/// <param name="byteBlock">字节块</param>
/// <param name="beCached">是否为上次遗留对象当该参数为True时request也将是上次实例化的对象。</param>
/// <param name="request">对象。</param>
/// <param name="tempCapacity">缓存容量指导,指示当需要缓存时,应该申请多大的内存。</param>
/// <returns></returns>
protected override FilterResult Filter<TByteBlock>(ref TByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity)
private ushort m_payloadLength;
protected override FilterResult Filter<TReader>(ref TReader reader, bool beCached, ref MyDataClass request)
{
//以下解析思路为一次性解析,不考虑缓存的临时对象。
if (byteBlock.CanReadLength < 3)
if (beCached)
{
return FilterResult.Cache;//当头部都无法解析时,直接缓存
}
//说明上次已经解析了header
var pos = byteBlock.Position;//记录初始游标位置,防止本次无法解析时,回退游标。
var myRequestInfo = new MyRequestInfo();
//此操作实际上有两个作用,
//1.填充header
//2.将byteBlock.Pos递增3的长度。
var header = byteBlock.ReadToSpan(3);//填充header
//因为第一个字节表示所有长度而DataType、OrderType已经包含在了header里面。
//所有只需呀再读取header[0]-2个长度即可。
var bodyLength = (byte)(header[0] - 2);
if (bodyLength > byteBlock.CanReadLength)
{
//body数据不足。
byteBlock.Position = pos;//回退游标
return FilterResult.Cache;
return this.ParseData(ref reader, request);
}
else
{
//此操作实际上有两个作用,
//1.填充body
//2.将byteBlock.Pos递增bodyLength的长度。
var body = byteBlock.ReadToSpan(bodyLength);
//首次解析
myRequestInfo.DataType = header[1];
myRequestInfo.OrderType = header[2];
myRequestInfo.Body = body.ToArray();
request = myRequestInfo;//赋值ref
return FilterResult.Success;//返回成功
if (reader.BytesRemaining < 4)
{
//如果剩余数据小于4个字节则继续等待
return FilterResult.Cache;
}
//读取前4个字节
var header = reader.GetSpan(4);
//推进已读取的4个字节
reader.Advance(4);
//获取指令类型
var orderType = header[0];
//获取数据类型
var dataType = header[1];
//创建数据对象
request = new MyDataClass()
{
OrderType = orderType,
DataType = dataType
};
//获取载荷长度
this.m_payloadLength = TouchSocketBitConverter.BigEndian.To<ushort>(header.Slice(2, 2));
return this.ParseData(ref reader, request);
}
}
private FilterResult ParseData<TReader>(ref TReader reader, MyDataClass myDataClass)
where TReader : IBytesReader
{
//判断剩余数据是否足够,+2是因为最后2个字节是CRC16校验码
if (reader.BytesRemaining < this.m_payloadLength + 2)
{
return FilterResult.Cache;
}
//读取数据
var data = reader.GetSpan(this.m_payloadLength);
reader.Advance(this.m_payloadLength);
//读取CRC16校验码
var crcData = reader.GetSpan(2);
reader.Advance(2);
//转换CRC16校验码为ushort相比于byte[],更节省内存
var crc16 = TouchSocketBitConverter.BigEndian.To<ushort>(crcData);
//计算CRC16
var newCrc16 = Crc.Crc16Value(data);
if (crc16 != newCrc16)
{
//CRC校验失败
throw new Exception("CRC校验失败");
}
//保存数据
myDataClass.Data = data.ToArray();
//至此,数据接收完成,可以进行投递处理
this.m_payloadLength = 0;
return FilterResult.Success;
}
}
internal class MyRequestInfo : IRequestInfo
/// <summary>
/// 定义数据对象
/// </summary>
internal class MyDataClass : IRequestInfo
{
/// <summary>
/// 自定义属性,Body
/// </summary>
public byte[] Body { get; internal set; }
/// <summary>
/// 自定义属性,DataType
/// </summary>
public byte DataType { get; internal set; }
/// <summary>
/// 自定义属性,OrderType
/// </summary>
public byte OrderType { get; internal set; }
public byte OrderType { get; set; }
public byte DataType { get; set; }
public byte[] Data { get; set; }
}
#endregion

View File

@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
@@ -6,38 +18,6 @@ namespace CustomBigFixedHeaderConsoleApp;
internal class Program
{
private static async Task Main(string[] args)
{
var service = await CreateService();
var client = await CreateClient();
ConsoleLogger.Default.Info("按任意键发送10次");
while (true)
{
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
var myRequestInfo = new MyBigFixedHeaderRequestInfo()
{
Body = Encoding.UTF8.GetBytes("hello"),
DataType = (byte)i,
OrderType = (byte)i
};
//构建发送数据
using (var byteBlock = new ByteBlock(1024))
{
byteBlock.WriteByte((byte)(myRequestInfo.Body.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
byteBlock.WriteByte(myRequestInfo.DataType);//然后数据类型
byteBlock.WriteByte(myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Body);//再写数据
await client.SendAsync(byteBlock.Memory);
}
}
}
}
private static async Task<TcpClient> CreateClient()
{
var client = new TcpClient();
@@ -58,16 +38,18 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region
service.Received = (client, e) =>
{
//从客户端收到信息
if (e.RequestInfo is MyBigFixedHeaderRequestInfo myRequest)
if (e.RequestInfo is MyDataClass myRequest)
{
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Body)}");
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
@@ -84,20 +66,75 @@ internal class Program
service.Logger.Info("服务器已启动");
return service;
}
}
internal class MyCustomBigFixedHeaderDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter<MyBigFixedHeaderRequestInfo>
{
public override int HeaderLength => 3;
protected override MyBigFixedHeaderRequestInfo GetInstance()
private static async Task Main(string[] args)
{
return new MyBigFixedHeaderRequestInfo();
var service = await CreateService();
var client = await CreateClient();
ConsoleLogger.Default.Info("按任意键发送10次");
while (true)
{
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
var myRequestInfo = new MyDataClass()
{
Body = Encoding.UTF8.GetBytes("hello"),
DataType = (byte)i,
OrderType = (byte)i
};
//构建发送数据
var byteBlock = new ByteBlock(1024);
try
{
WriterExtension.WriteValue(ref byteBlock, (byte)(myRequestInfo.Body.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.DataType);//然后数据类型
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Body);//再写数据
await client.SendAsync(byteBlock.Memory);
}
finally
{
byteBlock.Dispose();
}
}
}
}
}
internal class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo
#region {10,42-46,48-56,58-74}
/// <summary>
/// 第1个字节表示指令类型
/// 第2字节表示数据类型
/// 第3字节表示后续数据的长度。使用ushort(大端)表示最大长度为65535
/// 后续字节表示载荷数据
/// 最后2字节表示CRC16校验码
/// </summary>
internal class MyCustomBigFixedHeaderDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter<MyDataClass>
{
public override int HeaderLength => 4;
protected override MyDataClass GetInstance()
{
return new MyDataClass();
}
}
internal class MyDataClass : IBigFixedHeaderRequestInfo
{
private readonly List<byte> m_bytes = new List<byte>();
private long m_length;
/// <summary>
/// 自定义属性,标识实际数据
/// </summary>
public byte[] Body { get; set; }
/// <summary>
/// 自定义属性,标识数据类型
/// </summary>
@@ -108,17 +145,7 @@ internal class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo
/// </summary>
public byte OrderType { get; set; }
/// <summary>
/// 自定义属性,标识实际数据
/// </summary>
public byte[] Body { get; set; }
private long m_bodyLength;
private readonly List<byte> m_bytes = new List<byte>();
#region
long IBigFixedHeaderRequestInfo.BodyLength => this.m_bodyLength;
long IBigFixedHeaderRequestInfo.BodyLength => this.m_length;
void IBigFixedHeaderRequestInfo.OnAppendBody(ReadOnlySpan<byte> buffer)
{
@@ -128,7 +155,7 @@ internal class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo
bool IBigFixedHeaderRequestInfo.OnFinished()
{
if (this.m_bytes.Count == this.m_bodyLength)
if (this.m_bytes.Count == this.m_length)
{
this.Body = this.m_bytes.ToArray();
return true;
@@ -138,12 +165,20 @@ internal class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo
bool IBigFixedHeaderRequestInfo.OnParsingHeader(ReadOnlySpan<byte> header)
{
//在该示例中第一个字节表示后续的所有数据长度但是header设置的是3所以后续还应当接收length-2个长度。
this.m_bodyLength = header[0] - 2;
//这里header长度已经经过验证一定是4字节
//获取指令类型
this.OrderType = header[0];
//获取数据类型
this.DataType = header[1];
this.OrderType = header[2];
var payloadLength = TouchSocketBitConverter.BigEndian.To<ushort>(header.Slice(2, 2));
this.m_length = payloadLength + 2;//+2是因为还包含Crc16的长度
return true;
}
#endregion
}
#endregion

View File

@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
@@ -17,7 +29,7 @@ internal class Program
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
var myRequestInfo = new MyBigUnfixedHeaderRequestInfo()
var myRequestInfo = new MyDataClass()
{
Body = Encoding.UTF8.GetBytes("hello"),
DataType = (byte)i,
@@ -25,15 +37,20 @@ internal class Program
};
//构建发送数据
using (var byteBlock = new ByteBlock(1024))
var byteBlock = new ByteBlock(1024);
try
{
byteBlock.WriteByte((byte)(myRequestInfo.Body.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
byteBlock.WriteByte(myRequestInfo.DataType);//然后数据类型
byteBlock.WriteByte(myRequestInfo.OrderType);//然后指令类型
WriterExtension.WriteValue(ref byteBlock, (byte)(myRequestInfo.Body.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.DataType);//然后数据类型
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Body);//再写数据
await client.SendAsync(byteBlock.Memory);
}
finally
{
byteBlock.Dispose();
}
}
}
}
@@ -58,16 +75,17 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region
service.Received = (client, e) =>
{
//从客户端收到信息
if (e.RequestInfo is MyBigUnfixedHeaderRequestInfo myRequest)
if (e.RequestInfo is MyDataClass myRequest)
{
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Body)}");
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
@@ -85,16 +103,23 @@ internal class Program
return service;
}
}
internal class MyCustomBigUnfixedHeaderDataHandlingAdapter : CustomBigUnfixedHeaderDataHandlingAdapter<MyBigUnfixedHeaderRequestInfo>
#region
/// <summary>
/// 第1个字节表示指令类型
/// 第2字节表示数据类型
/// 第3字节表示后续数据的长度。使用ushort(大端)表示最大长度为65535
/// 后续字节表示载荷数据
/// 最后2字节表示CRC16校验码
/// </summary>
internal class MyCustomBigUnfixedHeaderDataHandlingAdapter : CustomBigUnfixedHeaderDataHandlingAdapter<MyDataClass>
{
protected override MyBigUnfixedHeaderRequestInfo GetInstance()
protected override MyDataClass GetInstance()
{
return new MyBigUnfixedHeaderRequestInfo();
return new MyDataClass();
}
}
internal class MyBigUnfixedHeaderRequestInfo : IBigUnfixedHeaderRequestInfo
internal class MyDataClass : IBigUnfixedHeaderRequestInfo
{
/// <summary>
/// 自定义属性,标识数据类型
@@ -117,7 +142,7 @@ internal class MyBigUnfixedHeaderRequestInfo : IBigUnfixedHeaderRequestInfo
private int m_headerLength;
private long m_bodyLength;
#region
int IBigUnfixedHeaderRequestInfo.HeaderLength => this.m_headerLength;
long IBigUnfixedHeaderRequestInfo.BodyLength => this.m_bodyLength;
@@ -138,26 +163,38 @@ internal class MyBigUnfixedHeaderRequestInfo : IBigUnfixedHeaderRequestInfo
return false;
}
bool IBigUnfixedHeaderRequestInfo.OnParsingHeader<TByteBlock>(ref TByteBlock byteBlock)
bool IBigUnfixedHeaderRequestInfo.OnParsingHeader<TReader>(ref TReader reader)
{
if (byteBlock.CanReadLength < 3)//判断可读数据是否满足一定长度
//在使用不固定包头解析时
//【首先】需要先解析包头
if (reader.BytesRemaining < 4)
{
//即直接缓存
return false;
}
var pos = byteBlock.Position;//可以先记录游标位置,当解析不能进行时回退游标
//【然后】先获取4字节包头
var header = reader.GetSpan(4);
//在该示例中第一个字节表示后续的所有数据长度但是header设置的是3所以后续还应当接收length-2个长度。
this.m_bodyLength = byteBlock.ReadByte() - 2;
this.DataType = byteBlock.ReadByte();
this.OrderType = byteBlock.ReadByte();
reader.Advance(4); //推进游标到包头结束位置
//【然后】解析包头和BodyLength
//获取指令类型
this.OrderType = header[0];
//获取数据类型
this.DataType = header[1];
var payloadLength = TouchSocketBitConverter.BigEndian.To<ushort>(header.Slice(2, 2));
//当执行到这里时byteBlock.Position已经递增了3个长度。
//所以无需再其他操作如果是其他则需要手动移动byteBlock.Position到指定位置。
//【最后】对HeaderLength做有效赋值
this.m_headerLength = 4;
this.m_bodyLength = payloadLength + 2;
this.m_headerLength = 3;//表示Header消耗了3个字节实际上可以省略这一行但是为了性能最好加上
return true;
}
#endregion
}
#endregion

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
@@ -48,6 +60,7 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region
service.Received = (client, e) =>
{
//从客户端收到信息
@@ -58,7 +71,7 @@ internal class Program
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
.SetTcpDataHandlingAdapter(() => new MyCustomCountSpliterDataHandlingAdapter())
@@ -76,16 +89,8 @@ internal class Program
}
}
internal class MyCountSpliterRequestInfo : IRequestInfo
{
public string Data { get; private set; }
public MyCountSpliterRequestInfo(string data)
{
this.Data = data;
}
}
#region
internal class MyCustomCountSpliterDataHandlingAdapter : CustomCountSpliterDataHandlingAdapter<MyCountSpliterRequestInfo>
{
public MyCustomCountSpliterDataHandlingAdapter() : base(8, Encoding.UTF8.GetBytes("#"))
@@ -97,3 +102,14 @@ internal class MyCustomCountSpliterDataHandlingAdapter : CustomCountSpliterDataH
return new MyCountSpliterRequestInfo(dataSpan.ToString(Encoding.UTF8));
}
}
internal class MyCountSpliterRequestInfo : IRequestInfo
{
public string Data { get; private set; }
public MyCountSpliterRequestInfo(string data)
{
this.Data = data;
}
}
#endregion

View File

@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -29,23 +29,28 @@ internal class Program
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
var myRequestInfo = new MyFixedHeaderRequestInfo()
var myRequestInfo = new MyDataClass()
{
Body = Encoding.UTF8.GetBytes("hello"),
Data = Encoding.UTF8.GetBytes("hello"),
DataType = (byte)i,
OrderType = (byte)i
};
//构建发送数据
using (var byteBlock = new ByteBlock(1024))
var byteBlock = new ByteBlock(1024);
try
{
byteBlock.WriteByte((byte)(myRequestInfo.Body.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
byteBlock.WriteByte(myRequestInfo.DataType);//然后数据类型
byteBlock.WriteByte(myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Body);//再写数据
WriterExtension.WriteValue(ref byteBlock, (byte)(myRequestInfo.Data.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.DataType);//然后数据类型
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Data);//再写数据
await client.SendAsync(byteBlock.Memory);
}
finally
{
byteBlock.Dispose();
}
}
}
}
@@ -70,16 +75,18 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region
service.Received = (client, e) =>
{
//从客户端收到信息
if (e.RequestInfo is MyFixedHeaderRequestInfo myRequest)
if (e.RequestInfo is MyDataClass myRequest)
{
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Body)}");
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Data)}");
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
@@ -97,30 +104,34 @@ internal class Program
return service;
}
}
public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyFixedHeaderRequestInfo>
#region {13,46-61,63-79}
/// <summary>
/// 第1个字节表示指令类型
/// 第2字节表示数据类型
/// 第3字节表示后续数据的长度。使用ushort(大端)表示最大长度为65535
/// 后续字节表示载荷数据
/// 最后2字节表示CRC16校验码
/// </summary>
public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyDataClass>
{
/// <summary>
/// 接口实现,指示固定包头长度
/// </summary>
public override int HeaderLength => 3;
public override int HeaderLength => 4;
/// <summary>
/// 获取新实例
/// </summary>
/// <returns></returns>
protected override MyFixedHeaderRequestInfo GetInstance()
protected override MyDataClass GetInstance()
{
return new MyFixedHeaderRequestInfo();
return new MyDataClass();
}
}
public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo
public class MyDataClass : IFixedHeaderRequestInfo
{
/// <summary>
/// 接口实现,标识数据长度
/// </summary>
public int BodyLength { get; private set; }
private int m_length;
/// <summary>
/// 自定义属性,标识数据类型
@@ -135,24 +146,43 @@ public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo
/// <summary>
/// 自定义属性,标识实际数据
/// </summary>
public byte[] Body { get; set; }
public byte[] Data { get; set; }
public bool OnParsingBody(ReadOnlySpan<byte> body)
int IFixedHeaderRequestInfo.BodyLength => this.m_length;
bool IFixedHeaderRequestInfo.OnParsingBody(ReadOnlySpan<byte> body)
{
if (body.Length == this.BodyLength)
var data = body.Slice(0, body.Length - 2);//最后2个字节是CRC16校验码
var crc16 = TouchSocketBitConverter.BigEndian.To<ushort>(body.Slice(body.Length - 2, 2));
//计算CRC16
var newCrc16 = Crc.Crc16Value(data);
if (crc16 != newCrc16)
{
this.Body = body.ToArray();
//CRC校验失败
throw new Exception("CRC校验失败");
}
this.Data = data.ToArray();
return true;
}
return false;
}
public bool OnParsingHeader(ReadOnlySpan<byte> header)
bool IFixedHeaderRequestInfo.OnParsingHeader(ReadOnlySpan<byte> header)
{
//在该示例中第一个字节表示后续的所有数据长度但是header设置的是3所以后续还应当接收length-2个长度。
this.BodyLength = header[0] - 2;
//这里header长度已经经过验证一定是4字节
//获取指令类型
this.OrderType = header[0];
//获取数据类型
this.DataType = header[1];
this.OrderType = header[2];
var payloadLength = TouchSocketBitConverter.BigEndian.To<ushort>(header.Slice(2, 2));
this.m_length = payloadLength + 2;//+2是因为还包含Crc16的长度
return true;
}
}
#endregion

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
@@ -48,6 +60,7 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region Json适配器
service.Received = (client, e) =>
{
//从客户端收到信息
@@ -58,6 +71,7 @@ internal class Program
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
@@ -76,6 +90,19 @@ internal class Program
}
}
#region Json适配器
internal class MyCustomJsonDataHandlingAdapter : CustomJsonDataHandlingAdapter<MyJsonClass>
{
public MyCustomJsonDataHandlingAdapter() : base(Encoding.UTF8)
{
}
protected override MyJsonClass GetInstance(JsonPackageKind packageKind, Encoding encoding, ReadOnlyMemory<byte> dataMemory, ReadOnlyMemory<byte> impurityMemory)
{
return new MyJsonClass(packageKind, encoding, dataMemory, impurityMemory);
}
}
internal class MyJsonClass : IRequestInfo
{
public MyJsonClass(JsonPackageKind packageKind, Encoding encoding, ReadOnlyMemory<byte> dataMemory, ReadOnlyMemory<byte> impurityMemory)
@@ -92,14 +119,4 @@ internal class MyJsonClass : IRequestInfo
public ReadOnlyMemory<byte> ImpurityMemory { get; }
}
internal class MyCustomJsonDataHandlingAdapter : CustomJsonDataHandlingAdapter<MyJsonClass>
{
public MyCustomJsonDataHandlingAdapter() : base(Encoding.UTF8)
{
}
protected override MyJsonClass GetInstance(JsonPackageKind packageKind, Encoding encoding, ReadOnlyMemory<byte> dataMemory, ReadOnlyMemory<byte> impurityMemory)
{
return new MyJsonClass(packageKind, encoding, dataMemory, impurityMemory);
}
}
#endregion

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
@@ -17,23 +29,28 @@ internal class Program
Console.ReadKey();
for (var i = 0; i < 10; i++)
{
var myRequestInfo = new MyUnfixedHeaderRequestInfo()
var myRequestInfo = new MyDataClass()
{
Body = Encoding.UTF8.GetBytes("hello"),
Data = Encoding.UTF8.GetBytes("hello"),
DataType = (byte)i,
OrderType = (byte)i
};
//构建发送数据
using (var byteBlock = new ByteBlock(1024))
var byteBlock = new ByteBlock(1024);
try
{
byteBlock.WriteByte((byte)(myRequestInfo.Body.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
byteBlock.WriteByte(myRequestInfo.DataType);//然后数据类型
byteBlock.WriteByte(myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Body);//再写数据
WriterExtension.WriteValue(ref byteBlock, (byte)(myRequestInfo.Data.Length + 2));//先写长度,因为该长度还包含数据类型和指令类型,所以+2
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.DataType);//然后数据类型
WriterExtension.WriteValue(ref byteBlock, myRequestInfo.OrderType);//然后指令类型
byteBlock.Write(myRequestInfo.Data);//再写数据
await client.SendAsync(byteBlock.Memory);
}
finally
{
byteBlock.Dispose();
}
}
}
}
@@ -58,16 +75,16 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region
service.Received = (client, e) =>
{
//从客户端收到信息
if (e.RequestInfo is MyUnfixedHeaderRequestInfo myRequest)
if (e.RequestInfo is MyDataClass myRequest)
{
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Body)}");
client.Logger.Info($"已从{client.Id}接收到DataType={myRequest.DataType},OrderType={myRequest.OrderType},消息={Encoding.UTF8.GetString(myRequest.Data)}");
}
return Task.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
@@ -86,15 +103,23 @@ internal class Program
}
}
public class MyUnfixedHeaderCustomDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter<MyUnfixedHeaderRequestInfo>
#region
/// <summary>
/// 第1个字节表示指令类型
/// 第2字节表示数据类型
/// 第3字节表示后续数据的长度。使用ushort(大端)表示最大长度为65535
/// 后续字节表示载荷数据
/// 最后2字节表示CRC16校验码
/// </summary>
public class MyUnfixedHeaderCustomDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter<MyDataClass>
{
protected override MyUnfixedHeaderRequestInfo GetInstance()
protected override MyDataClass GetInstance()
{
return new MyUnfixedHeaderRequestInfo();
return new MyDataClass();
}
}
public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo
public class MyDataClass : IUnfixedHeaderRequestInfo
{
/// <summary>
/// 接口实现,标识数据长度
@@ -114,53 +139,60 @@ public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo
/// <summary>
/// 自定义属性,标识实际数据
/// </summary>
public byte[] Body { get; set; }
public byte[] Data { get; set; }
public int HeaderLength { get; private set; }
public bool OnParsingBody(ReadOnlySpan<byte> body)
{
if (body.Length == this.BodyLength)
var data = body.Slice(0, body.Length - 2);//最后2个字节是CRC16校验码
var crc16 = TouchSocketBitConverter.BigEndian.To<ushort>(body.Slice(body.Length - 2, 2));
//计算CRC16
var newCrc16 = Crc.Crc16Value(data);
if (crc16 != newCrc16)
{
this.Body = body.ToArray();
//CRC校验失败
throw new Exception("CRC校验失败");
}
this.Data = data.ToArray();
return true;
}
return false;
}
public bool OnParsingHeader<TByteBlock>(ref TByteBlock byteBlock) where TByteBlock : IByteBlock
public bool OnParsingHeader<TReader>(ref TReader reader) where TReader : IBytesReader
{
//在使用不固定包头解析时
//【首先】需要先解析包头
if (byteBlock.CanReadLength < 3)
if (reader.BytesRemaining < 4)
{
//即直接缓存
return false;
}
//先保存一下初始游标,如果解析时还需要缓存,可能需要回退游标
var position = byteBlock.Position;
//【然后】先获取4字节包头
var header = reader.GetSpan(4);
//【然后】ReadToSpan会递增游标所以不需要再递增游标
var header = byteBlock.ReadToSpan(3);
//如果使用Span自行裁剪的话就需要手动递增游标
//var header=byteBlock.Span.Slice(position,3);
//byteBlock.Position += 3;
reader.Advance(4); //推进游标到包头结束位置
//【然后】解析包头和BodyLength
//在该示例中第一个字节表示后续的所有数据长度但是header设置的是3所以后续还应当接收length-2个长度。
this.BodyLength = header[0] - 2;
//获取指令类型
this.OrderType = header[0];
//获取数据类型
this.DataType = header[1];
this.OrderType = header[2];
var payloadLength = TouchSocketBitConverter.BigEndian.To<ushort>(header.Slice(2, 2));
//【最后】对HeaderLength做有效赋值
this.HeaderLength = 3;
this.HeaderLength = 4;
this.BodyLength = payloadLength + 2;
return true;
}
}
#endregion

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
@@ -42,9 +54,10 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region Json适配器按JsonPackage解析 {3-11}
service.Received = async (client, e) =>
{
//从客户端收到信息
if (e.RequestInfo is JsonPackage jsonPackage)
{
var sb = new StringBuilder();
@@ -54,11 +67,9 @@ internal class Program
sb.Append($"杂质数据:{jsonPackage.ImpurityData.Span.ToString(Encoding.UTF8)}");
client.Logger.Info(sb.ToString());
}
await e.InvokeNext();
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
.SetTcpDataHandlingAdapter(() => new JsonPackageAdapter(Encoding.UTF8))

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,163 @@
using Newtonsoft.Json;
using System.Text;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace MultipacketAdapterConsoleApp;
internal class Program
{
static async Task Main(string[] args)
{
var tcpService = await GetTcpService();
var tcpClient = await GetTcpClient();
while (true)
{
var input = Console.ReadLine();
if (input.HasValue())
{
if (input == "1")
{
await tcpClient.SendAsync(new MyPack1() { MyProperty1 = 10 });
}
else if (input == "2")
{
await tcpClient.SendAsync(new MyPack2() { MyProperty1 = "Hello World" });
}
else
{
throw new Exception("输入错误");
}
}
}
}
static async Task<TcpClient> GetTcpClient()
{
var tcpClient = new TcpClient();
await tcpClient.SetupAsync(new TouchSocketConfig()
.SetTcpDataHandlingAdapter(() => new MyAdapter())
.SetRemoteIPHost("tcp://127.0.0.1:7789"));
await tcpClient.ConnectAsync();
return tcpClient;
}
static async Task<TcpService> GetTcpService()
{
var service = new TcpService();
service.Received = async (client, e) =>
{
//从客户端收到信息
switch (e.RequestInfo)
{
case MyPack1 pack:
{
Console.WriteLine($"收到MyPack1MyProperty1={pack.MyProperty1}");
break;
}
case MyPack2 pack:
{
Console.WriteLine($"收到MyPack2MyProperty1={pack.MyProperty1}");
break;
}
default:
break;
}
await EasyTask.CompletedTask;
};
await service.SetupAsync(new TouchSocketConfig()
.SetListenIPHosts(7789)
.SetTcpDataHandlingAdapter(() => new MyAdapter()));
await service.StartAsync();//启动
return service;
}
}
class MyPackBase : IRequestInfo
{
}
class MyPack1 : MyPackBase
{
public int MyProperty1 { get; set; }
}
class MyPack2 : MyPackBase
{
public string? MyProperty1 { get; set; }
}
class MyAdapter : CustomDataHandlingAdapter<MyPackBase>
{
protected override FilterResult Filter<TReader>(ref TReader reader, bool beCached, ref MyPackBase request)
{
if (reader.BytesRemaining < 5)
{
return FilterResult.Cache;
}
var header = reader.GetSpan(5);
var type = header.ReadValue<byte>();
var length = header.ReadValue<int>(EndianType.Big);
if (reader.BytesRemaining < length + 5)
{
return FilterResult.Cache;
}
reader.Advance(5);
var body = reader.GetSpan(length);
var json = body.ToUtf8String();
switch (type)
{
case 1:
request = JsonConvert.DeserializeObject<MyPack1>(json);
break;
case 2:
request = JsonConvert.DeserializeObject<MyPack2>(json);
break;
default:
request = null;
break;
}
reader.Advance(length);
return FilterResult.Success;
}
public override bool CanSendRequestInfo => true;
public override void SendInput<TWriter>(ref TWriter writer, IRequestInfo requestInfo)
{
switch (requestInfo)
{
case MyPack1 pack1:
{
WriterExtension.WriteValue(ref writer, (byte)1);
var data = JsonConvert.SerializeObject(pack1);
WriterAnchor<TWriter> writerAnchor = new WriterAnchor<TWriter>(ref writer, 4);
WriterExtension.WriteNormalString(ref writer, data, Encoding.UTF8);
var span = writerAnchor.Rewind(ref writer, out var length);
span.WriteValue(length, EndianType.Big);
break;
}
case MyPack2 pack2:
{
WriterExtension.WriteValue(ref writer, (byte)2);
var data = JsonConvert.SerializeObject(pack2);
WriterAnchor<TWriter> writerAnchor = new WriterAnchor<TWriter>(ref writer, 4);
WriterExtension.WriteNormalString(ref writer, data, Encoding.UTF8);
var span = writerAnchor.Rewind(ref writer, out var length);
span.WriteValue(length, EndianType.Big);
break;
}
default:
break;
}
}
}

View File

@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -60,13 +60,16 @@ internal class Program
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
#region Memory解析 {3}
service.Received = (client, e) =>
{
//从客户端收到信息
var mes = e.ByteBlock.Span.ToString(Encoding.UTF8);//注意数据长度是byteBlock.Length
var mes = e.Memory.Span.ToString(Encoding.UTF8);//注意数据长度是byteBlock.Length
client.Logger.Info($"已从{client.Id}接收到信息:{mes}");
return EasyTask.CompletedTask;
};
#endregion
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
@@ -83,6 +86,33 @@ internal class Program
service.Logger.Info("服务器已启动");
return service;
}
private static void Test()
{
var config = new TouchSocketConfig();
#region
config.SetTcpDataHandlingAdapter(() => new FixedHeaderPackageAdapter() { FixedHeaderType = FixedHeaderType.Int });
#endregion
#region
config.SetTcpDataHandlingAdapter(() => new FixedSizePackageAdapter(10));
#endregion
#region
config.SetTcpDataHandlingAdapter(() => new TerminatorPackageAdapter("\r\n"));
#endregion
#region
config.SetTcpDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromMicroseconds(100) });
#endregion
#region Json适配器
config.SetTcpDataHandlingAdapter(() => new JsonPackageAdapter());
#endregion
}
}
internal class MyFixedSizePackageAdapter : FixedSizePackageAdapter
@@ -90,10 +120,4 @@ internal class MyFixedSizePackageAdapter : FixedSizePackageAdapter
public MyFixedSizePackageAdapter(int fixedSize) : base(fixedSize)
{
}
protected override Task PreviewSendAsync(ReadOnlyMemory<byte> memory)
{
//重写之后直接发送,当然也可以自己判断一些信息
return this.GoSendAsync(memory);
}
}

View File

@@ -0,0 +1,225 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using System;
using System.Text;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.NamedPipe;
using TouchSocket.SerialPorts;
using TouchSocket.Sockets;
namespace RawAdapterConsoleApp;
internal class Program
{
private static async Task Main(string[] args)
{
var service = await CreateService();
var client = await CreateClient();
ConsoleLogger.Default.Info("输入任意内容回车发送将会循环发送10次");
while (true)
{
var str = Console.ReadLine();
for (var i = 0; i < 10; i++)
{
await client.SendAsync(str);
}
}
}
private static async Task<TcpClient> CreateClient()
{
var client = new TcpClient();
//载入配置
await client.SetupAsync(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetTcpDataHandlingAdapter(() => new MyRawDataHandleAdapter())
.ConfigureContainer(a =>
{
a.AddConsoleLogger();//添加一个日志注入
}));
await client.ConnectAsync();//调用连接,当连接不成功时,会抛出异常。
client.Logger.Info("客户端成功连接");
return client;
}
private static async Task<TcpService> CreateService()
{
var service = new TcpService();
service.Received = (client, e) =>
{
//从客户端收到信息
var mes = e.Memory.Span.ToString(Encoding.UTF8);
client.Logger.Info($"已从{client.Id}接收到信息:{mes}");
return Task.CompletedTask;
};
await service.SetupAsync(new TouchSocketConfig()//载入配置
.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址
.SetTcpDataHandlingAdapter(() => new PeriodPackageAdapter() { CacheTimeout = TimeSpan.FromSeconds(1) })
.ConfigureContainer(a =>
{
a.AddConsoleLogger();//添加一个控制台日志注入注意在maui中控制台日志不可用
})
.ConfigurePlugins(a =>
{
//a.Add();//此处可以添加插件
}));
await service.StartAsync();//启动
service.Logger.Info("服务器已启动");
return service;
}
public static void Config()
{
var config = new TouchSocketConfig();
#region 使Tcp适配器
config.SetTcpDataHandlingAdapter(() => new TerminatorPackageAdapter("\r\n"));
#endregion
#region 使NamedPipe适配器
config.SetNamedPipeDataHandlingAdapter(() => new TerminatorPackageAdapter("\r\n"));
#endregion
#region 使Serial适配器
config.SetSerialDataHandlingAdapter(() => new TerminatorPackageAdapter("\r\n"));
#endregion
}
}
#region 使
/// <summary>
/// 第1个字节表示指令类型
/// 第2字节表示数据类型
/// 第3字节表示后续数据的长度。使用ushort(大端)表示最大长度为65535
/// 后续字节表示载荷数据
/// 最后2字节表示CRC16校验码
/// </summary>
internal class MyRawDataHandleAdapter : SingleStreamDataHandlingAdapter
{
private MyDataClass m_myDataClass;
private int m_payloadLength;
protected override async Task PreviewReceivedAsync<TReader>(TReader reader)
{
while (reader.BytesRemaining > 0)
{
if (this.m_myDataClass == null)
{
//首次接收该解析对象
if (reader.BytesRemaining < 4)
{
//如果剩余数据小于4个字节则继续等待
return;
}
//读取前4个字节
var header = reader.GetSpan(4);
//推进已读取的4个字节
reader.Advance(4);
//获取指令类型
var orderType = header[0];
//获取数据类型
var dataType = header[1];
//创建数据对象
this.m_myDataClass = new MyDataClass()
{
OrderType = orderType,
DataType = dataType
};
//获取载荷长度
this.m_payloadLength = TouchSocketBitConverter.BigEndian.To<ushort>(header.Slice(2, 2));
await this.ParseData(reader);
}
else
{
//已经读取过头部,继续读取剩余数据
await this.ParseData(reader);
}
}
}
private async Task ParseData<TReader>(TReader reader)
where TReader : class, IBytesReader
{
//判断剩余数据是否足够,+2是因为最后2个字节是CRC16校验码
if (reader.BytesRemaining < this.m_payloadLength + 2)
{
return;
}
//读取数据
var data = reader.GetSpan(this.m_payloadLength);
reader.Advance(this.m_payloadLength);
//读取CRC16校验码
var crcData = reader.GetSpan(2);
reader.Advance(2);
//转换CRC16校验码为ushort相比于byte[],更节省内存
var crc16 = TouchSocketBitConverter.BigEndian.To<ushort>(crcData);
//计算CRC16
var newCrc16 = Crc.Crc16Value(data);
if (crc16 != newCrc16)
{
//CRC校验失败
throw new Exception("CRC校验失败");
}
//保存数据
this.m_myDataClass.Data = data.ToArray();
//至此,数据接收完成,可以进行投递处理
//此处可以选择投递方式此处选择了使用IRequestInfo投递
await base.GoReceivedAsync(ReadOnlyMemory<byte>.Empty, this.m_myDataClass);
//清空数据,准备下次接收
this.m_myDataClass = null;
this.m_payloadLength = 0;
}
}
/// <summary>
/// 定义数据对象
/// </summary>
internal class MyDataClass : IRequestInfo
{
public byte OrderType { get; set; }
public byte DataType { get; set; }
public byte[] Data { get; set; }
}
#endregion
#region Tcp客户端直接设置适配器 {6}
internal class MyTcpClient : TcpClient
{
protected override Task OnTcpConnecting(ConnectingEventArgs e)
{
//直接设置适配器到当前客户端
base.SetAdapter(new TerminatorPackageAdapter("\r\n"));
return base.OnTcpConnecting(e);
}
}
#endregion

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.NamedPipe" />
<PackageReference Include="TouchSocket.SerialPorts" />
</ItemGroup>
</Project>

View File

@@ -1,201 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
namespace TLVWinFormsApp
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.button3 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.button4 = new System.Windows.Forms.Button();
this.button5 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(61, 54);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(150, 46);
this.button1.TabIndex = 0;
this.button1.Text = "启动服务器";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(249, 54);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(150, 46);
this.button2.TabIndex = 1;
this.button2.Text = "客户端连接";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// listBox1
//
this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listBox1.FormattingEnabled = true;
this.listBox1.ItemHeight = 31;
this.listBox1.Location = new System.Drawing.Point(12, 160);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(1363, 283);
this.listBox1.TabIndex = 2;
//
// button3
//
this.button3.Location = new System.Drawing.Point(1015, 54);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(150, 46);
this.button3.TabIndex = 3;
this.button3.Text = "发送";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(493, 62);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(56, 31);
this.label1.TabIndex = 4;
this.label1.Text = "Tag";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(671, 62);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(78, 31);
this.label2.TabIndex = 5;
this.label2.Text = "Value";
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(770, 59);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(200, 38);
this.textBox1.TabIndex = 6;
//
// numericUpDown1
//
this.numericUpDown1.Location = new System.Drawing.Point(555, 60);
this.numericUpDown1.Maximum = new decimal(new int[] {
65535,
0,
0,
0});
this.numericUpDown1.Minimum = new decimal(new int[] {
10,
0,
0,
0});
this.numericUpDown1.Name = "numericUpDown1";
this.numericUpDown1.Size = new System.Drawing.Size(95, 38);
this.numericUpDown1.TabIndex = 7;
this.numericUpDown1.Value = new decimal(new int[] {
10,
0,
0,
0});
//
// button4
//
this.button4.Location = new System.Drawing.Point(1187, 54);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(150, 46);
this.button4.TabIndex = 8;
this.button4.Text = "Ping";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// button5
//
this.button5.Location = new System.Drawing.Point(1015, 108);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(150, 46);
this.button5.TabIndex = 9;
this.button5.Text = "连续发送";
this.button5.UseVisualStyleBackColor = true;
this.button5.Click += new System.EventHandler(this.button5_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(14F, 31F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1387, 450);
this.Controls.Add(this.button5);
this.Controls.Add(this.button4);
this.Controls.Add(this.numericUpDown1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.button3);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Button button1;
private Button button2;
private ListBox listBox1;
private Button button3;
private Label label1;
private Label label2;
private TextBox textBox1;
private NumericUpDown numericUpDown1;
private Button button4;
private Button button5;
}
}

View File

@@ -1,130 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using System.Text;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace TLVWinFormsApp;
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void ShowMsg(string msg)
{
this.listBox1.Items.Insert(0, msg);
}
private readonly TcpService m_tcpService = new TcpService();
private void button1_Click(object sender, EventArgs e)
{
//<2F><><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD><D5B5><EFBFBD>Ϣ<EFBFBD>¼<EFBFBD>
this.m_tcpService.Received = (client, e) =>
{
if (e.RequestInfo is TLVDataFrame frame)
{
client.Logger.Info($"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD>,Tag={frame.Tag},Length={frame.Length},Value={(frame.Value != null ? Encoding.UTF8.GetString(frame.Value) : string.Empty)}");
}
return EasyTask.CompletedTask;
};
var config = new TouchSocketConfig();
config.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.AddEasyLogger(this.ShowMsg);
})
.ConfigurePlugins(a =>
{
a.Add<TLVPlugin>()//ʹ<>ò<EFBFBD><C3B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0B5B1><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӦPing<6E><67>
.SetLengthType(FixedHeaderType.Int);//<2F><><EFBFBD><EFBFBD>֧<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>SetMaxPackageSizeӰ<65>
});
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
this.m_tcpService.SetupAsync(config);
//<2F><><EFBFBD><EFBFBD>
this.m_tcpService.StartAsync();
this.m_tcpService.Logger.Info("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD><C9B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
}
private readonly TcpClient m_client = new TcpClient();
private void button2_Click(object sender, EventArgs e)
{
this.m_client.SetupAsync(new TouchSocketConfig()
.SetAdapterOption(new AdapterOption()
{
MaxPackageSize = 1024 * 1024 * 10
})
.ConfigureContainer(a =>
{
a.AddEasyLogger(this.ShowMsg);
})
//.SetDataHandlingAdapter(() => new TLVDataHandlingAdapter(FixedHeaderType.Int, verifyFunc: null))//<2F><><EFBFBD>ʹ<EFBFBD><CAB9>TLVPlugin<69><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˲<EFBFBD><CBB2><EFBFBD><EFBFBD>ʡ<EFBFBD>ԡ<EFBFBD>
.ConfigurePlugins(a =>
{
a.Add<TLVPlugin>()//ʹ<>ò<EFBFBD><C3B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0B5B1><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӦPing<6E><67>
.SetLengthType(FixedHeaderType.Int);//<2F><><EFBFBD><EFBFBD>֧<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>SetMaxPackageSizeӰ<65>
})
.SetRemoteIPHost(new IPHost("127.0.0.1:7789")));
this.m_client.ConnectAsync();
this.m_client.Logger.Info("<22><><EFBFBD>ӳɹ<D3B3>");
}
private async void button3_Click(object sender, EventArgs e)
{
try
{
await this.m_client?.SendAsync(new ValueTLVDataFrame((ushort)this.numericUpDown1.Value, Encoding.UTF8.GetBytes(this.textBox1.Text)));
}
catch (Exception ex)
{
this.m_client.Logger.Exception(ex);
}
}
private void button4_Click(object sender, EventArgs e)
{
try
{
this.m_client.Logger.Info($"ping={this.m_client?.PingWithTLV()}");
}
catch (Exception ex)
{
this.m_client.Logger.Exception(ex);
}
}
private async void button5_Click(object sender, EventArgs e)
{
for (var i = 0; i < 100; i++)
{
try
{
await this.m_client?.SendAsync(new ValueTLVDataFrame((ushort)this.numericUpDown1.Value, Encoding.UTF8.GetBytes(i.ToString())));
}
catch (Exception ex)
{
this.m_client?.Logger.Exception(ex);
}
}
}
}

View File

@@ -1,60 +0,0 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -1,37 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using TouchSocket.Core;
namespace TLVWinFormsApp;
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
try
{
Enterprise.ForTest();
}
catch
{
}
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}

View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
<Project Sdk="Microsoft.NET.Sdk.WebAssembly">
<PropertyGroup>
<TargetFramework>net8.0-browser</TargetFramework>
<OutputType>Exe</OutputType>
@@ -6,7 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Browser" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Browser" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,4 @@
using System.Runtime.Versioning;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Avalonia;

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<!--If you are willing to use Windows/MacOS native APIs you will need to create 3 projects.
@@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Desktop" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Avalonia;

View File

@@ -1,4 +1,4 @@
using Avalonia;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
@@ -11,10 +11,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="$(AvaloniaVersion)" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.Themes.Fluent" />
<PackageReference Include="Avalonia.Fonts.Inter" />
<PackageReference Include="CommunityToolkit.Mvvm" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />

View File

@@ -1,4 +1,4 @@
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Diagnostics;
using System.Runtime.Intrinsics.Arm;

View File

@@ -1,4 +1,4 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
namespace AvaloniaApplication.ViewModels;

View File

@@ -1,4 +1,4 @@
using Avalonia.Controls;
using Avalonia.Controls;
namespace AvaloniaApplication.Views;

View File

@@ -1,4 +1,4 @@
using Avalonia.Controls;
using Avalonia.Controls;
namespace AvaloniaApplication.Views;

View File

@@ -1,3 +1,3 @@
using TouchSocket.Rpc;
using TouchSocket.Rpc;
[assembly: GeneratorRpcServerRegister]

View File

@@ -1,4 +1,4 @@
using TouchSocket.Core;
using TouchSocket.Core;
namespace WebServerApplication.Plugins
{

View File

@@ -33,7 +33,7 @@ namespace WebServerApplication
.ConfigurePlugins(a =>
{
a.UseDmtpRpc();
//<2F><><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>
//<2F><>Ӳ<EFBFBD><EFBFBD>
a.Add<MyDmtpPlugin>();
});
});
@@ -41,7 +41,7 @@ namespace WebServerApplication
var app = builder.Build();
app.UseWebSockets();
app.UseWebSocketDmtp("/WebSocketDmtp");//WebSocketDmtp<74><70><EFBFBD><EFBFBD><EFBFBD><EFBFBD>UseWebSockets֮<73><D6AE>ʹ<EFBFBD>á<EFBFBD>
app.UseWebSocketDmtp("/WebSocketDmtp");//WebSocketDmtp<74><70><EFBFBD><EFBFBD><EFBFBD><EFBFBD>UseWebSockets֮<73><D6AE>ʹ<EFBFBD>á<EFBFBD>
app.Run("http://localhost:5043");
}

View File

@@ -1,4 +1,4 @@
using RpcLibrary.Shared.RpcServers;
using RpcLibrary.Shared.RpcServers;
using System.ComponentModel;
using TouchSocket.Dmtp.Rpc;
using TouchSocket.Rpc;

View File

@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.AspNetCore" Version="2.1.5" />
<PackageReference Include="TouchSocket.AspNetCore" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
@@ -7,7 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.Dmtp" Version="2.1.5" />
<PackageReference Include="TouchSocket.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

View File

@@ -8,12 +8,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -28,7 +28,7 @@ internal class Program
service.Received = (client, e) =>
{
//从客户端收到信息
var mes = e.ByteBlock.Span.ToString(Encoding.UTF8);
var mes = e.Memory.Span.ToString(Encoding.UTF8);
client.Logger.Info($"已从{client.Id}接收到信息:{mes}");
return Task.CompletedTask;
};

View File

@@ -8,12 +8,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -88,7 +88,7 @@ internal class DifferentProtocolPlugin : PluginBase, ITcpConnectingPlugin, ITcpR
if (client is ITcpSessionClient sessionClient)
{
sessionClient.Logger.Info($"{sessionClient.GetIPPort()}收到数据,服务器端口:{sessionClient.ServicePort},数据:{e.ByteBlock}");
sessionClient.Logger.Info($"{sessionClient.GetIPPort()}收到数据,服务器端口:{sessionClient.ServicePort},数据:{e.Memory}");
}
await e.InvokeNext();

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -6,6 +6,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -131,8 +131,8 @@ internal class MyRequestInfo : IFixedHeaderRequestInfo
public void Package(ByteBlock byteBlock)
{
byteBlock.WriteUInt16((ushort)((this.Data == null ? 0 : this.Data.Length) + 1));
byteBlock.WriteByte((byte)this.DataType);
WriterExtension.WriteValue(ref byteBlock, (ushort)((this.Data == null ? 0 : this.Data.Length) + 1));
WriterExtension.WriteValue(ref byteBlock, (byte)this.DataType);
if (this.Data != null)
{
byteBlock.Write(this.Data);
@@ -141,7 +141,7 @@ internal class MyRequestInfo : IFixedHeaderRequestInfo
public byte[] PackageAsBytes()
{
using var byteBlock = new ByteBlock(1024*64);
using var byteBlock = new ByteBlock(1024 * 64);
this.Package(byteBlock);
return byteBlock.ToArray();
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -6,12 +6,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -31,7 +31,7 @@ internal class Program
service.Received = (client, e) =>
{
//从客户端收到信息
var mes = e.ByteBlock.Span.ToString(Encoding.UTF8);
var mes = e.Memory.Span.ToString(Encoding.UTF8);
client.Logger.Info($"已从{client.Id}接收到信息:{mes}");
return EasyTask.CompletedTask;
};
@@ -87,9 +87,9 @@ public class MyThrottlingPlugin : PluginBase, ITcpConnectedPlugin, ITcpReceiving
return e.InvokeNext();
}
public async Task OnTcpReceiving(ITcpSession client, ByteBlockEventArgs e)
public async Task OnTcpReceiving(ITcpSession client, BytesReaderEventArgs e)
{
await client.GetFlowGate().AddCheckWaitAsync(e.ByteBlock.Length);
await client.GetFlowGate().AddCheckWaitAsync(e.Reader.Sequence.Length);
await e.InvokeNext();
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -6,12 +6,12 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -92,7 +92,7 @@ internal class Program
// protected override void OnReceivingData(ITcpSession client, ByteBlockEventArgs e)
// {
// client.SetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty,
// e.ByteBlock.Length + +client.GetValue<int>(TrafficCounterEx.ReceivedTempTrafficCounterProperty));
// e.Memory.Length + +client.GetValue<int>(TrafficCounterEx.ReceivedTempTrafficCounterProperty));
// base.OnReceivingData(client, e);
// }
//}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -6,11 +6,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -6,13 +6,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Consul" Version="1.7.14.7" />
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="Consul" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -46,7 +46,7 @@ internal class Program
{
//从客户端收到信息
var mes = e.ByteBlock.Span.ToString(Encoding.UTF8);
var mes = e.Memory.Span.ToString(Encoding.UTF8);
client.Logger.Info($"已从{client.Id}接收到信息:{mes}");
//client.Send(mes);//将收到的信息直接返回给发送方

View File

@@ -48,11 +48,16 @@ internal class Program
.ConfigurePlugins(a =>
{
a.UseDmtpRpc();
a.UseXmlRpc().SetXmlRpcUrl("/xmlrpc");
a.UseXmlRpc("/xmlrpc");
a.UseWebApi();
a.UseWebSocket()//添加WebSocket功能
.SetWSUrl("/ws");
//添加WebSocket功能
a.UseWebSocket(options =>
{
options.SetUrl("/ws");//设置url直接可以连接。
options.SetAutoPong(true);//当收到ping报文时自动回应pong
});
a.Add<MyWebSocketPlug>();//添加WebSocket业务数据接收插件
a.Add<MyWebSocketCommand>();//添加WebSocket快捷实现常规WS客户端发送文本“Add 10 20”即可得到30。
})
@@ -149,9 +154,9 @@ internal class MyWebSocketCommand : WebSocketCommandLinePlugin
/// <summary>
/// WS收到数据等业务。
/// </summary>
internal class MyWebSocketPlug : PluginBase, IWebSocketHandshakedPlugin, IWebSocketReceivedPlugin
internal class MyWebSocketPlug : PluginBase, IWebSocketConnectedPlugin, IWebSocketReceivedPlugin
{
public async Task OnWebSocketHandshaked(IWebSocket client, HttpContextEventArgs e)
public async Task OnWebSocketConnected(IWebSocket client, HttpContextEventArgs e)
{
if (client.Client is IHttpSessionClient socketClient)
{

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -6,13 +6,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Consul" Version="1.7.14.7" />
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="Consul" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -13,7 +13,6 @@
using Consul;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using TouchSocket.Core;
using TouchSocket.Dmtp;

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
@@ -7,13 +7,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Consul" Version="1.7.14.7" />
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="Consul" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -13,6 +13,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.Core" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core" />
</ItemGroup>
</Project>

View File

@@ -11,295 +11,346 @@
// ------------------------------------------------------------------------------
using System.Diagnostics;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using TouchSocket.Core;
namespace AotDynamicMethodConsoleApp;
internal class Program
{
static async Task Main(string[] args)
private const int DefaultPerformanceTestCount = 10_000_000;
private static async Task Main(string[] args)
{
var consoleAction = new ConsoleAction();
consoleAction.OnException += ConsoleAction_OnException;
consoleAction.Add("1", "简单调用", SimpleRun);
consoleAction.Add("2", "IL调用", ILRun);
consoleAction.Add("3", "表达式树调用", ExpressionRun);
consoleAction.Add("4", "反射调用", ReflectRun);
consoleAction.Add("5", "源生成调用", SourceGeneratorRun);
consoleAction.Add("6", "性能测试", Performance);
consoleAction.Add("7", "多参数调用", MultiParameters);
consoleAction.Add("8", "自定义动态调用", CustomDynamicMethod);
consoleAction.Add("9", "TaskRun", TaskRun);
consoleAction.Add("10", "TaskObjectRun", TaskObjectRun);
consoleAction.OnException += OnException;
// 注册所有示例命令
RegisterCommands(consoleAction);
consoleAction.ShowAll();
await consoleAction.RunCommandLineAsync();
}
private static void ConsoleAction_OnException(Exception ex)
/// <summary>
/// 注册所有示例命令
/// </summary>
private static void RegisterCommands(ConsoleAction consoleAction)
{
Console.WriteLine(ex.Message);
consoleAction.Add("1", "简单调用", SimpleRun);
consoleAction.Add("2", "性能测试", Performance);
consoleAction.Add("3", "多参数调用", MultiParameters);
consoleAction.Add("4", "自定义动态调用", CustomDynamicMethod);
consoleAction.Add("5", "异步Task调用", TaskRun);
consoleAction.Add("6", "异步Task<T>调用", TaskObjectRun);
}
static void SimpleRun()
/// <summary>
/// 全局异常处理
/// </summary>
private static void OnException(Exception ex)
{
Method method = new Method(typeof(MyClass), nameof(MyClass.Run));
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"错误: {ex.Message}");
Console.ResetColor();
}
MyClass myClass = new MyClass();
/// <summary>
/// 示例1: 简单的方法调用
/// </summary>
private static void SimpleRun()
{
Console.WriteLine("=== 简单调用示例 ===");
#region
var method = new Method(typeof(MyClass), nameof(MyClass.Run));
var instance = new MyClass();
method.Invoke(instance);
#endregion
Console.WriteLine("调用完成!");
}
/// <summary>
/// 示例2: 性能测试
/// </summary>
private static void Performance()
{
Console.WriteLine("=== 性能测试 ===");
Console.WriteLine($"将执行 {DefaultPerformanceTestCount:N0} 次方法调用...\n");
#region
var myClass = new MyClass();
var method = new Method(typeof(MyClass), nameof(MyClass.Performance));
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < 10_000_000; i++)
{
method.Invoke(myClass);
}
static void ILRun()
{
Method method = new Method(typeof(MyClass), nameof(MyClass.Run), DynamicBuilderType.IL);
stopwatch.Stop();
Console.WriteLine($"总耗时: {stopwatch.ElapsedMilliseconds} ms");
#endregion
MyClass myClass = new MyClass();
method.Invoke(myClass);
}
static void ExpressionRun()
{
Method method = new Method(typeof(MyClass), nameof(MyClass.Run), DynamicBuilderType.Expression);
MyClass myClass = new MyClass();
method.Invoke(myClass);
}
static void ReflectRun()
{
Method method = new Method(typeof(MyClass), nameof(MyClass.Run), DynamicBuilderType.Reflect);
MyClass myClass = new MyClass();
method.Invoke(myClass);
}
static void SourceGeneratorRun()
{
Method method = new Method(typeof(MyClass), nameof(MyClass.Run), DynamicBuilderType.SourceGenerator);
MyClass myClass = new MyClass();
method.Invoke(myClass);
}
static void Performance()
{
int count = 10000000;
MyClass myClass = new MyClass();
Stopwatch stopwatch = new Stopwatch();
var methods = GetMethods(typeof(MyClass), nameof(MyClass.Performance));
foreach (var item in methods)
{
stopwatch.Restart();
try
{
var method = item;
for (int i = 0; i < count; i++)
{
method.Invoke(myClass);
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"✓ 执行完成");
Console.WriteLine($" 总耗时: {stopwatch.ElapsedMilliseconds:N0} ms");
Console.WriteLine($" 平均耗时: {(double)stopwatch.ElapsedMilliseconds / DefaultPerformanceTestCount:F6} ms/call");
Console.WriteLine($" 吞吐量: {DefaultPerformanceTestCount / (stopwatch.ElapsedMilliseconds / 1000.0):N0} calls/sec");
Console.ResetColor();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
stopwatch.Stop();
Console.WriteLine($"Method BuilderType={item.DynamicBuilderType},Time={stopwatch.ElapsedMilliseconds}");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"✗ 性能测试失败: {ex.Message}");
Console.WriteLine($" 已完成部分测试,耗时: {stopwatch.ElapsedMilliseconds:N0} ms");
Console.ResetColor();
}
}
}
static void MultiParameters()
/// <summary>
/// 示例3: 多参数调用,包括 out 和 ref 参数
/// </summary>
private static void MultiParameters()
{
MyClass myClass = new MyClass();
Console.WriteLine("=== 多参数调用示例 ===");
var methods = GetMethods(typeof(MyClass), nameof(MyClass.MultiParameters));
#region out和ref参数调用
var method = new Method(typeof(MyClass), nameof(MyClass.MultiParameters));
var instance = new MyClass();
var parameters = new object[] { "hello", 0, 200 };
method.Invoke(instance, parameters);
Console.WriteLine($"out参数b={parameters[1]}"); // 输出: out参数b=10
Console.WriteLine($"ref参数c={parameters[2]}"); // 输出: ref参数c=201
#endregion
Console.WriteLine($"调用前参数: a=\"{parameters[0]}\", b={parameters[1]}, c={parameters[2]}");
foreach (var item in methods)
{
object[] ps = new object[] { "hello", 0, 200 };
try
{
var method = item;
method.Invoke(myClass, ps);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"调用后参数: a=\"{parameters[0]}\", b={parameters[1]}, c={parameters[2]}");
Console.ResetColor();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"调用失败: {ex.Message}");
Console.ResetColor();
}
finally
}
/// <summary>
/// 示例4: 使用自定义特性的动态方法调用
/// </summary>
private static void CustomDynamicMethod()
{
Console.WriteLine($"Method BuilderType={item.DynamicBuilderType},ps0={ps[0]},ps1={ps[1]},ps2={ps[2]}");
}
}
Console.WriteLine("=== 自定义动态方法调用示例 ===");
}
#region
var method = new Method(typeof(MyClass), nameof(MyClass.CustomDynamicMethod));
var instance = new MyClass();
method.Invoke(instance);
#endregion
static void CustomDynamicMethod()
{
MyClass myClass = new MyClass();
var methods = GetMethods(typeof(MyClass), nameof(MyClass.CustomDynamicMethod));
foreach (var item in methods)
{
try
{
var method = item;
method.Invoke(myClass);
Console.WriteLine("自定义动态方法调用成功!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine($"Method BuilderType={item.DynamicBuilderType}");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"调用失败: {ex.Message}");
Console.ResetColor();
}
}
}
static async Task TaskRun()
/// <summary>
/// 示例5: 异步 Task 方法调用
/// </summary>
private static async Task TaskRun()
{
MyClass myClass = new MyClass();
Console.WriteLine("=== 异步Task调用示例 ===");
var methods = GetMethods(typeof(MyClass), nameof(MyClass.TaskRun));
#region Task调用
var method = new Method(typeof(MyClass), nameof(MyClass.TaskRun));
var instance = new MyClass();
foreach (var item in methods)
{
try
{
var method = item;
// 判断是否为异步方法
if (method.IsAwaitable)
{
await method.InvokeAsync(myClass);
await method.InvokeAsync(instance);
}
#endregion
Console.WriteLine($"方法是否可等待: {method.IsAwaitable}");
Console.WriteLine($"返回类型: {method.ReturnKind}");
try
{
if (method.IsAwaitable)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("异步调用完成!");
Console.ResetColor();
}
else
{
Console.WriteLine("该方法不是异步方法");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine($"Method BuilderType={item.DynamicBuilderType}");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"异步调用失败: {ex.Message}");
Console.ResetColor();
}
}
}
static async Task TaskObjectRun()
/// <summary>
/// 示例6: 异步 Task<T> 方法调用(带返回值)
/// </summary>
private static async Task TaskObjectRun()
{
MyClass myClass = new MyClass();
Console.WriteLine("=== 异步Task<T>调用示例 ===");
var methods = GetMethods(typeof(MyClass), nameof(MyClass.TaskObjectRun));
#region Task泛型调用
var method = new Method(typeof(MyClass), nameof(MyClass.TaskObjectRun));
var instance = new MyClass();
foreach (var item in methods)
{
try
{
var method = item;
if (method.ReturnKind == MethodReturnKind.AwaitableObject)
{
var result = await method.InvokeAsync(myClass);
Console.WriteLine($"result={result}");
var result = await method.InvokeAsync(instance);
Console.WriteLine($"返回值: {result}"); // 输出: 返回值: 10
}
#endregion
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine($"Method BuilderType={item.DynamicBuilderType}");
}
}
Console.WriteLine($"方法返回类型: {method.ReturnKind}");
Console.WriteLine($"实际返回值类型: {method.RealReturnType?.Name ?? "void"}");
}
static List<Method> GetMethods(Type type, string name)
{
var methods = new List<Method>();
foreach (var item in Enum.GetValues(typeof(DynamicBuilderType)).OfType<DynamicBuilderType>())
{
try
{
methods.Add(new Method(type, name, item));
if (method.ReturnKind == MethodReturnKind.AwaitableObject)
{
var result2 = await method.InvokeAsync(instance);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"异步调用完成,返回值: {result2}");
Console.ResetColor();
}
else
{
Console.WriteLine("该方法不返回异步对象");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"异步调用失败: {ex.Message}");
Console.ResetColor();
}
}
return methods;
}
static bool IsDynamicCodeCompiled()
{
#if NET8_0_OR_GREATER
return RuntimeFeature.IsDynamicCodeCompiled;
#else
return true;
#endif
}
}
/// <summary>
/// 测试类,包含各种类型的动态方法
/// </summary>
#region
public class MyClass
{
/// <summary>
/// 简单的void方法
/// </summary>
[DynamicMethod]
public void Run()
{
Console.WriteLine("Run");
Console.WriteLine("Run 方法被调用");
}
#endregion
/// <summary>
/// 用于性能测试的空方法
/// </summary>
#region
[DynamicMethod]
public void Performance()
{
// 空方法体,用于性能测试
}
#endregion
/// <summary>
/// 包含多种参数类型的方法普通参数、out参数、ref参数
/// </summary>
#region out和ref参数声明
[DynamicMethod]
public void MultiParameters(string a, out int b, ref int c)
{
b = 10;
c = c + 1;
Console.WriteLine("MultiParameters");
Console.WriteLine($"a={a}, b={b}, c={c}");
}
#endregion
/// <summary>
/// 使用自定义特性标记的方法
/// </summary>
[MyDynamicMethod]
public void CustomDynamicMethod()
{
Console.WriteLine("CustomDynamicMethod");
Console.WriteLine("CustomDynamicMethod 方法被调用(使用自定义特性)");
}
/// <summary>
/// 异步Task方法无返回值
/// </summary>
#region Task调用声明
[DynamicMethod]
public async Task TaskRun()
{
Console.WriteLine("TaskRun");
await Task.CompletedTask;
Console.WriteLine("开始执行...");
await Task.Delay(100);
Console.WriteLine("执行完成");
}
#endregion
/// <summary>
/// 异步Task<T>方法(有返回值)
/// </summary>
#region Task泛型调用声明
[DynamicMethod]
public async Task<int> TaskObjectRun()
{
Console.WriteLine("TaskObjectRun");
await Task.CompletedTask;
await Task.Delay(100);
return 10;
}
#endregion
}
/// <summary>
/// 自定义的动态方法特性
/// </summary>
#region
[DynamicMethod]
[AttributeUsage(AttributeTargets.Method)]
public class MyDynamicMethodAttribute : Attribute
{
}
#endregion
#region Method实例推荐
/// <summary>
/// 推荐的缓存方式将Method实例缓存为静态字段避免重复创建
/// </summary>
public static class MethodCache
{
public static readonly Method RunMethod = new Method(typeof(MyClass), nameof(MyClass.Run));
// 使用示例:
// MethodCache.RunMethod.Invoke(instance);
}
#endregion

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.Core" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core" />
</ItemGroup>
<!--<ItemGroup>

View File

@@ -1,11 +1,22 @@
using System.Diagnostics;
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using TouchSocket.Core;
namespace FastBinaryFormatterConsoleApp
{
internal class Program
{
static void Main(string[] args)
private static void Main(string[] args)
{
//未完成
//SerializeConvert.AddFastBinary<Arg>();
@@ -17,7 +28,7 @@ namespace FastBinaryFormatterConsoleApp
//SerializeConvert.AddFastBinary<Dictionary<string,string>>();
//SerializeConvert.AddFastBinary<Dictionary<int,Arg>>();
GlobalEnvironment.DynamicBuilderType = DynamicBuilderType.Reflect;
ShouldSerializeObjBeOk();
Console.ReadKey();
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.Core" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core" />
</ItemGroup>
</Project>

View File

@@ -33,7 +33,7 @@ namespace PluginConsoleApp
//}
//Console.WriteLine("end print interfaceMethods------");
PluginManager pluginManager = new PluginManager(new Container())
var pluginManager = new PluginManager(new Container())
{
Enable = true//必须启用
};

View File

@@ -3,9 +3,11 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,202 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using TouchSocket.Core;
namespace AppMessengerConsoleApp;
internal class Program
{
private static async Task Main(string[] args)
{
await RegisterInstanceExample();
await RegisterStaticExample();
await SendAsyncExample();
await UnregisterExample();
await AllowMultipleExample();
Console.WriteLine("所有示例执行完成。");
Console.ReadKey();
}
#region AppMessenger注册实例示例
private static async Task RegisterInstanceExample()
{
Console.WriteLine("=== 注册实例示例 ===");
var messageObject = new MessageObject();
int add = await AppMessenger.Default.SendAsync<int>("Add", 20, 10);
Console.WriteLine($"Add结果: {add}");
int sub = await AppMessenger.Default.SendAsync<int>("Sub", 20, 10);
Console.WriteLine($"Sub结果: {sub}");
Console.WriteLine();
}
#endregion
#region AppMessenger注册静态方法示例
private static async Task RegisterStaticExample()
{
Console.WriteLine("=== 注册静态方法示例 ===");
AppMessenger.Default.RegisterStatic<StaticMessageObject>();
int multiply = await AppMessenger.Default.SendAsync<int>("StaticMultiply", 5, 4);
Console.WriteLine($"StaticMultiply结果: {multiply}");
Console.WriteLine();
}
#endregion
#region AppMessenger触发示例
private static async Task SendAsyncExample()
{
Console.WriteLine("=== 触发消息示例 ===");
// 触发有返回值的消息
int result = await AppMessenger.Default.SendAsync<int>("Add", 100, 50);
Console.WriteLine($"Add(100, 50) = {result}");
// 触发无返回值的消息
await AppMessenger.Default.SendAsync("Notify", "这是一条通知消息");
Console.WriteLine();
}
#endregion
#region AppMessenger注销示例
private static async Task UnregisterExample()
{
Console.WriteLine("=== 注销示例 ===");
var tempObject = new TempMessageObject();
// 注销前可以调用
await AppMessenger.Default.SendAsync("TempMethod");
Console.WriteLine("注销前调用成功");
// 注销对象
AppMessenger.Default.Unregister(tempObject);
try
{
// 注销后无法调用
await AppMessenger.Default.SendAsync("TempMethod");
}
catch (Exception ex)
{
Console.WriteLine($"注销后调用失败: {ex.Message}");
}
Console.WriteLine();
}
#endregion
#region AppMessenger允许多个订阅示例
private static async Task AllowMultipleExample()
{
Console.WriteLine("=== 允许多个订阅示例 ===");
// 创建新的AppMessenger实例并允许多个订阅
var messenger = new AppMessenger { AllowMultiple = true };
var subscriber1 = new MultiSubscriber("订阅者1");
var subscriber2 = new MultiSubscriber("订阅者2");
messenger.Register(subscriber1);
messenger.Register(subscriber2);
// 广播消息,所有订阅者都会收到
await messenger.SendAsync("OnEvent", "测试事件");
Console.WriteLine();
}
#endregion
}
#region AppMessenger实例类定义
public class MessageObject : IMessageObject
{
public MessageObject()
{
AppMessenger.Default.Register(this);
}
[AppMessage]
public Task<int> Add(int a, int b)
{
return Task.FromResult(a + b);
}
[AppMessage]
public Task<int> Sub(int a, int b)
{
return Task.FromResult(a - b);
}
[AppMessage]
public async Task Notify(string message)
{
await Task.CompletedTask;
Console.WriteLine($"收到通知: {message}");
}
}
#endregion
#region AppMessenger静态方法定义
public class StaticMessageObject : IMessageObject
{
[AppMessage]
public static Task<int> StaticMultiply(int a, int b)
{
return Task.FromResult(a * b);
}
}
#endregion
#region AppMessenger临时对象定义
public class TempMessageObject : IMessageObject
{
public TempMessageObject()
{
AppMessenger.Default.Register(this);
}
[AppMessage]
public async Task TempMethod()
{
await Task.CompletedTask;
Console.WriteLine("临时方法被调用");
}
}
#endregion
#region AppMessenger多订阅者定义
public class MultiSubscriber : IMessageObject
{
private readonly string _name;
public MultiSubscriber(string name)
{
_name = name;
}
[AppMessage]
public async Task OnEvent(string message)
{
await Task.CompletedTask;
Console.WriteLine($"{_name} 收到消息: {message}");
}
}
#endregion

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
@@ -9,11 +9,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -5,11 +5,11 @@
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -13,6 +13,7 @@
using System;
using System.Text;
using TouchSocket.Core;
using TouchSocket.Sockets;
namespace BytePoolConsoleApp;
@@ -20,21 +21,112 @@ internal class Program
{
private static void Main(string[] args)
{
CreateArrayPool();
CreateByteBlock();
CreateValueByteBlock();
CreateByteBlockWithCustomPool();
CreateByteBlockWithUsing();
BaseWriteRead();
BufferWriterWriteRead();
PrimitiveWriteRead();
BytesPackageWriteRead();
IPackageWriteRead();
IPackageWriteRead();
BufferWriterWriteRead();
HoldingExample();
Console.ReadKey();
}
private static void ExtensionWrite()
#region
private static void CreateArrayPool()
{
var byteBlock = new ValueByteBlock(1024);
System.Buffers.ArrayPool<byte> bytePool = System.Buffers.ArrayPool<byte>.Create(maxArrayLength: 1024 * 1024, maxArraysPerBucket: 50);
}
#endregion
#region ByteBlock
private static void CreateByteBlock()
{
var byteBlock = new ByteBlock(1024 * 64);
byteBlock.Dispose();
}
#endregion ByteBlock
#region ValueByteBlock
private static void CreateValueByteBlock()
{
var byteBlock = new ValueByteBlock(1024 * 64);
byteBlock.Dispose();
}
#endregion ValueByteBlock
#region 使
private static void CreateByteBlockWithCustomPool()
{
var customPool = System.Buffers.ArrayPool<byte>.Create();
var byteBlock = new ByteBlock(1024 * 64, (c) => customPool.Rent(c), (m) =>
{
if (System.Runtime.InteropServices.MemoryMarshal.TryGetArray((ReadOnlyMemory<byte>)m, out var result))
{
customPool.Return(result.Array);
}
});
byteBlock.Dispose();
}
#endregion 使
#region 使using释放
private static void CreateByteBlockWithUsing()
{
using (var byteBlock = new ByteBlock(1024 * 64))
{
//使用ByteBlock
}
}
#endregion 使using释放
#region
private static void BaseWriteRead()
{
using (var byteBlock = new ByteBlock(1024 * 64))
{
byteBlock.Write(new byte[] { 0, 1, 2, 3 });//将字节数组写入
byteBlock.SeekToStart();//将游标重置
var buffer = new byte[byteBlock.Length];//定义一个数组容器
var r = byteBlock.Read(buffer);//读取数据到容器并返回读取的长度r
}
}
#endregion
#region
private static void PrimitiveWriteRead()
{
var byteBlock = new ByteBlock(1024 * 64);
try
{
MyByteBlockExtension.ExtensionWrite(ref byteBlock);
WriterExtension.WriteValue(ref byteBlock, byte.MaxValue);//写入byte类型
WriterExtension.WriteValue(ref byteBlock, int.MaxValue);//写入int类型
WriterExtension.WriteValue(ref byteBlock, long.MaxValue);//写入long类型
WriterExtension.WriteString(ref byteBlock, "RRQM");//写入字符串类型
byteBlock.SeekToStart();//读取时,先将游标移动到初始写入的位置,然后按写入顺序,依次读取
var byteValue = ReaderExtension.ReadValue<ByteBlock, byte>(ref byteBlock);
var intValue = ReaderExtension.ReadValue<ByteBlock, int>(ref byteBlock);
var longValue = ReaderExtension.ReadValue<ByteBlock, long>(ref byteBlock);
var stringValue = ReaderExtension.ReadString<ByteBlock>(ref byteBlock);
}
finally
{
@@ -42,59 +134,13 @@ internal class Program
}
}
private static void IPackageWriteRead()
{
using (var byteBlock = new ByteBlock(1024*64))
{
byteBlock.WritePackage(new MyPackage()
{
Property = 10
});
byteBlock.SeekToStart();
#endregion
var myPackage = byteBlock.ReadPackage<MyPackage>();
}
}
private static void BytesPackageWriteRead()
{
using (var byteBlock = new ByteBlock(1024*64))
{
byteBlock.WriteBytesPackage(Encoding.UTF8.GetBytes("TouchSocket"));
byteBlock.SeekToStart();
var bytes = byteBlock.ReadBytesPackage();
byteBlock.SeekToStart();
//使用下列方式即可高效完成读取
var memory = byteBlock.ReadBytesPackageMemory();
}
}
private static void PrimitiveWriteRead()
{
using (var byteBlock = new ByteBlock(1024*64))
{
byteBlock.WriteByte(byte.MaxValue);//写入byte类型
byteBlock.WriteInt32(int.MaxValue);//写入int类型
byteBlock.WriteInt64(long.MaxValue);//写入long类型
byteBlock.WriteString("RRQM");//写入字符串类型
byteBlock.SeekToStart();//读取时,先将游标移动到初始写入的位置,然后按写入顺序,依次读取
var byteValue = byteBlock.ReadByte();
var intValue = byteBlock.ReadInt32();
var longValue = byteBlock.ReadInt64();
var stringValue = byteBlock.ReadString();
}
}
#region BufferWriter方式写入
private static void BufferWriterWriteRead()
{
using (var byteBlock = new ByteBlock(1024*64))
using (var byteBlock = new ByteBlock(1024 * 64))
{
var span = byteBlock.GetSpan(4);
span[0] = 0;
@@ -114,81 +160,91 @@ internal class Program
}
}
private static void BaseWriteRead()
{
using (var byteBlock = new ByteBlock(1024*64))
{
byteBlock.Write(new byte[] { 0, 1, 2, 3 });//将字节数组写入
#endregion BufferWriter方式写入
byteBlock.SeekToStart();//将游标重置
#region 线
var buffer = new byte[byteBlock.Length];//定义一个数组容器
var r = byteBlock.Read(buffer);//读取数据到容器并返回读取的长度r
}
private static void HoldingExample()
{
// 此示例演示了SetHolding的用法
// 实际使用请参考MyTClient和MyTClientError类
}
private static void Performance()
{
var count = 1000000;
var timeSpan1 = TimeMeasurer.Run(() =>
{
for (var i = 0; i < count; i++)
{
var buffer = new byte[1024];
}
});
#endregion 线
var timeSpan2 = TimeMeasurer.Run(() =>
private static void ExtensionWrite()
{
for (var i = 0; i < count; i++)
var byteBlock = new ValueByteBlock(1024);
try
{
MyByteBlockExtension.ExtensionWrite(ref byteBlock);
}
finally
{
var byteBlock = new ByteBlock(1024);
byteBlock.Dispose();
}
});
Console.WriteLine($"直接实例化:{timeSpan1}");
Console.WriteLine($"内存池实例化:{timeSpan2}");
}
}
#region Hold错误示例
// 错误示例直接在异步任务中使用ByteBlock会导致异常
// 因为byteBlock在异步任务开始前就已经被释放了
internal static class HoldErrorExample
{
public static void HandleData(ByteBlock byteBlock)
{
System.Threading.Tasks.Task.Run(() =>
{
// 错误此时byteBlock可能已被释放
string mes = byteBlock.Span.ToString(Encoding.UTF8);
Console.WriteLine($"已接收到信息:{mes}");
});
}
}
#endregion Hold错误示例
#region Hold正确示例
// 正确示例使用SetHolding锁定ByteBlock在异步任务中使用后再解锁
internal static class HoldCorrectExample
{
public static void HandleData(ByteBlock byteBlock)
{
byteBlock.SetHolding(true);//异步前锁定
System.Threading.Tasks.Task.Run(() =>
{
string mes = byteBlock.Span.ToString(Encoding.UTF8);
byteBlock.SetHolding(false);//使用完成后取消锁定且不用再调用Dispose
Console.WriteLine($"已接收到信息:{mes}");
});
}
}
#endregion Hold正确示例
internal class MyPackage : PackageBase
{
public int Property { get; set; }
/*新写法*/
public override void Package<TByteBlock>(ref TByteBlock byteBlock)
{
byteBlock.WriteInt32(this.Property);
WriterExtension.WriteValue<TByteBlock, int>(ref byteBlock, this.Property);
}
public override void Unpackage<TByteBlock>(ref TByteBlock byteBlock)
{
this.Property = byteBlock.ReadInt32();
this.Property = ReaderExtension.ReadValue<TByteBlock, int>(ref byteBlock);
}
/*旧写法*/
//public override void Package(in ByteBlock byteBlock)
//{
// byteBlock.Write(this.Property);
//}
//public override void Unpackage(in ByteBlock byteBlock)
//{
// this.Property = byteBlock.ReadInt32();
//}
}
internal class MyClass
{
public int Property { get; set; }
}
internal static class MyByteBlockExtension
{
public static void ExtensionWrite<TByteBlock>(ref TByteBlock byteBlock) where TByteBlock : IByteBlock
public static void ExtensionWrite<TByteBlock>(ref TByteBlock byteBlock) where TByteBlock : IBytesWriter
{
byteBlock.WriteInt16(10);
byteBlock.WriteInt32(10);
WriterExtension.WriteValue(ref byteBlock, (short)10);
WriterExtension.WriteValue(ref byteBlock, 10);
}
}

View File

@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,178 @@
//------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://touchsocket.net/
// 交流QQ群:234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using System;
using System.Threading.Tasks;
using TouchSocket.Core;
namespace ConsoleActionConsoleApp;
internal class Program
{
private static async Task Main(string[] args)
{
// 基础示例
BasicUsageExample();
// 运行命令行示例
// await RunCommandLineExample();
}
#region
/// <summary>
/// 基础用法示例
/// </summary>
private static void BasicUsageExample()
{
var consoleAction = new ConsoleAction("h|help|?"); // 设置帮助命令
consoleAction.OnException += ConsoleAction_OnException; // 订阅执行异常输出
// 添加命令
consoleAction.Add("start|s", "启动服务", StartService);
consoleAction.Add("stop|st", "停止服务", StopService);
consoleAction.Add("status|ss", "查看状态", ShowStatus);
consoleAction.Add("clear|c", "清空控制台", ClearConsole);
// 显示所有注册的命令
consoleAction.ShowAll();
// 模拟执行命令
Console.WriteLine("\n执行命令示例:");
consoleAction.RunAsync("start").Wait();
consoleAction.RunAsync("status").Wait();
}
#endregion
#region
/// <summary>
/// 异常处理
/// </summary>
private static void ConsoleAction_OnException(Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"发生错误: {ex.Message}");
Console.ResetColor();
}
#endregion
#region
/// <summary>
/// 添加同步命令示例
/// </summary>
private static void AddSyncCommandExample()
{
var consoleAction = new ConsoleAction();
// 添加无参数的同步命令
consoleAction.Add("test1", "测试命令1", () =>
{
Console.WriteLine("执行测试命令1");
});
// 多个命令别名
consoleAction.Add("start|s|run", "启动服务", StartService);
}
#endregion
#region
/// <summary>
/// 添加异步命令示例
/// </summary>
private static void AddAsyncCommandExample()
{
var consoleAction = new ConsoleAction();
// 添加异步命令
consoleAction.Add("async-task", "异步任务", async () =>
{
Console.WriteLine("开始异步任务...");
await Task.Delay(1000);
Console.WriteLine("异步任务完成");
});
}
#endregion
#region
/// <summary>
/// 运行命令行循环
/// </summary>
private static async Task RunCommandLineExample()
{
var consoleAction = new ConsoleAction();
consoleAction.OnException += ConsoleAction_OnException;
// 注册命令
consoleAction.Add("start", "启动服务", StartService);
consoleAction.Add("stop", "停止服务", StopService);
consoleAction.Add("exit|quit", "退出程序", () =>
{
Console.WriteLine("程序退出");
Environment.Exit(0);
});
// 显示所有命令
consoleAction.ShowAll();
// 运行命令行循环
await consoleAction.RunCommandLineAsync();
}
#endregion
#region
/// <summary>
/// 获取所有命令信息
/// </summary>
private static void GetAllCommandsExample()
{
var consoleAction = new ConsoleAction();
consoleAction.Add("cmd1", "命令1", () => { });
consoleAction.Add("cmd2|c2", "命令2", () => { });
// 获取所有命令信息
var allCommands = consoleAction.AllActionInfos;
foreach (var cmd in allCommands)
{
Console.WriteLine($"命令: {cmd.FullOrder}, 描述: {cmd.Description}");
}
}
#endregion
// 示例命令实现方法
private static void StartService()
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("✓ 服务已启动");
Console.ResetColor();
}
private static void StopService()
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("✓ 服务已停止");
Console.ResetColor();
}
private static void ShowStatus()
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("当前状态: 运行中");
Console.WriteLine("启动时间: 2024-01-01 00:00:00");
Console.WriteLine("活动连接: 0");
Console.ResetColor();
}
private static void ClearConsole()
{
Console.Clear();
Console.WriteLine("控制台已清空");
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
namespace DependencyPropertyConsoleApp;
#region
class MyClass
{
public int MyProperty { get; set; }
}
#endregion

View File

@@ -0,0 +1,182 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using TouchSocket.Core;
namespace DependencyPropertyConsoleApp;
internal class Program
{
static void Main(string[] args)
{
// 演示内部声明
InternalDeclarationExample();
// 演示扩展声明
ExtensionDeclarationExample();
// 演示应用场景
ScenarioExample();
Console.ReadKey();
}
static void InternalDeclarationExample()
{
#region
var obj = new MyDependencyObject();
obj.MyProperty1 = 100;
Console.WriteLine($"MyProperty1的值: {obj.MyProperty1}");
#endregion
}
static void ExtensionDeclarationExample()
{
#region
var obj = new MyDependencyObject();
// 使用扩展方法设置和获取
obj.SetMyProperty2(200);
var value = obj.GetMyProperty2();
Console.WriteLine($"MyProperty2的值: {value}");
// 也可以直接使用SetValue和GetValue
obj.SetValue(DependencyExtensions.MyPropertyProperty2, 300);
var value2 = obj.GetValue(DependencyExtensions.MyPropertyProperty2);
Console.WriteLine($"MyProperty2的新值: {value2}");
#endregion
}
static void ScenarioExample()
{
#region
var person = new Person { Age = 25 };
// 为Person对象动态添加Name属性
person.SetName("张三");
Console.WriteLine($"姓名: {person.GetName()}, 年龄: {person.Age}");
// 为Person对象动态添加Address属性
person.SetAddress("北京市");
Console.WriteLine($"地址: {person.GetAddress()}");
#endregion
}
}
#region
class MyDependencyObject : DependencyObject
{
/// <summary>
/// 属性项
/// </summary>
public int MyProperty1
{
get { return GetValue(MyPropertyProperty1); }
set { SetValue(MyPropertyProperty1, value); }
}
/// <summary>
/// 依赖项
/// </summary>
public static readonly DependencyProperty<int> MyPropertyProperty1 =
new DependencyProperty<int>("MyProperty1", 10);
}
#endregion
#region
public static class DependencyExtensions
{
/// <summary>
/// 依赖项
/// </summary>
public static readonly DependencyProperty<int> MyPropertyProperty2 =
new DependencyProperty<int>("MyProperty2", 10);
/// <summary>
/// 设置MyProperty2
/// </summary>
public static TClient SetMyProperty2<TClient>(this TClient client, int value) where TClient : IDependencyObject
{
client.SetValue(MyPropertyProperty2, value);
return client;
}
/// <summary>
/// 获取MyProperty2
/// </summary>
public static int GetMyProperty2<TClient>(this TClient client) where TClient : IDependencyObject
{
return client.GetValue(MyPropertyProperty2);
}
}
#endregion
#region Person类定义
public class Person : DependencyObject
{
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
}
#endregion
#region
public static class PersonExtensions
{
/// <summary>
/// Name依赖项
/// </summary>
public static readonly DependencyProperty<string> NameProperty =
new DependencyProperty<string>("Name", string.Empty);
/// <summary>
/// Address依赖项
/// </summary>
public static readonly DependencyProperty<string> AddressProperty =
new DependencyProperty<string>("Address", string.Empty);
/// <summary>
/// 设置Name
/// </summary>
public static TClient SetName<TClient>(this TClient client, string value) where TClient : IDependencyObject
{
client.SetValue(NameProperty, value);
return client;
}
/// <summary>
/// 获取Name
/// </summary>
public static string GetName<TClient>(this TClient client) where TClient : IDependencyObject
{
return client.GetValue(NameProperty);
}
/// <summary>
/// 设置Address
/// </summary>
public static TClient SetAddress<TClient>(this TClient client, string value) where TClient : IDependencyObject
{
client.SetValue(AddressProperty, value);
return client;
}
/// <summary>
/// 获取Address
/// </summary>
public static string GetAddress<TClient>(this TClient client) where TClient : IDependencyObject
{
return client.GetValue(AddressProperty);
}
}
#endregion

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -17,6 +17,6 @@
</ItemGroup>-->
<ItemGroup>
<PackageReference Include="TouchSocket.Core" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using TouchSocket.Core;
namespace FastBinaryFormatterConsoleApp;
@@ -6,6 +18,8 @@ internal class Program
{
private static void Main(string[] args)
{
SimpleUsage();
SerializeAndDeserialize(new MyClass4());
TestMyClass2_3();
@@ -20,11 +34,20 @@ internal class Program
SerializeAndDeserializeFromBytes(10);
SerializeAndDeserializeFromBytes("RRQM");
FastBinaryFormatter.AddFastBinaryConverter(typeof(MyClass5), new MyClass5FastBinaryConverter());
AddConverter();
Console.ReadKey();
}
#region FastBinary简单使用
public static void SimpleUsage()
{
var bytes = FastBinaryFormatter.SerializeToBytes(10);
var newObj = FastBinaryFormatter.Deserialize<int>(bytes);
}
#endregion
#region FastBinary兼容类型使用
public static void TestMyClass2_3()
{
var myClass2 = new MyClass2()
@@ -36,9 +59,8 @@ internal class Program
var newObj = FastBinaryFormatter.Deserialize<MyClass3>(bytes);
var ss = newObj.ToJsonString();
}
#endregion
public static void TestMyClass1()
{
@@ -54,7 +76,7 @@ internal class Program
SerializeAndDeserialize(myClass1);
}
#region FastBinary使用内存池块
public static void SerializeAndDeserialize<TValue>(TValue value)
{
//申请内存块,并指定此次序列化可能使用到的最大尺寸。
@@ -64,18 +86,16 @@ internal class Program
//将数据序列化到内存块
FastBinaryFormatter.Serialize(block, value);
Console.WriteLine($"ByteBlock序列化“{typeof(TValue)}”完成,数据长度={block.Length}");
//在反序列化前,将内存块数据游标移动至正确位。
block.SeekToStart();
//反序列化
var newObj = FastBinaryFormatter.Deserialize<TValue>(block);
Console.WriteLine($"ByteBlock反序列化“{typeof(TValue)}”完成Value={newObj.ToJsonString()}");
}
}
#endregion
#region FastBinary使用值类型内存池块
public static void SerializeAndDeserializeFromValueByteBlock<TValue>(TValue value)
{
//申请内存块,并指定此次序列化可能使用到的最大尺寸。
@@ -87,15 +107,11 @@ internal class Program
//将数据序列化到内存块
FastBinaryFormatter.Serialize(ref block, value);
Console.WriteLine($"ValueByteBlock序列化“{typeof(TValue)}”完成,数据长度={block.Length}");
//在反序列化前,将内存块数据游标移动至正确位。
block.SeekToStart();
//反序列化
var newObj = FastBinaryFormatter.Deserialize<TValue>(ref block);
Console.WriteLine($"ValueByteBlock反序列化“{typeof(TValue)}”完成Value={newObj.ToJsonString()}");
}
finally
{
@@ -103,20 +119,23 @@ internal class Program
block.Dispose();
}
}
#endregion
public static void SerializeAndDeserializeFromBytes<TValue>(TValue value)
{
var bytes = FastBinaryFormatter.SerializeToBytes(value);
Console.WriteLine($"Bytes序列化“{typeof(TValue)}”完成,数据长度={bytes.Length}");
var newObj = FastBinaryFormatter.Deserialize<TValue>(bytes);
Console.WriteLine($"Bytes反序列化“{typeof(TValue)}”完成Value={newObj.ToJsonString()}");
}
#region FastBinary添加转换器
public static void AddConverter()
{
FastBinaryFormatter.AddFastBinaryConverter(typeof(MyClass5), new MyClass5FastBinaryConverter());
}
#endregion
}
#region FastBinary常规配置示例类
public class MyClass1
{
private int m_p5;
@@ -162,7 +181,9 @@ public class MyClass1
this.P7 = value;
}
}
#endregion
#region FastBinary兼容类型类定义
public class MyClass2
{
public int P1 { get; set; }
@@ -171,9 +192,11 @@ public class MyClass2
public class MyClass3
{
public int P1 { get; set; }
public string P2 { get; set; }
public string? P2 { get; set; }
}
#endregion
#region FastBinary特性成员示例类
[FastSerialized(EnableIndex = true)]
public class MyClass4
{
@@ -183,14 +206,18 @@ public class MyClass4
[FastMember(2)]
public int MyProperty2 { get; set; }
}
#endregion
#region FastBinary自定义转换器示例类
[FastConverter(typeof(MyClass5FastBinaryConverter))]
public class MyClass5
{
public int P1 { get; set; }
public int P2 { get; set; }
}
#endregion
#region FastBinary自定义转换器实现
public sealed class MyClass5FastBinaryConverter : FastBinaryConverter<MyClass5>
{
protected override MyClass5 Read<TByteBlock>(ref TByteBlock byteBlock, Type type)
@@ -199,8 +226,8 @@ public sealed class MyClass5FastBinaryConverter : FastBinaryConverter<MyClass5>
//我们只需要把有效信息按写入的顺序,读取即可。
var myClass5 = new MyClass5();
myClass5.P1 = byteBlock.ReadInt32();
myClass5.P2 = byteBlock.ReadInt32();
myClass5.P1 = ReaderExtension.ReadValue<TByteBlock, int>(ref byteBlock);
myClass5.P2 = ReaderExtension.ReadValue<TByteBlock, int>(ref byteBlock);
return myClass5;
}
@@ -212,16 +239,17 @@ public sealed class MyClass5FastBinaryConverter : FastBinaryConverter<MyClass5>
//对于MyClass5类只有两个属性是有效的。
//所以,依次写入属性值即可
byteBlock.WriteInt32(obj.P1);
byteBlock.WriteInt32(obj.P2);
WriterExtension.WriteValue(ref byteBlock, obj.P1);
WriterExtension.WriteValue(ref byteBlock, obj.P2);
}
}
#endregion
#region FastBinary包模式序列化示例类
[GeneratorPackage]
public partial class MyClass6 : PackageBase
{
public int P1 { get; set; }
public int P2 { get; set; }
}
#endregion

View File

@@ -0,0 +1,129 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
using Microsoft.Extensions.DependencyInjection;
using TouchSocket.Core;
using TouchSocket.Core.AspNetCore;
namespace IocConsoleApp;
/// <summary>
/// 高级IOC容器示例
/// </summary>
internal static class AdvancedContainer
{
public static void Run()
{
UseAspNetCoreContainer();
UseAspNetCoreContainerWithConfig();
InterfaceMapping();
GenericTypeRegistration();
}
private static void UseAspNetCoreContainer()
{
#region IOC使用AspNetCoreContainer
var aspNetCoreContainer = new AspNetCoreContainer(new ServiceCollection());
aspNetCoreContainer.RegisterSingleton<MyClass1>();
aspNetCoreContainer.RegisterSingleton<MyClass2>();
aspNetCoreContainer.BuildResolver();
var myClass1 = aspNetCoreContainer.Resolve<MyClass1>();
var myClass2 = aspNetCoreContainer.Resolve<MyClass2>();
#endregion
Console.WriteLine("UseAspNetCoreContainer completed");
}
private static void UseAspNetCoreContainerWithConfig()
{
#region IOC配置中使用ServiceCollection
var config = new TouchSocketConfig()
.UseAspNetCoreContainer(new ServiceCollection()); //ServiceCollection可以使用现有的
#endregion
Console.WriteLine("UseAspNetCoreContainerWithConfig completed");
}
private static void InterfaceMapping()
{
#region IOC接口映射注册
var container = new Container();
// 将接口映射到实现类
container.RegisterSingleton<IMyService, MyServiceImpl>();
var service = container.Resolve<IMyService>();
service.DoSomething();
#endregion
Console.WriteLine("InterfaceMapping completed");
}
private static void GenericTypeRegistration()
{
#region IOC泛型类型注册
var container = new Container();
// 注册泛型类型定义(使用瞬态避免单例冲突)
container.RegisterTransient(typeof(IRepository<>), typeof(Repository<>));
// 解析具体的泛型类型
var userRepo = (IRepository<User>)container.Resolve(typeof(IRepository<User>));
var productRepo = (IRepository<Product>)container.Resolve(typeof(IRepository<Product>));
userRepo.Save(new User { Name = "Alice" });
productRepo.Save(new Product { Name = "Book" });
#endregion
Console.WriteLine("GenericTypeRegistration completed");
}
}
#region IOC高级示例类型定义
internal interface IMyService
{
void DoSomething();
}
internal class MyServiceImpl : IMyService
{
public void DoSomething()
{
Console.WriteLine("MyServiceImpl.DoSomething");
}
}
internal interface IRepository<T>
{
void Save(T entity);
}
internal class Repository<T> : IRepository<T>
{
public void Save(T entity)
{
Console.WriteLine($"Saving {typeof(T).Name}: {entity}");
}
}
internal class User
{
public string Name { get; set; }
public override string ToString() => Name;
}
internal class Product
{
public string Name { get; set; }
public override string ToString() => Name;
}
#endregion

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket.Core" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core.DependencyInjection" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core" />
<PackageReference Include="TouchSocket.Core.DependencyInjection" />
</ItemGroup>
</Project>

View File

@@ -23,8 +23,11 @@ internal static class NormalContainer
public static void Run()
{
ConstructorInject();
PropertyInject();
MethodInject();
SingletonLifetime();
TransientLifetime();
ScopedLifetime();
RegisterWithKey();
RegisterWithFactory();
}
/// <summary>
@@ -32,53 +35,124 @@ internal static class NormalContainer
/// </summary>
private static void ConstructorInject()
{
var container = GetContainer();
#region IOC构造函数注入
var container = new Container();
container.RegisterSingleton<MyClass1>();
container.RegisterSingleton<MyClass2>();
var myClass1 = container.Resolve<MyClass1>();
var myClass2 = container.Resolve<MyClass2>();
#endregion
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
}
/// <summary>
/// 属性注入
/// 单例生命周期
/// </summary>
private static void PropertyInject()
private static void SingletonLifetime()
{
var container = GetContainer();
#region IOC单例生命周期
var container = new Container();
container.RegisterSingleton<MyClass1>();
container.RegisterSingleton<MyClass1>("key");
container.RegisterSingleton<MyClass2>();
container.RegisterSingleton<MyClass3>();
var instance1 = container.Resolve<MyClass1>();
var instance2 = container.Resolve<MyClass1>();
// instance1 和 instance2 是同一个实例
Console.WriteLine($"Singleton: {ReferenceEquals(instance1, instance2)}"); // True
#endregion
var myClass3 = container.Resolve<MyClass3>();
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
}
/// <summary>
/// 方法注入
/// 瞬态生命周期
/// </summary>
private static void MethodInject()
private static void TransientLifetime()
{
var container = GetContainer();
container.RegisterSingleton<MyClass1>();
container.RegisterSingleton<MyClass4>();
#region IOC瞬态生命周期
var container = new Container();
container.RegisterTransient<MyClass1>();
var instance1 = container.Resolve<MyClass1>();
var instance2 = container.Resolve<MyClass1>();
// instance1 和 instance2 是不同的实例
Console.WriteLine($"Transient: {ReferenceEquals(instance1, instance2)}"); // False
#endregion
var myClass4 = container.Resolve<MyClass4>();
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
}
private static IContainer GetContainer()
/// <summary>
/// 作用域生命周期
/// </summary>
private static void ScopedLifetime()
{
return new Container();//默认IOC容器
#region IOC作用域生命周期
var container = new Container();
container.RegisterScoped<MyClass1>();
//return new AspNetCoreContainer(new ServiceCollection());//使用Aspnetcore的容器
// 在同一作用域内是同一实例
using (var scope = container.CreateScopedResolver())
{
var instance1 = scope.Resolver.Resolve<MyClass1>();
var instance2 = scope.Resolver.Resolve<MyClass1>();
Console.WriteLine($"Scoped (same scope): {ReferenceEquals(instance1, instance2)}"); // True
}
// 在不同作用域内是不同实例
using (var scope1 = container.CreateScopedResolver())
using (var scope2 = container.CreateScopedResolver())
{
var instance1 = scope1.Resolver.Resolve<MyClass1>();
var instance2 = scope2.Resolver.Resolve<MyClass1>();
Console.WriteLine($"Scoped (different scopes): {ReferenceEquals(instance1, instance2)}"); // False
}
#endregion
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
}
/// <summary>
/// 使用Key注册
/// </summary>
private static void RegisterWithKey()
{
#region IOC使用Key注册
var container = new Container();
container.RegisterSingleton<MyClass1>();
container.RegisterSingleton<MyClass1>("specialKey");
var defaultInstance = container.Resolve<MyClass1>();
var keyedInstance = container.Resolve<MyClass1>("specialKey");
// 不同的注册,不同的实例
Console.WriteLine($"Keyed: {ReferenceEquals(defaultInstance, keyedInstance)}"); // False
#endregion
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
}
/// <summary>
/// 使用工厂方法注册
/// </summary>
private static void RegisterWithFactory()
{
#region IOC使用工厂方法注册
var container = new Container();
container.RegisterSingleton<MyClass1>(resolver =>
{
Console.WriteLine("Creating MyClass1 using factory");
return new MyClass1();
});
var instance = container.Resolve<MyClass1>();
#endregion
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
}
}
#region IOC定义类型
internal class MyClass1
{
}
@@ -92,35 +166,4 @@ internal class MyClass2
public MyClass1 MyClass1 { get; }
}
internal class MyClass3
{
/// <summary>
/// 直接按类型,默认方式获取
/// </summary>
[DependencyInject]
public MyClass1 MyClass1 { get; set; }
/// <summary>
/// 获得指定类型的对象然后赋值到object
/// </summary>
[DependencyInject(typeof(MyClass2))]
public object MyClass2 { get; set; }
/// <summary>
/// 按照类型+Key获取
/// </summary>
[DependencyInject("key")]
public MyClass1 KeyMyClass1 { get; set; }
}
internal class MyClass4
{
public MyClass1 MyClass1 { get; private set; }
[DependencyInject]
public void MethodInject(MyClass1 myClass1)
{
this.MyClass1 = myClass1;
}
}
#endregion

View File

@@ -16,7 +16,8 @@ internal class Program
{
private static void Main(string[] args)
{
NormalContainer.Run();// 常规Ioc容器使用IL和反射实现支持运行时注册和获取
NormalContainer.Run();
AdvancedContainer.Run();
Console.ReadKey();
}

View File

@@ -8,13 +8,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="log4net" Version="3.1.0" />
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.JsonRpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.Rpc" Version="3.1.15" />
<PackageReference Include="TouchSocket.WebApi" Version="3.1.15" />
<PackageReference Include="TouchSocket.XmlRpc" Version="3.1.15" />
<PackageReference Include="TouchSocketPro.Dmtp" Version="3.1.15" />
<PackageReference Include="log4net" />
<PackageReference Include="TouchSocket" />
<PackageReference Include="TouchSocket.JsonRpc" />
<PackageReference Include="TouchSocket.Rpc" />
<PackageReference Include="TouchSocket.WebApi" />
<PackageReference Include="TouchSocket.XmlRpc" />
<PackageReference Include="TouchSocketPro.Dmtp" />
</ItemGroup>
<ItemGroup>

View File

@@ -32,7 +32,7 @@ internal class Program
service.Received = async (client, e) =>
{
//从客户端收到信息
var mes = e.ByteBlock.Span.ToString(Encoding.UTF8);
var mes = e.Memory.Span.ToString(Encoding.UTF8);
service.Logger.Info($"服务器已从{client.Id}接收到信息:{mes}");
await client.SendAsync(mes);//将收到的信息直接返回给发送方
@@ -42,6 +42,22 @@ internal class Program
.SetListenIPHosts(7789)
.ConfigureContainer(a =>
{
#region
a.AddFileLogger(fileLogger =>
{
fileLogger.MaxSize = 1024 * 1024;
fileLogger.LogLevel = LogLevel.Debug;
});
#endregion
#region
a.AddLogger(logger =>
{
logger.AddConsoleLogger();
logger.AddFileLogger();
});
#endregion
a.AddLogger(logger =>
{
logger.AddConsoleLogger();
@@ -64,6 +80,7 @@ internal class Program
}
}
#region Log4net自定义日志记录器
internal class Mylog4netLogger : LoggerBase
{
private readonly log4net.ILog m_logger;
@@ -109,3 +126,4 @@ internal class Mylog4netLogger : LoggerBase
}
}
}
#endregion

View File

@@ -8,6 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,15 @@
// ------------------------------------------------------------------------------
// 此代码版权除特别声明或在XREF结尾的命名空间的代码归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议若本仓库没有设置则按MIT开源协议授权
// CSDN博客https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频https://space.bilibili.com/94253567
// Gitee源代码仓库https://gitee.com/RRQM_Home
// Github源代码仓库https://github.com/RRQM
// API首页https://touchsocket.net/
// 交流QQ群234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using TouchSocket.Core;
namespace LoggerConsoleApp;
@@ -11,55 +23,89 @@ internal class Program
private static void TestConsoleLogger()
{
#region 使
var logger = ConsoleLogger.Default;
logger.LogLevel = LogLevel.Debug;
logger.Info("Message");
logger.Warning("Warning");
logger.Error("Error");
#endregion
}
private static void TestFileLogger()
{
#region
var logger = new FileLogger();
logger.Info("Message");
logger.Warning("Warning");
logger.Error("Error");
#endregion
}
private static void TestFileLogger_MaxSize()
{
#region
var logger = new FileLogger()
{
MaxSize = 1024 * 1024 * 2
};
#endregion
}
private static void TestFileLogger_Folder()
{
#region
var logger = new FileLogger()
{
CreateLogFolder = (logLevel) =>
{
return $"logs\\{DateTime.Now:[yyyy-MM-dd]}";
}
};
#endregion
}
private static void TestFileLogger_FolderByLogLevel()
{
#region
var logger = new FileLogger()
{
CreateLogFolder = (logLevel) =>
{
return $"logs\\{DateTime.Now:[yyyy-MM-dd]}\\{logLevel}";
},
FileNameFormat = "",
}
};
logger.Info("Message");
logger.Warning("Warning");
logger.Error("Error");
#endregion
}
private static void TestEasyLogger()
{
#region 使
var logger = new EasyLogger(LoggerOutput);
logger.Info("Message");
logger.Warning("Warning");
logger.Error("Error");
#endregion
}
#region
private static void LoggerOutput(string loggerString)
{
Console.WriteLine(loggerString);
//或者如果是winform程序可以直接输出到TextBox
//或者如果是winform程序,可以直接输出到TextBox
}
#endregion
}
internal class MyLogger : ILog
#region
class MyLogger : ILog
{
public LogLevel LogLevel { get; set; } = LogLevel.Debug;
public string DateTimeFormat { get; set; }
public string DateTimeFormat { get; set; } = "yyyy-MM-dd HH:mm:ss ffff";
public void Log(LogLevel logLevel, object source, string message, Exception exception)
{
//此处可以自由实现逻辑。
}
}
#endregion

View File

@@ -8,7 +8,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="3.1.15" />
<PackageReference Include="TouchSocket.Core" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,380 @@
// ------------------------------------------------------------------------------
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
// CSDN博客:https://blog.csdn.net/qq_40374647
// 哔哩哔哩视频:https://space.bilibili.com/94253567
// Gitee源代码仓库:https://gitee.com/RRQM_Home
// Github源代码仓库:https://github.com/RRQM
// API首页:https://touchsocket.net/
// 交流QQ群:234762506
// 感谢您的下载和使用
// ------------------------------------------------------------------------------
using TouchSocket.Core;
namespace OtherCoreConsoleApp;
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("=== TouchSocket 其他核心功能示例 ===\n");
// 一、Crc计算示例
OtherCoreDemo.CrcExample();
OtherCoreDemo.Crc16ValueExample();
// 二、时间测量器示例
OtherCoreDemo.TimeMeasurerExample();
OtherCoreDemo.TimeMeasurerAsyncExample();
// 三、MD5计算示例
OtherCoreDemo.MD5Example();
// 四、16进制相关示例
OtherCoreDemo.HexStringExample();
// 五、雪花Id生成示例
OtherCoreDemo.SnowflakeIdExample();
// 六、数据压缩示例
OtherCoreDemo.GZipExample();
OtherCoreDemo.CustomDataCompressorExample();
// 七、短时间戳示例
OtherCoreDemo.ShortTimestampExample();
// 八、读写锁using示例
OtherCoreDemo.ReadWriteLockExample();
// 九、3DES示例
OtherCoreDemo.TripleDESExample();
Console.WriteLine("\n=== 所有示例执行完毕 ===");
Console.ReadKey();
}
}
/// <summary>
/// 其他核心功能示例类
/// </summary>
public static class OtherCoreDemo
{
#region Crc计算
/// <summary>
/// Crc计算示例
/// </summary>
public static void CrcExample()
{
Console.WriteLine("【一、Crc计算示例】");
byte[] data = new byte[10];
new Random().NextBytes(data);
// Crc16计算
byte[] result = Crc.Crc16(data);
Console.WriteLine($"原始数据: {BitConverter.ToString(data)}");
Console.WriteLine($"Crc16结果: {BitConverter.ToString(result)}");
Console.WriteLine();
}
#endregion
#region Crc16Value计算
/// <summary>
/// Crc16Value计算示例
/// </summary>
public static void Crc16ValueExample()
{
Console.WriteLine("【Crc16Value计算示例】");
byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 };
// 计算Crc16Value(返回ushort)
ushort crc16Value = Crc.Crc16Value(data);
Console.WriteLine($"原始数据: {BitConverter.ToString(data)}");
Console.WriteLine($"Crc16Value: 0x{crc16Value:X4}");
Console.WriteLine();
}
#endregion
#region
/// <summary>
/// 时间测量器示例
/// </summary>
public static void TimeMeasurerExample()
{
Console.WriteLine("【二、时间测量器示例】");
TimeSpan timeSpan = TimeMeasurer.Run(() =>
{
Thread.Sleep(1000);
});
Console.WriteLine($"同步操作耗时: {timeSpan.TotalMilliseconds} 毫秒");
Console.WriteLine();
}
#endregion
#region
/// <summary>
/// 时间测量器异步示例
/// </summary>
public static void TimeMeasurerAsyncExample()
{
Console.WriteLine("【时间测量器异步示例】");
var timeSpan = TimeMeasurer.Run(async () =>
{
await Task.Delay(500);
});
Console.WriteLine($"异步操作耗时: {timeSpan.TotalMilliseconds} 毫秒");
Console.WriteLine();
}
#endregion
#region MD5计算
/// <summary>
/// MD5计算示例
/// </summary>
public static void MD5Example()
{
Console.WriteLine("【三、MD5计算示例】");
string str = MD5.GetMD5Hash("TouchSocket");
bool b = MD5.VerifyMD5Hash("TouchSocket", str);
Console.WriteLine($"MD5哈希值: {str}");
Console.WriteLine($"验证结果: {b}");
Console.WriteLine();
}
#endregion
#region 16
/// <summary>
/// 16进制相关示例
/// </summary>
public static void HexStringExample()
{
Console.WriteLine("【四、16进制相关示例】");
// 将16进制字符串转换为字节数组
string hexString = "01-02-03-04-05";
byte[] bytes = hexString.ByHexStringToBytes("-");
Console.WriteLine($"16进制字符串: {hexString}");
Console.WriteLine($"转换为字节数组: {BitConverter.ToString(bytes)}");
// 将16进制字符串转换为int32
string hexInt = "12345678";
int value = hexInt.ByHexStringToInt32();
Console.WriteLine($"16进制字符串: {hexInt}");
Console.WriteLine($"转换为int32: 0x{value:X8}");
Console.WriteLine();
}
#endregion
#region Id生成
/// <summary>
/// 雪花Id生成示例
/// </summary>
public static void SnowflakeIdExample()
{
Console.WriteLine("【五、雪花Id生成示例】");
SnowflakeIdGenerator generator = new SnowflakeIdGenerator(4);
// 生成多个Id
for (int i = 0; i < 5; i++)
{
long id = generator.NextId();
Console.WriteLine($"生成的雪花Id: {id}");
}
Console.WriteLine();
}
#endregion
#region GZip压缩
/// <summary>
/// GZip数据压缩示例
/// </summary>
public static void GZipExample()
{
Console.WriteLine("【六、数据压缩示例】");
byte[] data = new byte[1024];
new Random().NextBytes(data);
using (ByteBlock byteBlock = new ByteBlock(1024 * 64))
{
// 压缩
GZip.Compress(byteBlock, data);
Console.WriteLine($"原始数据大小: {data.Length} 字节");
Console.WriteLine($"压缩后大小: {byteBlock.Length} 字节");
// 解压
var decompressData = GZip.Decompress(byteBlock.Span).ToArray();
Console.WriteLine($"解压后大小: {decompressData.Length} 字节");
Console.WriteLine($"数据一致性: {data.SequenceEqual(decompressData)}");
}
Console.WriteLine();
}
#endregion
#region
/// <summary>
/// 自定义数据压缩器示例
/// </summary>
public static void CustomDataCompressorExample()
{
Console.WriteLine("【自定义数据压缩器示例】");
// 使用GZip压缩器
IDataCompressor compressor = new GZipDataCompressor();
byte[] data = new byte[512];
new Random().NextBytes(data);
// 压缩
var compressedBlock = new ByteBlock(1024);
compressor.Compress(ref compressedBlock, data);
Console.WriteLine($"原始数据大小: {data.Length} 字节");
Console.WriteLine($"压缩后大小: {compressedBlock.Length} 字节");
// 解压
var decompressedBlock = new ByteBlock(1024);
compressor.Decompress(ref decompressedBlock, compressedBlock.Span);
Console.WriteLine($"解压后大小: {decompressedBlock.Length} 字节");
Console.WriteLine($"数据一致性: {data.SequenceEqual(decompressedBlock.Span.ToArray())}");
// 释放资源
compressedBlock.Dispose();
decompressedBlock.Dispose();
Console.WriteLine();
}
#endregion
#region
/// <summary>
/// 短时间戳示例
/// </summary>
public static void ShortTimestampExample()
{
Console.WriteLine("【七、短时间戳示例】");
// 获取当前时间的短时间戳(自1970年1月1日以来的毫秒数,uint类型)
uint timestamp = DateTime.Now.ToUnsignedMillis();
Console.WriteLine($"短时间戳(uint): {timestamp}");
// 使用DateTimeOffset
timestamp = DateTimeOffset.Now.ToUnsignedMillis();
Console.WriteLine($"DateTimeOffset短时间戳: {timestamp}");
Console.WriteLine();
}
#endregion
#region Using
/// <summary>
/// 读写锁using示例
/// </summary>
public static void ReadWriteLockExample()
{
Console.WriteLine("【八、读写锁using示例】");
ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();
int sharedResource = 0;
// 读锁示例
using (new ReadLock(lockSlim))
{
Console.WriteLine($"读取共享资源: {sharedResource}");
}
// 写锁示例
using (new WriteLock(lockSlim))
{
sharedResource = 100;
Console.WriteLine($"写入共享资源: {sharedResource}");
}
// 再次读取
using (new ReadLock(lockSlim))
{
Console.WriteLine($"再次读取共享资源: {sharedResource}");
}
lockSlim.Dispose();
Console.WriteLine();
}
#endregion
#region 3DES加密
/// <summary>
/// 3DES加密解密示例
/// </summary>
public static void TripleDESExample()
{
Console.WriteLine("【九、3DES加密解密示例】");
byte[] data = System.Text.Encoding.UTF8.GetBytes("Hello TouchSocket!");
Console.WriteLine($"原始数据: {System.Text.Encoding.UTF8.GetString(data)}");
// 加密(口令长度为8)
var dataLocked = DataSecurity.EncryptDES(data, "12345678");
Console.WriteLine($"加密后: {BitConverter.ToString(dataLocked)}");
// 解密
var newData = DataSecurity.DecryptDES(dataLocked, "12345678");
Console.WriteLine($"解密后: {System.Text.Encoding.UTF8.GetString(newData)}");
Console.WriteLine($"数据一致性: {data.SequenceEqual(newData)}");
Console.WriteLine();
}
#endregion
#region
/// <summary>
/// 自定义压缩器实现示例
/// </summary>
class MyDataCompressor : IDataCompressor
{
public void Compress<TWriter>(ref TWriter writer, ReadOnlySpan<byte> data)
where TWriter : IBytesWriter
{
//此处实现压缩
throw new NotImplementedException();
}
public void Decompress<TWriter>(ref TWriter writer, ReadOnlySpan<byte> data)
where TWriter : IBytesWriter
{
//此处实现解压
throw new NotImplementedException();
}
}
#endregion
#region
/// <summary>
/// 读写锁传统用法示例
/// </summary>
public static void TraditionalReadWriteLockExample()
{
ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();
try
{
lockSlim.EnterReadLock();
//do something
}
finally
{
lockSlim.ExitReadLock();
}
}
#endregion
}

Some files were not shown because too many files have changed in this diff Show More