diff --git a/.github/prompts/优化文档代码.prompt.md b/.github/prompts/优化文档代码.prompt.md new file mode 100644 index 000000000..c1401d68c --- /dev/null +++ b/.github/prompts/优化文档代码.prompt.md @@ -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 标签格式:。 + +# 任务 + +- 你的任务是把文档中的代码示例提取到示例工程中,或者直接使用示例工程中的代码,并使用region包裹,然后在文档中使用`CustomCodeBlock`引用这些代码示例。你需要确保生成的文档符合用户的要求,内容准确无误,语言表达清晰流畅。 +- 如果文档中已经有`CustomCodeBlock`,则不再修改这些`CustomCodeBlock`,只需要处理没有`CustomCodeBlock`的代码示例即可。 diff --git a/.github/prompts/文档生成.prompt.md b/.github/prompts/文档生成.prompt.md new file mode 100644 index 000000000..13144807f --- /dev/null +++ b/.github/prompts/文档生成.prompt.md @@ -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 标签格式:。 + +# 视频链接规则 + +- 如果文档中包含视频链接,在重写文档时,链接必须保持。 +- 不要生成不存在的视频链接。 + + + +# 任务 + +- 1. 提取关键信息,组织内容结构,撰写文档内容。如果文档已存在,则需要适当润色和扩展内容。 +- 2. 根据用户提供的需求,生成相应的CSharp编程文档。你需要根据源代码和示例代码,提取关键信息,组织内容结构,撰写文档内容。 +- 3. 确保生成的文档符合用户的要求,内容准确无误,语言表达清晰流畅。 +- 4. 在生成的文档中,添加示例Demo的链接,链接格式为:。其中,link属性表示示例代码的相对路径,这路径都是从`examples`文件夹开始的,例如:。如果一个文档中包含多个示例代码链接,则需要分别在对应章节中添加多个`CardLink`标签。 \ No newline at end of file diff --git a/.gitignore b/.gitignore index d322048f0..5c0c08434 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/.vscode/doc.code-snippets b/.vscode/doc.code-snippets new file mode 100644 index 000000000..b5c667e35 --- /dev/null +++ b/.vscode/doc.code-snippets @@ -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": [ + "", + ], + "description": "img" + }, + "imgstatic": { + "prefix": "imgstatic", + "body": [ + "", + ], + "description": "imgstatic" + }, + "imgLink": { + "prefix": "imgLink", + "body": [ + "", + ], + "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": [ + "" + ], + "description": "CardLink" + }, + "CustomCodeBlock": { + "prefix": "CustomCodeBlock", + "body": [ + "" + ], + "description": "CustomCodeBlock" + }, + "BilibiliCard": { + "prefix": "BilibiliCard", + "body": [ + "" + ], + "description": "BilibiliCard" + }, + "Tag": { + "prefix": "Tag", + "body": [ + "$0" + ], + "description": "importTag" + }, + "Highlight": { + "prefix": "Highlight", + "body": [ + "Docusaurus 绿" + ], + "description": "tagHighlight" + }, + "details": { + "prefix": "details", + "body": [ + "", + "$1", + "", + "", + "$0", + "", + "", + "" + ], + "description": "details" + }, + "ahref": { + "prefix": "ahref", + "body": [ + "$0" + ], + "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": [ + "", + "", + "", + "", + "", + "", + ], + "description": "importTab" + }, + "Mermaid": { + "prefix": "mermaid", + "body": [ + "```mermaid", + "graph TD;", + "\tA-->B;", + "\tA-->C;", + "\tB-->D;", + "\tC-->D;", + "```" + ], + "description": "mermaid" + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 368b643d5..b85160e31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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": "", + "pasteImage.namePrefix": "", + "pasteImage.nameSuffix": "", + "pasteImage.encodePath": "urlEncodeSpace", + "pasteImage.showFilePathConfirmInputBox": false, + "pasteImage.filePathConfirmInputBoxMode": "onlyName", + "pasteImage.defaultName": "${currentFileNameWithoutExt}-YYYYMMDDHHmmss" } \ No newline at end of file diff --git a/TouchSocketVersion.props b/TouchSocketVersion.props index be3d44992..afe86b926 100644 --- a/TouchSocketVersion.props +++ b/TouchSocketVersion.props @@ -1,8 +1,9 @@ - + - 3.1.19 + 4.0.0-rc.50 + $(BaseVersion) diff --git a/examples/Adapter/AdapterConsoleApp/Program.cs b/examples/Adapter/AdapterConsoleApp/Program.cs deleted file mode 100644 index 6003bb0ac..000000000 --- a/examples/Adapter/AdapterConsoleApp/Program.cs +++ /dev/null @@ -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 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 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 -{ - /// - /// 包剩余长度 - /// - private byte m_surPlusLength; - - /// - /// 临时包,此包仅当前实例储存 - /// - 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(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(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(buffer, 0, r)); - this.m_surPlusLength -= (byte)r; - } - } - } - - - protected override async Task PreviewSendAsync(ReadOnlyMemory 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> 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(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(); - 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); - } - } - } - - /// - /// 处理数据 - /// - /// - private async Task PreviewHandleAsync(ByteBlock byteBlock) - { - try - { - await this.GoReceivedAsync(byteBlock, null); - } - finally - { - byteBlock.Dispose();//在框架里面将内存块释放 - } - } - - /// - /// 分解包 - /// - /// - /// - /// - 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(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(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 -} \ No newline at end of file diff --git a/examples/Adapter/AdapterTesterConsoleApp/AdapterTesterConsoleApp.csproj b/examples/Adapter/AdapterTesterConsoleApp/AdapterTesterConsoleApp.csproj index ac1119c78..5b850cb08 100644 --- a/examples/Adapter/AdapterTesterConsoleApp/AdapterTesterConsoleApp.csproj +++ b/examples/Adapter/AdapterTesterConsoleApp/AdapterTesterConsoleApp.csproj @@ -7,6 +7,6 @@ - + diff --git a/examples/Adapter/AdapterTesterConsoleApp/Program.cs b/examples/Adapter/AdapterTesterConsoleApp/Program.cs index f82cf68fc..5759b6666 100644 --- a/examples/Adapter/AdapterTesterConsoleApp/Program.cs +++ b/examples/Adapter/AdapterTesterConsoleApp/Program.cs @@ -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("测试结束"); diff --git a/examples/Adapter/BetweenAndConsoleApp/BetweenAndConsoleApp.csproj b/examples/Adapter/BetweenAndConsoleApp/BetweenAndConsoleApp.csproj index 401277729..a4e8e19f6 100644 --- a/examples/Adapter/BetweenAndConsoleApp/BetweenAndConsoleApp.csproj +++ b/examples/Adapter/BetweenAndConsoleApp/BetweenAndConsoleApp.csproj @@ -9,6 +9,6 @@ - + diff --git a/examples/Adapter/BetweenAndConsoleApp/Program.cs b/examples/Adapter/BetweenAndConsoleApp/Program.cs index 3c128c876..744ec4913 100644 --- a/examples/Adapter/BetweenAndConsoleApp/Program.cs +++ b/examples/Adapter/BetweenAndConsoleApp/Program.cs @@ -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 CreateClient() { var client = new TcpClient(); @@ -54,6 +38,7 @@ internal class Program private static async Task 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 +{ + private readonly ReadOnlyMemory m_endCode; + + private readonly ReadOnlyMemory 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 EndCode => this.m_endCode; + public override ReadOnlyMemory StartCode => this.m_startCode; + protected override MyBetweenAndRequestInfo GetInstance(ReadOnlySpan 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 -{ - 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 body) - { - return new MyBetweenAndRequestInfo(body.ToArray()); - } -} +#endregion \ No newline at end of file diff --git a/examples/Adapter/CustomAdapterConsoleApp/CustomAdapterConsoleApp.csproj b/examples/Adapter/CustomAdapterConsoleApp/CustomAdapterConsoleApp.csproj index ab8f18f2e..e79c4df47 100644 --- a/examples/Adapter/CustomAdapterConsoleApp/CustomAdapterConsoleApp.csproj +++ b/examples/Adapter/CustomAdapterConsoleApp/CustomAdapterConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/CustomAdapterConsoleApp/Program.cs b/examples/Adapter/CustomAdapterConsoleApp/Program.cs index b0a55df81..bad9dd821 100644 --- a/examples/Adapter/CustomAdapterConsoleApp/Program.cs +++ b/examples/Adapter/CustomAdapterConsoleApp/Program.cs @@ -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 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 +#region 用户自定义适配器 + +/// +/// 第1个字节表示指令类型 +/// 第2字节表示数据类型 +/// 第3字节表示后续数据的长度。使用ushort(大端)表示,最大长度为65535 +/// 后续字节表示载荷数据 +/// 最后2字节表示CRC16校验码 +/// +internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter { - /// - /// 筛选解析数据。实例化的TRequest会一直保存,直至解析成功,或手动清除。 - /// 当不满足解析条件时,请返回,此时会保存的数据 - /// 当数据部分异常时,请移动到指定位置,然后返回 - /// 当完全满足解析条件时,请返回最后将移至指定位置。 - /// - /// 字节块 - /// 是否为上次遗留对象,当该参数为True时,request也将是上次实例化的对象。 - /// 对象。 - /// 缓存容量指导,指示当需要缓存时,应该申请多大的内存。 - /// - protected override FilterResult Filter(ref TByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity) + private ushort m_payloadLength; + + protected override FilterResult Filter(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(header.Slice(2, 2)); + + return this.ParseData(ref reader, request); } } + + private FilterResult ParseData(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(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 +/// +/// 定义数据对象 +/// +internal class MyDataClass : IRequestInfo { - /// - /// 自定义属性,Body - /// - public byte[] Body { get; internal set; } - - /// - /// 自定义属性,DataType - /// - public byte DataType { get; internal set; } - - /// - /// 自定义属性,OrderType - /// - public byte OrderType { get; internal set; } -} \ No newline at end of file + public byte OrderType { get; set; } + public byte DataType { get; set; } + public byte[] Data { get; set; } +} +#endregion \ No newline at end of file diff --git a/examples/Adapter/CustomBigFixedHeaderConsoleApp/CustomBigFixedHeaderConsoleApp.csproj b/examples/Adapter/CustomBigFixedHeaderConsoleApp/CustomBigFixedHeaderConsoleApp.csproj index e215e7ade..e79c4df47 100644 --- a/examples/Adapter/CustomBigFixedHeaderConsoleApp/CustomBigFixedHeaderConsoleApp.csproj +++ b/examples/Adapter/CustomBigFixedHeaderConsoleApp/CustomBigFixedHeaderConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/CustomBigFixedHeaderConsoleApp/Program.cs b/examples/Adapter/CustomBigFixedHeaderConsoleApp/Program.cs index 56208172e..651604e90 100644 --- a/examples/Adapter/CustomBigFixedHeaderConsoleApp/Program.cs +++ b/examples/Adapter/CustomBigFixedHeaderConsoleApp/Program.cs @@ -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 CreateClient() { var client = new TcpClient(); @@ -58,16 +38,18 @@ internal class Program private static async Task 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 -{ - 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} +/// +/// 第1个字节表示指令类型 +/// 第2字节表示数据类型 +/// 第3字节表示后续数据的长度。使用ushort(大端)表示,最大长度为65535 +/// 后续字节表示载荷数据 +/// 最后2字节表示CRC16校验码 +/// +internal class MyCustomBigFixedHeaderDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter { + public override int HeaderLength => 4; + + protected override MyDataClass GetInstance() + { + return new MyDataClass(); + } +} + +internal class MyDataClass : IBigFixedHeaderRequestInfo +{ + private readonly List m_bytes = new List(); + + private long m_length; + + /// + /// 自定义属性,标识实际数据 + /// + public byte[] Body { get; set; } + /// /// 自定义属性,标识数据类型 /// @@ -108,17 +145,7 @@ internal class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo /// public byte OrderType { get; set; } - /// - /// 自定义属性,标识实际数据 - /// - public byte[] Body { get; set; } - - private long m_bodyLength; - - private readonly List m_bytes = new List(); - - #region 接口成员 - long IBigFixedHeaderRequestInfo.BodyLength => this.m_bodyLength; + long IBigFixedHeaderRequestInfo.BodyLength => this.m_length; void IBigFixedHeaderRequestInfo.OnAppendBody(ReadOnlySpan 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 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(header.Slice(2, 2)); + + + this.m_length = payloadLength + 2;//+2是因为还包含Crc16的长度 + return true; } - #endregion - } +#endregion diff --git a/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/CustomBigUnfixedHeaderConsoleApp.csproj b/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/CustomBigUnfixedHeaderConsoleApp.csproj index 897fb96ef..e08d18664 100644 --- a/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/CustomBigUnfixedHeaderConsoleApp.csproj +++ b/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/CustomBigUnfixedHeaderConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/Program.cs b/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/Program.cs index be7d01b34..b06e89241 100644 --- a/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/Program.cs +++ b/examples/Adapter/CustomBigUnfixedHeaderConsoleApp/Program.cs @@ -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 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 +#region 创建自定义大数据非固定包头适配器 +/// +/// 第1个字节表示指令类型 +/// 第2字节表示数据类型 +/// 第3字节表示后续数据的长度。使用ushort(大端)表示,最大长度为65535 +/// 后续字节表示载荷数据 +/// 最后2字节表示CRC16校验码 +/// +internal class MyCustomBigUnfixedHeaderDataHandlingAdapter : CustomBigUnfixedHeaderDataHandlingAdapter { - protected override MyBigUnfixedHeaderRequestInfo GetInstance() + protected override MyDataClass GetInstance() { - return new MyBigUnfixedHeaderRequestInfo(); + return new MyDataClass(); } } -internal class MyBigUnfixedHeaderRequestInfo : IBigUnfixedHeaderRequestInfo +internal class MyDataClass : IBigUnfixedHeaderRequestInfo { /// /// 自定义属性,标识数据类型 @@ -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(ref TByteBlock byteBlock) + bool IBigUnfixedHeaderRequestInfo.OnParsingHeader(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(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 diff --git a/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/CustomCountSpliterDataHandlingAdapterConsoleApp.csproj b/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/CustomCountSpliterDataHandlingAdapterConsoleApp.csproj index 18c1c8753..e08d18664 100644 --- a/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/CustomCountSpliterDataHandlingAdapterConsoleApp.csproj +++ b/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/CustomCountSpliterDataHandlingAdapterConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/Program.cs b/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/Program.cs index cef897445..fd95b2eb1 100644 --- a/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/Program.cs +++ b/examples/Adapter/CustomCountSpliterDataHandlingAdapterConsoleApp/Program.cs @@ -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 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 { 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 \ No newline at end of file diff --git a/examples/Adapter/CustomFixedHeaderConsoleApp/CustomFixedHeaderConsoleApp.csproj b/examples/Adapter/CustomFixedHeaderConsoleApp/CustomFixedHeaderConsoleApp.csproj index e215e7ade..e79c4df47 100644 --- a/examples/Adapter/CustomFixedHeaderConsoleApp/CustomFixedHeaderConsoleApp.csproj +++ b/examples/Adapter/CustomFixedHeaderConsoleApp/CustomFixedHeaderConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/CustomFixedHeaderConsoleApp/Program.cs b/examples/Adapter/CustomFixedHeaderConsoleApp/Program.cs index a43aca56a..bcb5fedd8 100644 --- a/examples/Adapter/CustomFixedHeaderConsoleApp/Program.cs +++ b/examples/Adapter/CustomFixedHeaderConsoleApp/Program.cs @@ -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 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 +#region 创建自定义固定包头适配器 {13,46-61,63-79} +/// +/// 第1个字节表示指令类型 +/// 第2字节表示数据类型 +/// 第3字节表示后续数据的长度。使用ushort(大端)表示,最大长度为65535 +/// 后续字节表示载荷数据 +/// 最后2字节表示CRC16校验码 +/// +public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter { /// /// 接口实现,指示固定包头长度 /// - public override int HeaderLength => 3; + public override int HeaderLength => 4; /// /// 获取新实例 /// /// - protected override MyFixedHeaderRequestInfo GetInstance() + protected override MyDataClass GetInstance() { - return new MyFixedHeaderRequestInfo(); + return new MyDataClass(); } } -public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo +public class MyDataClass : IFixedHeaderRequestInfo { - /// - /// 接口实现,标识数据长度 - /// - public int BodyLength { get; private set; } + private int m_length; /// /// 自定义属性,标识数据类型 @@ -135,24 +146,43 @@ public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo /// /// 自定义属性,标识实际数据 /// - public byte[] Body { get; set; } + public byte[] Data { get; set; } - public bool OnParsingBody(ReadOnlySpan body) + int IFixedHeaderRequestInfo.BodyLength => this.m_length; + + bool IFixedHeaderRequestInfo.OnParsingBody(ReadOnlySpan body) { - if (body.Length == this.BodyLength) + var data = body.Slice(0, body.Length - 2);//最后2个字节是CRC16校验码 + var crc16 = TouchSocketBitConverter.BigEndian.To(body.Slice(body.Length - 2, 2)); + + //计算CRC16 + var newCrc16 = Crc.Crc16Value(data); + if (crc16 != newCrc16) { - this.Body = body.ToArray(); - return true; + //CRC校验失败 + throw new Exception("CRC校验失败"); } - return false; - } - public bool OnParsingHeader(ReadOnlySpan header) - { - //在该示例中,第一个字节表示后续的所有数据长度,但是header设置的是3,所以后续还应当接收length-2个长度。 - this.BodyLength = header[0] - 2; - this.DataType = header[1]; - this.OrderType = header[2]; + this.Data = data.ToArray(); return true; } -} \ No newline at end of file + + bool IFixedHeaderRequestInfo.OnParsingHeader(ReadOnlySpan header) + { + //这里header长度已经经过验证,一定是4字节 + + //获取指令类型 + this.OrderType = header[0]; + + //获取数据类型 + this.DataType = header[1]; + + var payloadLength = TouchSocketBitConverter.BigEndian.To(header.Slice(2, 2)); + + + this.m_length = payloadLength + 2;//+2是因为还包含Crc16的长度 + + return true; + } +} +#endregion diff --git a/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/CustomJsonDataHandlingAdapterConsoleApp.csproj b/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/CustomJsonDataHandlingAdapterConsoleApp.csproj index 18c1c8753..e08d18664 100644 --- a/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/CustomJsonDataHandlingAdapterConsoleApp.csproj +++ b/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/CustomJsonDataHandlingAdapterConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/Program.cs b/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/Program.cs index 5e4cf3d29..8d4f05e7e 100644 --- a/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/Program.cs +++ b/examples/Adapter/CustomJsonDataHandlingAdapterConsoleApp/Program.cs @@ -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 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 +{ + public MyCustomJsonDataHandlingAdapter() : base(Encoding.UTF8) + { + } + + protected override MyJsonClass GetInstance(JsonPackageKind packageKind, Encoding encoding, ReadOnlyMemory dataMemory, ReadOnlyMemory impurityMemory) + { + return new MyJsonClass(packageKind, encoding, dataMemory, impurityMemory); + } +} internal class MyJsonClass : IRequestInfo { public MyJsonClass(JsonPackageKind packageKind, Encoding encoding, ReadOnlyMemory dataMemory, ReadOnlyMemory impurityMemory) @@ -92,14 +119,4 @@ internal class MyJsonClass : IRequestInfo public ReadOnlyMemory ImpurityMemory { get; } } -internal class MyCustomJsonDataHandlingAdapter : CustomJsonDataHandlingAdapter -{ - public MyCustomJsonDataHandlingAdapter() : base(Encoding.UTF8) - { - } - - protected override MyJsonClass GetInstance(JsonPackageKind packageKind, Encoding encoding, ReadOnlyMemory dataMemory, ReadOnlyMemory impurityMemory) - { - return new MyJsonClass(packageKind, encoding, dataMemory, impurityMemory); - } -} +#endregion diff --git a/examples/Adapter/CustomUnfixedHeaderConsoleApp/CustomUnfixedHeaderConsoleApp.csproj b/examples/Adapter/CustomUnfixedHeaderConsoleApp/CustomUnfixedHeaderConsoleApp.csproj index d6cfa539a..ddd0e8423 100644 --- a/examples/Adapter/CustomUnfixedHeaderConsoleApp/CustomUnfixedHeaderConsoleApp.csproj +++ b/examples/Adapter/CustomUnfixedHeaderConsoleApp/CustomUnfixedHeaderConsoleApp.csproj @@ -8,7 +8,7 @@ - + diff --git a/examples/Adapter/CustomUnfixedHeaderConsoleApp/Program.cs b/examples/Adapter/CustomUnfixedHeaderConsoleApp/Program.cs index 81e01c795..9cd1a45ec 100644 --- a/examples/Adapter/CustomUnfixedHeaderConsoleApp/Program.cs +++ b/examples/Adapter/CustomUnfixedHeaderConsoleApp/Program.cs @@ -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 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 +#region 创建自定义非固定包头适配器 +/// +/// 第1个字节表示指令类型 +/// 第2字节表示数据类型 +/// 第3字节表示后续数据的长度。使用ushort(大端)表示,最大长度为65535 +/// 后续字节表示载荷数据 +/// 最后2字节表示CRC16校验码 +/// +public class MyUnfixedHeaderCustomDataHandlingAdapter : CustomUnfixedHeaderDataHandlingAdapter { - protected override MyUnfixedHeaderRequestInfo GetInstance() + protected override MyDataClass GetInstance() { - return new MyUnfixedHeaderRequestInfo(); + return new MyDataClass(); } } -public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo +public class MyDataClass : IUnfixedHeaderRequestInfo { /// /// 接口实现,标识数据长度 @@ -114,53 +139,60 @@ public class MyUnfixedHeaderRequestInfo : IUnfixedHeaderRequestInfo /// /// 自定义属性,标识实际数据 /// - public byte[] Body { get; set; } - - + public byte[] Data { get; set; } public int HeaderLength { get; private set; } public bool OnParsingBody(ReadOnlySpan body) { - if (body.Length == this.BodyLength) + var data = body.Slice(0, body.Length - 2);//最后2个字节是CRC16校验码 + var crc16 = TouchSocketBitConverter.BigEndian.To(body.Slice(body.Length - 2, 2)); + + //计算CRC16 + var newCrc16 = Crc.Crc16Value(data); + if (crc16 != newCrc16) { - this.Body = body.ToArray(); - return true; + //CRC校验失败 + throw new Exception("CRC校验失败"); } - return false; + + this.Data = data.ToArray(); + return true; } - public bool OnParsingHeader(ref TByteBlock byteBlock) where TByteBlock : IByteBlock + public bool OnParsingHeader(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(header.Slice(2, 2)); + //【最后】对HeaderLength做有效赋值 - this.HeaderLength = 3; + this.HeaderLength = 4; + this.BodyLength = payloadLength + 2; return true; } } + +#endregion diff --git a/examples/Adapter/JsonPackageAdapterConsoleApp/JsonPackageAdapterConsoleApp.csproj b/examples/Adapter/JsonPackageAdapterConsoleApp/JsonPackageAdapterConsoleApp.csproj index ab8f18f2e..e79c4df47 100644 --- a/examples/Adapter/JsonPackageAdapterConsoleApp/JsonPackageAdapterConsoleApp.csproj +++ b/examples/Adapter/JsonPackageAdapterConsoleApp/JsonPackageAdapterConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/JsonPackageAdapterConsoleApp/Program.cs b/examples/Adapter/JsonPackageAdapterConsoleApp/Program.cs index af3bfb719..b656cf4e6 100644 --- a/examples/Adapter/JsonPackageAdapterConsoleApp/Program.cs +++ b/examples/Adapter/JsonPackageAdapterConsoleApp/Program.cs @@ -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 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)) diff --git a/examples/Adapter/MultipacketAdapterConsoleApp/MultipacketAdapterConsoleApp.csproj b/examples/Adapter/MultipacketAdapterConsoleApp/MultipacketAdapterConsoleApp.csproj new file mode 100644 index 000000000..a081538ee --- /dev/null +++ b/examples/Adapter/MultipacketAdapterConsoleApp/MultipacketAdapterConsoleApp.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/examples/Adapter/MultipacketAdapterConsoleApp/Program.cs b/examples/Adapter/MultipacketAdapterConsoleApp/Program.cs new file mode 100644 index 000000000..afe76e247 --- /dev/null +++ b/examples/Adapter/MultipacketAdapterConsoleApp/Program.cs @@ -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 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 GetTcpService() + { + var service = new TcpService(); + + service.Received = async (client, e) => + { + //从客户端收到信息 + switch (e.RequestInfo) + { + case MyPack1 pack: + { + Console.WriteLine($"收到MyPack1,MyProperty1={pack.MyProperty1}"); + break; + } + case MyPack2 pack: + { + Console.WriteLine($"收到MyPack2,MyProperty1={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 +{ + protected override FilterResult Filter(ref TReader reader, bool beCached, ref MyPackBase request) + { + if (reader.BytesRemaining < 5) + { + return FilterResult.Cache; + } + + var header = reader.GetSpan(5); + var type = header.ReadValue(); + + var length = header.ReadValue(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(json); + break; + case 2: + request = JsonConvert.DeserializeObject(json); + break; + default: + request = null; + break; + } + reader.Advance(length); + return FilterResult.Success; + } + + public override bool CanSendRequestInfo => true; + + public override void SendInput(ref TWriter writer, IRequestInfo requestInfo) + { + switch (requestInfo) + { + case MyPack1 pack1: + { + WriterExtension.WriteValue(ref writer, (byte)1); + var data = JsonConvert.SerializeObject(pack1); + WriterAnchor writerAnchor = new WriterAnchor(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 writerAnchor = new WriterAnchor(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; + } + } +} \ No newline at end of file diff --git a/examples/Adapter/PackageAdapterConsoleApp/PackageAdapterConsoleApp.csproj b/examples/Adapter/PackageAdapterConsoleApp/PackageAdapterConsoleApp.csproj index 897fb96ef..e08d18664 100644 --- a/examples/Adapter/PackageAdapterConsoleApp/PackageAdapterConsoleApp.csproj +++ b/examples/Adapter/PackageAdapterConsoleApp/PackageAdapterConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Adapter/PackageAdapterConsoleApp/Program.cs b/examples/Adapter/PackageAdapterConsoleApp/Program.cs index a5ef78c0b..2b66268c8 100644 --- a/examples/Adapter/PackageAdapterConsoleApp/Program.cs +++ b/examples/Adapter/PackageAdapterConsoleApp/Program.cs @@ -60,13 +60,16 @@ internal class Program private static async Task 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 memory) - { - //重写之后直接发送,当然也可以自己判断一些信息 - return this.GoSendAsync(memory); - } } \ No newline at end of file diff --git a/examples/Adapter/RawAdapterConsoleApp/Program.cs b/examples/Adapter/RawAdapterConsoleApp/Program.cs new file mode 100644 index 000000000..30bd5dd48 --- /dev/null +++ b/examples/Adapter/RawAdapterConsoleApp/Program.cs @@ -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 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 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 使用原始数据适配器解析 +/// +/// 第1个字节表示指令类型 +/// 第2字节表示数据类型 +/// 第3字节表示后续数据的长度。使用ushort(大端)表示,最大长度为65535 +/// 后续字节表示载荷数据 +/// 最后2字节表示CRC16校验码 +/// +internal class MyRawDataHandleAdapter : SingleStreamDataHandlingAdapter +{ + private MyDataClass m_myDataClass; + private int m_payloadLength; + protected override async Task PreviewReceivedAsync(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(header.Slice(2, 2)); + + await this.ParseData(reader); + } + else + { + //已经读取过头部,继续读取剩余数据 + await this.ParseData(reader); + } + } + } + + private async Task ParseData(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(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.Empty, this.m_myDataClass); + + //清空数据,准备下次接收 + this.m_myDataClass = null; + this.m_payloadLength = 0; + } +} + +/// +/// 定义数据对象 +/// +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 diff --git a/examples/Adapter/RawAdapterConsoleApp/RawAdapterConsoleApp.csproj b/examples/Adapter/RawAdapterConsoleApp/RawAdapterConsoleApp.csproj new file mode 100644 index 000000000..bde18f61d --- /dev/null +++ b/examples/Adapter/RawAdapterConsoleApp/RawAdapterConsoleApp.csproj @@ -0,0 +1,13 @@ + + + + Exe + net9.0 + + + + + + + + diff --git a/examples/Adapter/TLVWinFormsApp/Form1.Designer.cs b/examples/Adapter/TLVWinFormsApp/Form1.Designer.cs deleted file mode 100644 index 9b3e38786..000000000 --- a/examples/Adapter/TLVWinFormsApp/Form1.Designer.cs +++ /dev/null @@ -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 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - 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; - } -} \ No newline at end of file diff --git a/examples/Adapter/TLVWinFormsApp/Form1.cs b/examples/Adapter/TLVWinFormsApp/Form1.cs deleted file mode 100644 index 8a41286b1..000000000 --- a/examples/Adapter/TLVWinFormsApp/Form1.cs +++ /dev/null @@ -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) - { - //�����յ���Ϣ�¼� - this.m_tcpService.Received = (client, e) => - { - if (e.RequestInfo is TLVDataFrame frame) - { - client.Logger.Info($"�������յ�,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()//ʹ�ò�����൱���Զ�����������������������ӦPing�� - .SetLengthType(FixedHeaderType.Int);//����֧�ֵ�����������ͣ���ֵ����SetMaxPackageSizeӰ�졣 - }); - - //�������� - this.m_tcpService.SetupAsync(config); - - //���� - this.m_tcpService.StartAsync(); - this.m_tcpService.Logger.Info("�������ɹ�������"); - } - - 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))//���ʹ��TLVPlugin������˲����ʡ�ԡ� - .ConfigurePlugins(a => - { - a.Add()//ʹ�ò�����൱���Զ�����������������������ӦPing�� - .SetLengthType(FixedHeaderType.Int);//����֧�ֵ�����������ͣ���ֵ����SetMaxPackageSizeӰ�졣 - }) - .SetRemoteIPHost(new IPHost("127.0.0.1:7789"))); - this.m_client.ConnectAsync(); - - this.m_client.Logger.Info("���ӳɹ�"); - } - - 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); - } - } - } -} \ No newline at end of file diff --git a/examples/Adapter/TLVWinFormsApp/Form1.resx b/examples/Adapter/TLVWinFormsApp/Form1.resx deleted file mode 100644 index f298a7be8..000000000 --- a/examples/Adapter/TLVWinFormsApp/Form1.resx +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/examples/Adapter/TLVWinFormsApp/Program.cs b/examples/Adapter/TLVWinFormsApp/Program.cs deleted file mode 100644 index ef96b0a85..000000000 --- a/examples/Adapter/TLVWinFormsApp/Program.cs +++ /dev/null @@ -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 -{ - /// - /// The main entry point for the application. - /// - [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()); - } -} \ No newline at end of file diff --git a/examples/Adapter/TLVWinFormsApp/TLVWinFormsApp.csproj b/examples/Adapter/TLVWinFormsApp/TLVWinFormsApp.csproj deleted file mode 100644 index 7ee6b3fe9..000000000 --- a/examples/Adapter/TLVWinFormsApp/TLVWinFormsApp.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - WinExe - net9.0-windows - enable - true - enable - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/AvaloniaApplication.Browser.csproj b/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/AvaloniaApplication.Browser.csproj index aca3c80fe..3e01a4482 100644 --- a/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/AvaloniaApplication.Browser.csproj +++ b/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/AvaloniaApplication.Browser.csproj @@ -1,4 +1,4 @@ - + net8.0-browser Exe @@ -6,7 +6,7 @@ - + diff --git a/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/Program.cs b/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/Program.cs index 5aa934a53..b44532a8a 100644 --- a/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/Program.cs +++ b/examples/AvaloniaApplication/Client/AvaloniaApplication.Browser/Program.cs @@ -1,4 +1,4 @@ -using System.Runtime.Versioning; +using System.Runtime.Versioning; using System.Threading.Tasks; using Avalonia; diff --git a/examples/AvaloniaApplication/Client/AvaloniaApplication.Desktop/AvaloniaApplication.Desktop.csproj b/examples/AvaloniaApplication/Client/AvaloniaApplication.Desktop/AvaloniaApplication.Desktop.csproj index b204ca110..bedc7120d 100644 --- a/examples/AvaloniaApplication/Client/AvaloniaApplication.Desktop/AvaloniaApplication.Desktop.csproj +++ b/examples/AvaloniaApplication/Client/AvaloniaApplication.Desktop/AvaloniaApplication.Desktop.csproj @@ -1,4 +1,4 @@ - + WinExe diff --git a/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/MainViewModel.cs b/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/MainViewModel.cs index db42d4862..db5e2ed1f 100644 --- a/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/MainViewModel.cs +++ b/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/MainViewModel.cs @@ -1,4 +1,4 @@ -using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Input; using System; using System.Diagnostics; using System.Runtime.Intrinsics.Arm; diff --git a/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/ViewModelBase.cs b/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/ViewModelBase.cs index 619a659af..651abaa7f 100644 --- a/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/ViewModelBase.cs +++ b/examples/AvaloniaApplication/Client/AvaloniaApplication/ViewModels/ViewModelBase.cs @@ -1,4 +1,4 @@ -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.ComponentModel; namespace AvaloniaApplication.ViewModels; diff --git a/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainView.axaml.cs b/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainView.axaml.cs index f3bf2901f..9fa666bd0 100644 --- a/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainView.axaml.cs +++ b/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainView.axaml.cs @@ -1,4 +1,4 @@ -using Avalonia.Controls; +using Avalonia.Controls; namespace AvaloniaApplication.Views; diff --git a/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainWindow.axaml.cs b/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainWindow.axaml.cs index af15ba0ef..b5e74a501 100644 --- a/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainWindow.axaml.cs +++ b/examples/AvaloniaApplication/Client/AvaloniaApplication/Views/MainWindow.axaml.cs @@ -1,4 +1,4 @@ -using Avalonia.Controls; +using Avalonia.Controls; namespace AvaloniaApplication.Views; diff --git a/examples/AvaloniaApplication/Server/WebServerApplication/AssemblyInfo.cs b/examples/AvaloniaApplication/Server/WebServerApplication/AssemblyInfo.cs index 400990bad..ce024bed7 100644 --- a/examples/AvaloniaApplication/Server/WebServerApplication/AssemblyInfo.cs +++ b/examples/AvaloniaApplication/Server/WebServerApplication/AssemblyInfo.cs @@ -1,3 +1,3 @@ -using TouchSocket.Rpc; +using TouchSocket.Rpc; [assembly: GeneratorRpcServerRegister] \ No newline at end of file diff --git a/examples/AvaloniaApplication/Server/WebServerApplication/Plugins/MyDmtpPlugin.cs b/examples/AvaloniaApplication/Server/WebServerApplication/Plugins/MyDmtpPlugin.cs index 09c4fe588..2f9b787e4 100644 --- a/examples/AvaloniaApplication/Server/WebServerApplication/Plugins/MyDmtpPlugin.cs +++ b/examples/AvaloniaApplication/Server/WebServerApplication/Plugins/MyDmtpPlugin.cs @@ -1,4 +1,4 @@ -using TouchSocket.Core; +using TouchSocket.Core; namespace WebServerApplication.Plugins { diff --git a/examples/AvaloniaApplication/Server/WebServerApplication/Program.cs b/examples/AvaloniaApplication/Server/WebServerApplication/Program.cs index 74558060f..2137d0da3 100644 --- a/examples/AvaloniaApplication/Server/WebServerApplication/Program.cs +++ b/examples/AvaloniaApplication/Server/WebServerApplication/Program.cs @@ -33,7 +33,7 @@ namespace WebServerApplication .ConfigurePlugins(a => { a.UseDmtpRpc(); - //Ӳ + //��Ӳ�� a.Add(); }); }); @@ -41,7 +41,7 @@ namespace WebServerApplication var app = builder.Build(); app.UseWebSockets(); - app.UseWebSocketDmtp("/WebSocketDmtp");//WebSocketDmtpUseWebSockets֮ʹá + app.UseWebSocketDmtp("/WebSocketDmtp");//WebSocketDmtp������UseWebSockets֮��ʹ�á� app.Run("http://localhost:5043"); } diff --git a/examples/AvaloniaApplication/Server/WebServerApplication/RpcServers/MyRpcServer.cs b/examples/AvaloniaApplication/Server/WebServerApplication/RpcServers/MyRpcServer.cs index b6ed034fe..ea5c2ed72 100644 --- a/examples/AvaloniaApplication/Server/WebServerApplication/RpcServers/MyRpcServer.cs +++ b/examples/AvaloniaApplication/Server/WebServerApplication/RpcServers/MyRpcServer.cs @@ -1,4 +1,4 @@ -using RpcLibrary.Shared.RpcServers; +using RpcLibrary.Shared.RpcServers; using System.ComponentModel; using TouchSocket.Dmtp.Rpc; using TouchSocket.Rpc; diff --git a/examples/AvaloniaApplication/Server/WebServerApplication/WebServerApplication.csproj b/examples/AvaloniaApplication/Server/WebServerApplication/WebServerApplication.csproj index 9996fbad4..02b8cdb7d 100644 --- a/examples/AvaloniaApplication/Server/WebServerApplication/WebServerApplication.csproj +++ b/examples/AvaloniaApplication/Server/WebServerApplication/WebServerApplication.csproj @@ -7,7 +7,7 @@ - + diff --git a/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcLibrary.Shared.csproj b/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcLibrary.Shared.csproj index dfd43e166..a9fe383fd 100644 --- a/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcLibrary.Shared.csproj +++ b/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcLibrary.Shared.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -7,7 +7,7 @@ - + diff --git a/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcServers/IMyRpcServer.cs b/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcServers/IMyRpcServer.cs index 7255f84ca..ff96ab0b9 100644 --- a/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcServers/IMyRpcServer.cs +++ b/examples/AvaloniaApplication/Shared/RpcLibrary.Shared/RpcServers/IMyRpcServer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; diff --git a/examples/BlogsDemos/AccessRestrictionsConsoleApp/AccessRestrictionsConsoleApp.csproj b/examples/BlogsDemos/AccessRestrictionsConsoleApp/AccessRestrictionsConsoleApp.csproj index f18b62f22..6608859ea 100644 --- a/examples/BlogsDemos/AccessRestrictionsConsoleApp/AccessRestrictionsConsoleApp.csproj +++ b/examples/BlogsDemos/AccessRestrictionsConsoleApp/AccessRestrictionsConsoleApp.csproj @@ -8,12 +8,12 @@ - - - - - - + + + + + + diff --git a/examples/BlogsDemos/AccessRestrictionsConsoleApp/Program.cs b/examples/BlogsDemos/AccessRestrictionsConsoleApp/Program.cs index dc1b22e1e..042905c88 100644 --- a/examples/BlogsDemos/AccessRestrictionsConsoleApp/Program.cs +++ b/examples/BlogsDemos/AccessRestrictionsConsoleApp/Program.cs @@ -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; }; diff --git a/examples/BlogsDemos/DifferentProtocolConsoleApp/DifferentProtocolConsoleApp.csproj b/examples/BlogsDemos/DifferentProtocolConsoleApp/DifferentProtocolConsoleApp.csproj index f18b62f22..6608859ea 100644 --- a/examples/BlogsDemos/DifferentProtocolConsoleApp/DifferentProtocolConsoleApp.csproj +++ b/examples/BlogsDemos/DifferentProtocolConsoleApp/DifferentProtocolConsoleApp.csproj @@ -8,12 +8,12 @@ - - - - - - + + + + + + diff --git a/examples/BlogsDemos/DifferentProtocolConsoleApp/Program.cs b/examples/BlogsDemos/DifferentProtocolConsoleApp/Program.cs index 5062304a1..3a964ec54 100644 --- a/examples/BlogsDemos/DifferentProtocolConsoleApp/Program.cs +++ b/examples/BlogsDemos/DifferentProtocolConsoleApp/Program.cs @@ -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(); diff --git a/examples/BlogsDemos/HeartbeatConsoleApp/HeartbeatConsoleApp.csproj b/examples/BlogsDemos/HeartbeatConsoleApp/HeartbeatConsoleApp.csproj index fc9dcd098..7b83a0896 100644 --- a/examples/BlogsDemos/HeartbeatConsoleApp/HeartbeatConsoleApp.csproj +++ b/examples/BlogsDemos/HeartbeatConsoleApp/HeartbeatConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,6 @@ - + diff --git a/examples/BlogsDemos/HeartbeatConsoleApp/Program.cs b/examples/BlogsDemos/HeartbeatConsoleApp/Program.cs index d99fcfc1a..489adb607 100644 --- a/examples/BlogsDemos/HeartbeatConsoleApp/Program.cs +++ b/examples/BlogsDemos/HeartbeatConsoleApp/Program.cs @@ -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(); } diff --git a/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/LimitNumberOfConnectionsConsoleApp.csproj b/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/LimitNumberOfConnectionsConsoleApp.csproj index 3690c4a0f..11bc9a8a2 100644 --- a/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/LimitNumberOfConnectionsConsoleApp.csproj +++ b/examples/BlogsDemos/LimitNumberOfConnectionsConsoleApp/LimitNumberOfConnectionsConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,12 +6,12 @@ - - - - - - + + + + + + diff --git a/examples/BlogsDemos/ThrottlingConsoleApp/Program.cs b/examples/BlogsDemos/ThrottlingConsoleApp/Program.cs index 14c9c6156..e03e20265 100644 --- a/examples/BlogsDemos/ThrottlingConsoleApp/Program.cs +++ b/examples/BlogsDemos/ThrottlingConsoleApp/Program.cs @@ -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(); } } \ No newline at end of file diff --git a/examples/BlogsDemos/ThrottlingConsoleApp/ThrottlingConsoleApp.csproj b/examples/BlogsDemos/ThrottlingConsoleApp/ThrottlingConsoleApp.csproj index 3690c4a0f..11bc9a8a2 100644 --- a/examples/BlogsDemos/ThrottlingConsoleApp/ThrottlingConsoleApp.csproj +++ b/examples/BlogsDemos/ThrottlingConsoleApp/ThrottlingConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,12 +6,12 @@ - - - - - - + + + + + + diff --git a/examples/BlogsDemos/TrafficCounterConsoleApp/Program.cs b/examples/BlogsDemos/TrafficCounterConsoleApp/Program.cs index b157d663d..e1ea3a7a5 100644 --- a/examples/BlogsDemos/TrafficCounterConsoleApp/Program.cs +++ b/examples/BlogsDemos/TrafficCounterConsoleApp/Program.cs @@ -92,7 +92,7 @@ internal class Program // protected override void OnReceivingData(ITcpSession client, ByteBlockEventArgs e) // { // client.SetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty, -// e.ByteBlock.Length + +client.GetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty)); +// e.Memory.Length + +client.GetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty)); // base.OnReceivingData(client, e); // } //} diff --git a/examples/BlogsDemos/TrafficCounterConsoleApp/TrafficCounterConsoleApp.csproj b/examples/BlogsDemos/TrafficCounterConsoleApp/TrafficCounterConsoleApp.csproj index 6074e652c..fe6b0d27d 100644 --- a/examples/BlogsDemos/TrafficCounterConsoleApp/TrafficCounterConsoleApp.csproj +++ b/examples/BlogsDemos/TrafficCounterConsoleApp/TrafficCounterConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,11 +6,11 @@ - - - - - - + + + + + + diff --git a/examples/Consul集群示例/ConsulConsoleApp/ConsulConsoleApp.csproj b/examples/Consul集群示例/ConsulConsoleApp/ConsulConsoleApp.csproj index b08beb96c..6ff43a4b2 100644 --- a/examples/Consul集群示例/ConsulConsoleApp/ConsulConsoleApp.csproj +++ b/examples/Consul集群示例/ConsulConsoleApp/ConsulConsoleApp.csproj @@ -6,13 +6,13 @@ - - - - - - - + + + + + + + diff --git a/examples/Consul集群示例/ConsulConsoleApp/Program.cs b/examples/Consul集群示例/ConsulConsoleApp/Program.cs index 1c0f8ffa6..d34a8bbe5 100644 --- a/examples/Consul集群示例/ConsulConsoleApp/Program.cs +++ b/examples/Consul集群示例/ConsulConsoleApp/Program.cs @@ -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);//将收到的信息直接返回给发送方 diff --git a/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/Program.cs b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/Program.cs index fc6770b3a..386d82dd3 100644 --- a/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/Program.cs +++ b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/Program.cs @@ -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();//添加WebSocket业务数据接收插件 a.Add();//添加WebSocket快捷实现,常规WS客户端发送文本“Add 10 20”即可得到30。 }) @@ -149,9 +154,9 @@ internal class MyWebSocketCommand : WebSocketCommandLinePlugin /// /// WS收到数据等业务。 /// -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) { diff --git a/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/ServiceConsoleApp.csproj b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/ServiceConsoleApp.csproj index b08beb96c..2837b700d 100644 --- a/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/ServiceConsoleApp.csproj +++ b/examples/Consul集群示例/TouchRpc Consul集群/ServiceConsoleApp/ServiceConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,13 +6,13 @@ - - - - - - - + + + + + + + diff --git a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.cs b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.cs index 6590df36a..373dd68ee 100644 --- a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.cs +++ b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/Form1.cs @@ -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; diff --git a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/WinFormsApp.csproj b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/WinFormsApp.csproj index 1b5c1eb3f..d0df5149b 100644 --- a/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/WinFormsApp.csproj +++ b/examples/Consul集群示例/TouchRpc Consul集群/WinFormsApp/WinFormsApp.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -7,13 +7,13 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/examples/Core/AotDynamicMethodConsoleApp/AotDynamicMethodConsoleApp.csproj b/examples/Core/AotDynamicMethodConsoleApp/AotDynamicMethodConsoleApp.csproj index 19b8dd53a..0584dd0a2 100644 --- a/examples/Core/AotDynamicMethodConsoleApp/AotDynamicMethodConsoleApp.csproj +++ b/examples/Core/AotDynamicMethodConsoleApp/AotDynamicMethodConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -13,6 +13,6 @@ - + diff --git a/examples/Core/AotDynamicMethodConsoleApp/Program.cs b/examples/Core/AotDynamicMethodConsoleApp/Program.cs index 151988ea6..9c2eec471 100644 --- a/examples/Core/AotDynamicMethodConsoleApp/Program.cs +++ b/examples/Core/AotDynamicMethodConsoleApp/Program.cs @@ -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) + /// + /// 注册所有示例命令 + /// + 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调用", TaskObjectRun); } - static void SimpleRun() + /// + /// 全局异常处理 + /// + private static void OnException(Exception ex) { - Method method = new Method(typeof(MyClass), nameof(MyClass.Run)); - - MyClass myClass = new MyClass(); - method.Invoke(myClass); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"错误: {ex.Message}"); + Console.ResetColor(); } - static void ILRun() + /// + /// 示例1: 简单的方法调用 + /// + private static void SimpleRun() { - Method method = new Method(typeof(MyClass), nameof(MyClass.Run), DynamicBuilderType.IL); + Console.WriteLine("=== 简单调用示例 ==="); - MyClass myClass = new MyClass(); - method.Invoke(myClass); - } - static void ExpressionRun() - { - Method method = new Method(typeof(MyClass), nameof(MyClass.Run), DynamicBuilderType.Expression); + #region 简单调用示例 + var method = new Method(typeof(MyClass), nameof(MyClass.Run)); + var instance = new MyClass(); + method.Invoke(instance); + #endregion - MyClass myClass = new MyClass(); - method.Invoke(myClass); + Console.WriteLine("调用完成!"); } - static void ReflectRun() + /// + /// 示例2: 性能测试 + /// + private static void Performance() { - Method method = new Method(typeof(MyClass), nameof(MyClass.Run), DynamicBuilderType.Reflect); + Console.WriteLine("=== 性能测试 ==="); + Console.WriteLine($"将执行 {DefaultPerformanceTestCount:N0} 次方法调用...\n"); - MyClass myClass = new MyClass(); - method.Invoke(myClass); - } + #region 性能测试代码 + var myClass = new MyClass(); + var method = new Method(typeof(MyClass), nameof(MyClass.Performance)); + var stopwatch = Stopwatch.StartNew(); - 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) + for (var i = 0; i < 10_000_000; i++) { - stopwatch.Restart(); - try - { - var method = item; - for (int i = 0; i < count; i++) - { - method.Invoke(myClass); - } - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - finally - { - stopwatch.Stop(); - Console.WriteLine($"Method BuilderType={item.DynamicBuilderType},Time={stopwatch.ElapsedMilliseconds}"); - } + method.Invoke(myClass); } + stopwatch.Stop(); + Console.WriteLine($"总耗时: {stopwatch.ElapsedMilliseconds} ms"); + #endregion + + try + { + 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) + { + stopwatch.Stop(); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"✗ 性能测试失败: {ex.Message}"); + Console.WriteLine($" 已完成部分测试,耗时: {stopwatch.ElapsedMilliseconds:N0} ms"); + Console.ResetColor(); + } } - static void MultiParameters() + /// + /// 示例3: 多参数调用,包括 out 和 ref 参数 + /// + 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(); - foreach (var item in methods) + 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]}"); + + try { - object[] ps = new object[] { "hello", 0, 200 }; - try + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"调用后参数: a=\"{parameters[0]}\", b={parameters[1]}, c={parameters[2]}"); + Console.ResetColor(); + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"调用失败: {ex.Message}"); + Console.ResetColor(); + } + } + + /// + /// 示例4: 使用自定义特性的动态方法调用 + /// + private static void CustomDynamicMethod() + { + Console.WriteLine("=== 自定义动态方法调用示例 ==="); + + #region 自定义特性调用 + var method = new Method(typeof(MyClass), nameof(MyClass.CustomDynamicMethod)); + var instance = new MyClass(); + method.Invoke(instance); + #endregion + + try + { + Console.WriteLine("自定义动态方法调用成功!"); + } + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"调用失败: {ex.Message}"); + Console.ResetColor(); + } + } + + /// + /// 示例5: 异步 Task 方法调用 + /// + private static async Task TaskRun() + { + Console.WriteLine("=== 异步Task调用示例 ==="); + + #region 异步Task调用 + var method = new Method(typeof(MyClass), nameof(MyClass.TaskRun)); + var instance = new MyClass(); + + // 判断是否为异步方法 + if (method.IsAwaitable) + { + await method.InvokeAsync(instance); + } + #endregion + + Console.WriteLine($"方法是否可等待: {method.IsAwaitable}"); + Console.WriteLine($"返回类型: {method.ReturnKind}"); + + try + { + if (method.IsAwaitable) { - var method = item; - method.Invoke(myClass, ps); + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("异步调用完成!"); + Console.ResetColor(); } - catch (Exception ex) + else { - Console.WriteLine(ex.Message); - } - finally - { - Console.WriteLine($"Method BuilderType={item.DynamicBuilderType},ps0={ps[0]},ps1={ps[1]},ps2={ps[2]}"); + Console.WriteLine("该方法不是异步方法"); } } - + catch (Exception ex) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"异步调用失败: {ex.Message}"); + Console.ResetColor(); + } } - static void CustomDynamicMethod() + /// + /// 示例6: 异步 Task 方法调用(带返回值) + /// + private static async Task TaskObjectRun() { - MyClass myClass = new MyClass(); + Console.WriteLine("=== 异步Task调用示例 ==="); - var methods = GetMethods(typeof(MyClass), nameof(MyClass.CustomDynamicMethod)); + #region 异步Task泛型调用 + var method = new Method(typeof(MyClass), nameof(MyClass.TaskObjectRun)); + var instance = new MyClass(); - foreach (var item in methods) + if (method.ReturnKind == MethodReturnKind.AwaitableObject) { - try + var result = await method.InvokeAsync(instance); + Console.WriteLine($"返回值: {result}"); // 输出: 返回值: 10 + } + #endregion + + Console.WriteLine($"方法返回类型: {method.ReturnKind}"); + Console.WriteLine($"实际返回值类型: {method.RealReturnType?.Name ?? "void"}"); + + try + { + if (method.ReturnKind == MethodReturnKind.AwaitableObject) { - var method = item; - method.Invoke(myClass); + var result2 = await method.InvokeAsync(instance); + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"异步调用完成,返回值: {result2}"); + Console.ResetColor(); } - catch (Exception ex) + else { - Console.WriteLine(ex.Message); - } - finally - { - Console.WriteLine($"Method BuilderType={item.DynamicBuilderType}"); + Console.WriteLine("该方法不返回异步对象"); } } - - } - - static async Task TaskRun() - { - MyClass myClass = new MyClass(); - - var methods = GetMethods(typeof(MyClass), nameof(MyClass.TaskRun)); - - foreach (var item in methods) + catch (Exception ex) { - try - { - var method = item; - if (method.IsAwaitable) - { - await method.InvokeAsync(myClass); - } - } - 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() - { - MyClass myClass = new MyClass(); - - var methods = GetMethods(typeof(MyClass), nameof(MyClass.TaskObjectRun)); - - foreach (var item in methods) - { - try - { - var method = item; - if (method.ReturnKind == MethodReturnKind.AwaitableObject) - { - var result = await method.InvokeAsync(myClass); - Console.WriteLine($"result={result}"); - } - - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - finally - { - Console.WriteLine($"Method BuilderType={item.DynamicBuilderType}"); - } - } - - } - - static List GetMethods(Type type, string name) - { - var methods = new List(); - foreach (var item in Enum.GetValues(typeof(DynamicBuilderType)).OfType()) - { - try - { - methods.Add(new Method(type, name, item)); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - } - - return methods; - } - - static bool IsDynamicCodeCompiled() - { -#if NET8_0_OR_GREATER - return RuntimeFeature.IsDynamicCodeCompiled; -#else - return true; -#endif } } +/// +/// 测试类,包含各种类型的动态方法 +/// +#region 标记方法示例 public class MyClass { + /// + /// 简单的void方法 + /// [DynamicMethod] public void Run() { - Console.WriteLine("Run"); + Console.WriteLine("Run 方法被调用"); } + #endregion + /// + /// 用于性能测试的空方法 + /// + #region 性能测试声明 [DynamicMethod] public void Performance() { - + // 空方法体,用于性能测试 } + #endregion + /// + /// 包含多种参数类型的方法:普通参数、out参数、ref参数 + /// + #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 + /// + /// 使用自定义特性标记的方法 + /// [MyDynamicMethod] public void CustomDynamicMethod() { - Console.WriteLine("CustomDynamicMethod"); + Console.WriteLine("CustomDynamicMethod 方法被调用(使用自定义特性)"); } + /// + /// 异步Task方法(无返回值) + /// + #region 异步Task调用声明 [DynamicMethod] public async Task TaskRun() { - Console.WriteLine("TaskRun"); - await Task.CompletedTask; + Console.WriteLine("开始执行..."); + await Task.Delay(100); + Console.WriteLine("执行完成"); } + #endregion + /// + /// 异步Task方法(有返回值) + /// + #region 异步Task泛型调用声明 [DynamicMethod] public async Task TaskObjectRun() { - Console.WriteLine("TaskObjectRun"); - await Task.CompletedTask; + await Task.Delay(100); return 10; } + #endregion } +/// +/// 自定义的动态方法特性 +/// +#region 自定义特性声明 [DynamicMethod] [AttributeUsage(AttributeTargets.Method)] public class MyDynamicMethodAttribute : Attribute { } +#endregion + +#region 缓存Method实例推荐 +/// +/// 推荐的缓存方式:将Method实例缓存为静态字段,避免重复创建 +/// +public static class MethodCache +{ + public static readonly Method RunMethod = new Method(typeof(MyClass), nameof(MyClass.Run)); + + // 使用示例: + // MethodCache.RunMethod.Invoke(instance); +} +#endregion \ No newline at end of file diff --git a/examples/Core/AotFastBinaryFormatterConsoleApp/AotFastBinaryFormatterConsoleApp.csproj b/examples/Core/AotFastBinaryFormatterConsoleApp/AotFastBinaryFormatterConsoleApp.csproj index 0a87c9d1f..fc5d9f24e 100644 --- a/examples/Core/AotFastBinaryFormatterConsoleApp/AotFastBinaryFormatterConsoleApp.csproj +++ b/examples/Core/AotFastBinaryFormatterConsoleApp/AotFastBinaryFormatterConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -10,7 +10,7 @@ - + - + diff --git a/examples/Core/FastBinaryFormatterConsoleApp/Program.cs b/examples/Core/FastBinaryFormatterConsoleApp/Program.cs index 15f1ab8df..094d67653 100644 --- a/examples/Core/FastBinaryFormatterConsoleApp/Program.cs +++ b/examples/Core/FastBinaryFormatterConsoleApp/Program.cs @@ -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(bytes); + } + #endregion + + #region FastBinary兼容类型使用 public static void TestMyClass2_3() { var myClass2 = new MyClass2() @@ -36,9 +59,8 @@ internal class Program var newObj = FastBinaryFormatter.Deserialize(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 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(block); - - Console.WriteLine($"ByteBlock反序列化“{typeof(TValue)}”完成,Value={newObj.ToJsonString()}"); } } + #endregion + #region FastBinary使用值类型内存池块 public static void SerializeAndDeserializeFromValueByteBlock(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(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 value) { var bytes = FastBinaryFormatter.SerializeToBytes(value); - - Console.WriteLine($"Bytes序列化“{typeof(TValue)}”完成,数据长度={bytes.Length}"); - - var newObj = FastBinaryFormatter.Deserialize(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 { protected override MyClass5 Read(ref TByteBlock byteBlock, Type type) @@ -199,8 +226,8 @@ public sealed class MyClass5FastBinaryConverter : FastBinaryConverter //我们只需要把有效信息按写入的顺序,读取即可。 var myClass5 = new MyClass5(); - myClass5.P1 = byteBlock.ReadInt32(); - myClass5.P2 = byteBlock.ReadInt32(); + myClass5.P1 = ReaderExtension.ReadValue(ref byteBlock); + myClass5.P2 = ReaderExtension.ReadValue(ref byteBlock); return myClass5; } @@ -212,16 +239,17 @@ public sealed class MyClass5FastBinaryConverter : FastBinaryConverter //对于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 diff --git a/examples/Core/IocConsoleApp/AdvancedContainer.cs b/examples/Core/IocConsoleApp/AdvancedContainer.cs new file mode 100644 index 000000000..4160a0383 --- /dev/null +++ b/examples/Core/IocConsoleApp/AdvancedContainer.cs @@ -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; + +/// +/// 高级IOC容器示例 +/// +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(); + aspNetCoreContainer.RegisterSingleton(); + + aspNetCoreContainer.BuildResolver(); + + var myClass1 = aspNetCoreContainer.Resolve(); + var myClass2 = aspNetCoreContainer.Resolve(); + #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(); + + var service = container.Resolve(); + 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)container.Resolve(typeof(IRepository)); + var productRepo = (IRepository)container.Resolve(typeof(IRepository)); + + 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 +{ + void Save(T entity); +} + +internal class Repository : IRepository +{ + 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 diff --git a/examples/Core/IocConsoleApp/IocConsoleApp.csproj b/examples/Core/IocConsoleApp/IocConsoleApp.csproj index 633c18c88..2e7f1f96a 100644 --- a/examples/Core/IocConsoleApp/IocConsoleApp.csproj +++ b/examples/Core/IocConsoleApp/IocConsoleApp.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/examples/Core/IocConsoleApp/NormalContainer.cs b/examples/Core/IocConsoleApp/NormalContainer.cs index 02b1c864a..33f2d12da 100644 --- a/examples/Core/IocConsoleApp/NormalContainer.cs +++ b/examples/Core/IocConsoleApp/NormalContainer.cs @@ -23,8 +23,11 @@ internal static class NormalContainer public static void Run() { ConstructorInject(); - PropertyInject(); - MethodInject(); + SingletonLifetime(); + TransientLifetime(); + ScopedLifetime(); + RegisterWithKey(); + RegisterWithFactory(); } /// @@ -32,53 +35,124 @@ internal static class NormalContainer /// private static void ConstructorInject() { - var container = GetContainer(); + #region IOC构造函数注入 + var container = new Container(); container.RegisterSingleton(); container.RegisterSingleton(); var myClass1 = container.Resolve(); var myClass2 = container.Resolve(); + #endregion Console.WriteLine(MethodBase.GetCurrentMethod().Name); } /// - /// 属性注入 + /// 单例生命周期 /// - private static void PropertyInject() + private static void SingletonLifetime() { - var container = GetContainer(); + #region IOC单例生命周期 + var container = new Container(); container.RegisterSingleton(); - container.RegisterSingleton("key"); - container.RegisterSingleton(); - container.RegisterSingleton(); + var instance1 = container.Resolve(); + var instance2 = container.Resolve(); + // instance1 和 instance2 是同一个实例 + Console.WriteLine($"Singleton: {ReferenceEquals(instance1, instance2)}"); // True + #endregion - var myClass3 = container.Resolve(); Console.WriteLine(MethodBase.GetCurrentMethod().Name); } /// - /// 方法注入 + /// 瞬态生命周期 /// - private static void MethodInject() + private static void TransientLifetime() { - var container = GetContainer(); - container.RegisterSingleton(); - container.RegisterSingleton(); + #region IOC瞬态生命周期 + var container = new Container(); + container.RegisterTransient(); + + var instance1 = container.Resolve(); + var instance2 = container.Resolve(); + // instance1 和 instance2 是不同的实例 + Console.WriteLine($"Transient: {ReferenceEquals(instance1, instance2)}"); // False + #endregion - var myClass4 = container.Resolve(); Console.WriteLine(MethodBase.GetCurrentMethod().Name); } - private static IContainer GetContainer() + /// + /// 作用域生命周期 + /// + private static void ScopedLifetime() { - return new Container();//默认IOC容器 + #region IOC作用域生命周期 + var container = new Container(); + container.RegisterScoped(); - //return new AspNetCoreContainer(new ServiceCollection());//使用Aspnetcore的容器 + // 在同一作用域内是同一实例 + using (var scope = container.CreateScopedResolver()) + { + var instance1 = scope.Resolver.Resolve(); + var instance2 = scope.Resolver.Resolve(); + Console.WriteLine($"Scoped (same scope): {ReferenceEquals(instance1, instance2)}"); // True + } + + // 在不同作用域内是不同实例 + using (var scope1 = container.CreateScopedResolver()) + using (var scope2 = container.CreateScopedResolver()) + { + var instance1 = scope1.Resolver.Resolve(); + var instance2 = scope2.Resolver.Resolve(); + Console.WriteLine($"Scoped (different scopes): {ReferenceEquals(instance1, instance2)}"); // False + } + #endregion + + Console.WriteLine(MethodBase.GetCurrentMethod().Name); + } + + /// + /// 使用Key注册 + /// + private static void RegisterWithKey() + { + #region IOC使用Key注册 + var container = new Container(); + container.RegisterSingleton(); + container.RegisterSingleton("specialKey"); + + var defaultInstance = container.Resolve(); + var keyedInstance = container.Resolve("specialKey"); + // 不同的注册,不同的实例 + Console.WriteLine($"Keyed: {ReferenceEquals(defaultInstance, keyedInstance)}"); // False + #endregion + + Console.WriteLine(MethodBase.GetCurrentMethod().Name); + } + + /// + /// 使用工厂方法注册 + /// + private static void RegisterWithFactory() + { + #region IOC使用工厂方法注册 + var container = new Container(); + container.RegisterSingleton(resolver => + { + Console.WriteLine("Creating MyClass1 using factory"); + return new MyClass1(); + }); + + var instance = container.Resolve(); + #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 -{ - /// - /// 直接按类型,默认方式获取 - /// - [DependencyInject] - public MyClass1 MyClass1 { get; set; } - - /// - /// 获得指定类型的对象,然后赋值到object - /// - [DependencyInject(typeof(MyClass2))] - public object MyClass2 { get; set; } - - /// - /// 按照类型+Key获取 - /// - [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; - } -} \ No newline at end of file +#endregion \ No newline at end of file diff --git a/examples/Core/IocConsoleApp/Program.cs b/examples/Core/IocConsoleApp/Program.cs index 11bbf3d1a..21130d179 100644 --- a/examples/Core/IocConsoleApp/Program.cs +++ b/examples/Core/IocConsoleApp/Program.cs @@ -16,8 +16,9 @@ internal class Program { private static void Main(string[] args) { - NormalContainer.Run();// 常规Ioc容器,使用IL和反射实现,支持运行时注册和获取 - + NormalContainer.Run(); + AdvancedContainer.Run(); + Console.ReadKey(); } } \ No newline at end of file diff --git a/examples/Core/Log4netConsoleApp/Log4netConsoleApp.csproj b/examples/Core/Log4netConsoleApp/Log4netConsoleApp.csproj index 0c986496b..c96d3bd5d 100644 --- a/examples/Core/Log4netConsoleApp/Log4netConsoleApp.csproj +++ b/examples/Core/Log4netConsoleApp/Log4netConsoleApp.csproj @@ -8,13 +8,13 @@ - - - - - - - + + + + + + + diff --git a/examples/Core/Log4netConsoleApp/Program.cs b/examples/Core/Log4netConsoleApp/Program.cs index a8d2c2b92..8c47fb494 100644 --- a/examples/Core/Log4netConsoleApp/Program.cs +++ b/examples/Core/Log4netConsoleApp/Program.cs @@ -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; @@ -108,4 +125,5 @@ internal class Mylog4netLogger : LoggerBase break; } } -} \ No newline at end of file +} +#endregion \ No newline at end of file diff --git a/examples/Core/LoggerConsoleApp/LoggerConsoleApp.csproj b/examples/Core/LoggerConsoleApp/LoggerConsoleApp.csproj index 897fb96ef..e08d18664 100644 --- a/examples/Core/LoggerConsoleApp/LoggerConsoleApp.csproj +++ b/examples/Core/LoggerConsoleApp/LoggerConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Core/LoggerConsoleApp/Program.cs b/examples/Core/LoggerConsoleApp/Program.cs index bc426fdad..e1eee1e4e 100644 --- a/examples/Core/LoggerConsoleApp/Program.cs +++ b/examples/Core/LoggerConsoleApp/Program.cs @@ -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 diff --git a/examples/Tcp/ReuseAddressServerConsoleApp/ReuseAddressServerConsoleApp.csproj b/examples/Core/OtherCoreConsoleApp/OtherCoreConsoleApp.csproj similarity index 71% rename from examples/Tcp/ReuseAddressServerConsoleApp/ReuseAddressServerConsoleApp.csproj rename to examples/Core/OtherCoreConsoleApp/OtherCoreConsoleApp.csproj index d6cfa539a..b2377b2c0 100644 --- a/examples/Tcp/ReuseAddressServerConsoleApp/ReuseAddressServerConsoleApp.csproj +++ b/examples/Core/OtherCoreConsoleApp/OtherCoreConsoleApp.csproj @@ -7,8 +7,7 @@ enable - - - - + + + diff --git a/examples/Core/OtherCoreConsoleApp/Program.cs b/examples/Core/OtherCoreConsoleApp/Program.cs new file mode 100644 index 000000000..8acdc2bc2 --- /dev/null +++ b/examples/Core/OtherCoreConsoleApp/Program.cs @@ -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(); + } +} + +/// +/// 其他核心功能示例类 +/// +public static class OtherCoreDemo +{ + #region 其他核心Crc计算 + /// + /// Crc计算示例 + /// + 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计算 + /// + /// Crc16Value计算示例 + /// + 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 其他核心时间测量器 + /// + /// 时间测量器示例 + /// + public static void TimeMeasurerExample() + { + Console.WriteLine("【二、时间测量器示例】"); + + TimeSpan timeSpan = TimeMeasurer.Run(() => + { + Thread.Sleep(1000); + }); + + Console.WriteLine($"同步操作耗时: {timeSpan.TotalMilliseconds} 毫秒"); + Console.WriteLine(); + } + #endregion + + #region 其他核心时间测量器异步 + /// + /// 时间测量器异步示例 + /// + public static void TimeMeasurerAsyncExample() + { + Console.WriteLine("【时间测量器异步示例】"); + + var timeSpan = TimeMeasurer.Run(async () => + { + await Task.Delay(500); + }); + + Console.WriteLine($"异步操作耗时: {timeSpan.TotalMilliseconds} 毫秒"); + Console.WriteLine(); + } + #endregion + + #region 其他核心MD5计算 + /// + /// MD5计算示例 + /// + 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进制转字节数组 + /// + /// 16进制相关示例 + /// + 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生成 + /// + /// 雪花Id生成示例 + /// + 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压缩 + /// + /// GZip数据压缩示例 + /// + 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 其他核心自定义压缩器 + /// + /// 自定义数据压缩器示例 + /// + 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 其他核心短时间戳 + /// + /// 短时间戳示例 + /// + 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 + /// + /// 读写锁using示例 + /// + 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加密 + /// + /// 3DES加密解密示例 + /// + 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 其他核心自定义压缩器接口实现 + /// + /// 自定义压缩器实现示例 + /// + class MyDataCompressor : IDataCompressor + { + public void Compress(ref TWriter writer, ReadOnlySpan data) + where TWriter : IBytesWriter + { + //此处实现压缩 + throw new NotImplementedException(); + } + + public void Decompress(ref TWriter writer, ReadOnlySpan data) + where TWriter : IBytesWriter + { + //此处实现解压 + throw new NotImplementedException(); + } + } + #endregion + + #region 其他核心读写锁传统用法 + /// + /// 读写锁传统用法示例 + /// + public static void TraditionalReadWriteLockExample() + { + ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim(); + try + { + lockSlim.EnterReadLock(); + //do something + } + finally + { + lockSlim.ExitReadLock(); + } + } + #endregion +} diff --git a/examples/Core/PackageConsoleApp/PackageConsoleApp.csproj b/examples/Core/PackageConsoleApp/PackageConsoleApp.csproj index 591d0dcac..169bf13bc 100644 --- a/examples/Core/PackageConsoleApp/PackageConsoleApp.csproj +++ b/examples/Core/PackageConsoleApp/PackageConsoleApp.csproj @@ -6,11 +6,11 @@ enable - - - - - - + + + + + + diff --git a/examples/Core/PackageConsoleApp/Program.cs b/examples/Core/PackageConsoleApp/Program.cs index 673e780f4..c495d1ad1 100644 --- a/examples/Core/PackageConsoleApp/Program.cs +++ b/examples/Core/PackageConsoleApp/Program.cs @@ -37,12 +37,12 @@ internal class Program { 2,new MyClassModel(){ P1=DateTime.Now} } }; - var byteBlock = new ByteBlock(1024*64); + var byteBlock = new ByteBlock(1024 * 64); try { myClass.Package(ref byteBlock);//打包,相当于序列化 - byteBlock.Seek(0);//将流位置重置为0 + byteBlock.SeekToStart();//将流位置重置为0 var myNewClass = new MyPackage(); myNewClass.Unpackage(ref byteBlock);//解包,相当于反序列化 @@ -69,13 +69,13 @@ internal class Program { 2,new MyClassModel(){ P1=DateTime.Now} } }; - var byteBlock = new ByteBlock(1024*64); + var byteBlock = new ByteBlock(1024 * 64); try { myClass.Package(ref byteBlock);//打包,相当于序列化 - byteBlock.Seek(0);//将流位置重置为0 + byteBlock.SeekToStart();//将流位置重置为0 var myNewClass = new MyGeneratorPackage(); myNewClass.Unpackage(ref byteBlock);//解包,相当于反序列化 @@ -161,37 +161,37 @@ internal class MyPackage : PackageBase public override void Package(ref TByteBlock byteBlock) { //基础类型直接写入。 - byteBlock.WriteInt32(this.P1); - byteBlock.WriteString(this.P2); - byteBlock.WriteChar(this.P3); - byteBlock.WriteDouble(this.P4); + WriterExtension.WriteValue(ref byteBlock, this.P1); + WriterExtension.WriteString(ref byteBlock, this.P2); + WriterExtension.WriteValue(ref byteBlock, this.P3); + WriterExtension.WriteValue(ref byteBlock, (double)this.P4); //集合类型,可以先判断是否为null - byteBlock.WriteIsNull(this.P5); + WriterExtension.WriteIsNull(ref byteBlock, this.P5); if (this.P5 != null) { //如果不为null //就先写入集合长度 //然后遍历将每个项写入 - byteBlock.WriteInt32(this.P5.Count); + WriterExtension.WriteValue(ref byteBlock, this.P5.Count); foreach (var item in this.P5) { - byteBlock.WriteInt32(item); + WriterExtension.WriteValue(ref byteBlock, item); } } //字典类型,可以先判断是否为null - byteBlock.WriteIsNull(this.P6); + WriterExtension.WriteIsNull(ref byteBlock, this.P6); if (this.P6 != null) { //如果不为null //就先写入字典长度 //然后遍历将每个项,按键、值写入 - byteBlock.WriteInt32(this.P6.Count); + WriterExtension.WriteValue(ref byteBlock, this.P6.Count); foreach (var item in this.P6) { - byteBlock.WriteInt32(item.Key); - byteBlock.WritePackage(item.Value);//因为值MyClassModel实现了IPackage,所以可以直接写入 + WriterExtension.WriteValue(ref byteBlock, item.Key); + WriterExtension.WritePackage(ref byteBlock, item.Value);//因为值MyClassModel实现了IPackage,所以可以直接写入 } } } @@ -199,31 +199,34 @@ internal class MyPackage : PackageBase public override void Unpackage(ref TByteBlock byteBlock) { //基础类型按序读取。 - this.P1 = byteBlock.ReadInt32(); - this.P2 = byteBlock.ReadString(); - this.P3 = byteBlock.ReadChar(); - this.P4 = byteBlock.ReadDouble(); + this.P1 = ReaderExtension.ReadValue(ref byteBlock); + this.P2 = ReaderExtension.ReadString(ref byteBlock); + this.P3 = ReaderExtension.ReadValue(ref byteBlock); + this.P4 = ReaderExtension.ReadValue(ref byteBlock); - var isNull = byteBlock.ReadIsNull(); + var isNull = ReaderExtension.ReadIsNull(ref byteBlock); if (!isNull) { - var count = byteBlock.ReadInt32(); + var count = ReaderExtension.ReadValue(ref byteBlock); var list = new List(count); for (var i = 0; i < count; i++) { - list.Add(byteBlock.ReadInt32()); + list.Add(ReaderExtension.ReadValue(ref byteBlock)); } this.P5 = list; } - isNull = byteBlock.ReadIsNull();//复用前面的变量,省的重新声明 + isNull = ReaderExtension.ReadIsNull(ref byteBlock);//复用前面的变量,省的重新声明 if (!isNull) { - var count = byteBlock.ReadInt32(); + var count = ReaderExtension.ReadValue(ref byteBlock); var dic = new Dictionary(count); for (var i = 0; i < count; i++) { - dic.Add(byteBlock.ReadInt32(), byteBlock.ReadPackage()); + var key = ReaderExtension.ReadValue(ref byteBlock); + //因为值MyClassModel实现了IPackage,所以可以直接读取 + var value = ReaderExtension.ReadPackage(ref byteBlock); + dic.Add(key, value); } this.P6 = dic; } @@ -279,16 +282,16 @@ internal class RectangleConverter : FastBinaryConverter { protected override Rectangle Read(ref TByteBlock byteBlock, Type type) { - var rectangle = new Rectangle(byteBlock.ReadInt32(), byteBlock.ReadInt32(), byteBlock.ReadInt32(), byteBlock.ReadInt32()); + var rectangle = new Rectangle(ReaderExtension.ReadValue(ref byteBlock), ReaderExtension.ReadValue(ref byteBlock), ReaderExtension.ReadValue(ref byteBlock), ReaderExtension.ReadValue(ref byteBlock)); return rectangle; } protected override void Write(ref TByteBlock byteBlock, in Rectangle obj) { - byteBlock.WriteInt32(obj.X); - byteBlock.WriteInt32(obj.Y); - byteBlock.WriteInt32(obj.Width); - byteBlock.WriteInt32(obj.Height); + WriterExtension.WriteValue(ref byteBlock, obj.X); + WriterExtension.WriteValue(ref byteBlock, obj.Y); + WriterExtension.WriteValue(ref byteBlock, obj.Width); + WriterExtension.WriteValue(ref byteBlock, obj.Height); } } @@ -298,12 +301,12 @@ public class MyClassModel : PackageBase public override void Package(ref TByteBlock byteBlock) { - byteBlock.WriteDateTime(this.P1); + WriterExtension.WriteValue(ref byteBlock, this.P1); } public override void Unpackage(ref TByteBlock byteBlock) { - this.P1 = byteBlock.ReadDateTime(); + this.P1 = ReaderExtension.ReadValue(ref byteBlock); } } @@ -315,15 +318,15 @@ public class MyClass : PackageBase public override void Package(ref TByteBlock byteBlock) { //将P1与P2属性按类型依次写入 - byteBlock.WriteInt32(this.P1); - byteBlock.WriteString(this.P2); + WriterExtension.WriteValue(ref byteBlock, this.P1); + WriterExtension.WriteString(ref byteBlock, this.P2); } public override void Unpackage(ref TByteBlock byteBlock) { //将P1与P2属性按类型依次读取 - this.P1 = byteBlock.ReadInt32(); - this.P2 = byteBlock.ReadString(); + this.P1 = ReaderExtension.ReadValue(ref byteBlock); + this.P2 = ReaderExtension.ReadString(ref byteBlock); } } @@ -334,31 +337,31 @@ public class MyArrayClass : PackageBase public override void Package(ref TByteBlock byteBlock) { //集合类型,可以先判断集合是否为null - byteBlock.WriteIsNull(this.P5); + WriterExtension.WriteIsNull(ref byteBlock, this.P5); if (this.P5 != null) { //如果不为null //就先写入集合长度 //然后遍历将每个项写入 - byteBlock.WriteInt32(this.P5.Length); + WriterExtension.WriteValue(ref byteBlock, this.P5.Length); foreach (var item in this.P5) { - byteBlock.WriteInt32(item); + WriterExtension.WriteValue(ref byteBlock, item); } } } public override void Unpackage(ref TByteBlock byteBlock) { - var isNull_P5 = byteBlock.ReadIsNull(); + var isNull_P5 = ReaderExtension.ReadIsNull(ref byteBlock); if (!isNull_P5) { //有值 - var count = byteBlock.ReadInt32(); + var count = ReaderExtension.ReadValue(ref byteBlock); var array = new int[count]; for (var i = 0; i < count; i++) { - array[i] = byteBlock.ReadInt32(); + array[i] = ReaderExtension.ReadValue(ref byteBlock); } //赋值 @@ -374,31 +377,32 @@ public class MyDictionaryClass : PackageBase public override void Package(ref TByteBlock byteBlock) { //字典类型,可以先判断是否为null - byteBlock.WriteIsNull(this.P6); + WriterExtension.WriteIsNull(ref byteBlock, this.P6); if (this.P6 != null) { //如果不为null //就先写入字典长度 //然后遍历将每个项,按键、值写入 - byteBlock.WriteInt32(this.P6.Count); + WriterExtension.WriteValue(ref byteBlock, this.P6.Count); foreach (var item in this.P6) { - byteBlock.WriteInt32(item.Key); - byteBlock.WritePackage(item.Value);//因为值MyClassModel实现了IPackage,所以可以直接写入 + WriterExtension.WriteValue(ref byteBlock, item.Key); + //因为值MyClassModel实现了IPackage,所以可以直接写入 + WriterExtension.WritePackage(ref byteBlock, item.Value); } } } public override void Unpackage(ref TByteBlock byteBlock) { - var isNull_6 = byteBlock.ReadIsNull(); + var isNull_6 = ReaderExtension.ReadIsNull(ref byteBlock); if (!isNull_6) { - var count = byteBlock.ReadInt32(); + var count = ReaderExtension.ReadValue(ref byteBlock); var dic = new Dictionary(count); for (var i = 0; i < count; i++) { - dic.Add(byteBlock.ReadInt32(), byteBlock.ReadPackage()); + dic.Add(ReaderExtension.ReadValue(ref byteBlock), ReaderExtension.ReadPackage(ref byteBlock)); } this.P6 = dic; } diff --git a/examples/Core/PluginConsoleApp/PluginConsoleApp.csproj b/examples/Core/PluginConsoleApp/PluginConsoleApp.csproj index 16ff67972..33aa74222 100644 --- a/examples/Core/PluginConsoleApp/PluginConsoleApp.csproj +++ b/examples/Core/PluginConsoleApp/PluginConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,6 @@ - + diff --git a/examples/Core/PluginConsoleApp/Program.cs b/examples/Core/PluginConsoleApp/Program.cs index 8e35f8020..576c51b97 100644 --- a/examples/Core/PluginConsoleApp/Program.cs +++ b/examples/Core/PluginConsoleApp/Program.cs @@ -20,20 +20,26 @@ internal class Program { private static async Task Main(string[] args) { + #region 插件系统创建插件管理器 IPluginManager pluginManager = new PluginManager(new Container()) { Enable = true//必须启用 }; + #endregion + #region 插件系统按类型添加插件 //添加插件 pluginManager.Add(); - pluginManager.Add(); - pluginManager.Add(); pluginManager.Add(); pluginManager.Add(); + #endregion + //示例:注册委托方法 + pluginManager.Add(); + //示例:源生成插件 + pluginManager.Add(); - + #region 插件系统按委托添加插件 //订阅插件,不仅可以使用声明插件的方式,还可以使用委托。 pluginManager.Add(typeof(ISayPlugin), () => { @@ -61,7 +67,9 @@ internal class Program Console.WriteLine("在Action3中获得"); await e.InvokeNext(); }); + #endregion + #region 插件系统触发插件 while (true) { Console.WriteLine("请输入hello、helloaction、hellogenerator、hi或者其他"); @@ -70,9 +78,11 @@ internal class Program Words = Console.ReadLine() }); } + #endregion } } +#region 插件系统新建插件接口及事件类 public class MyPluginEventArgs : PluginEventArgs { public string Words { get; set; } @@ -94,7 +104,9 @@ public interface ISayPlugin : IPlugin /// Task Say(object sender, MyPluginEventArgs e); } +#endregion +#region 插件系统实现插件接口 public class SayHelloPlugin : PluginBase, ISayPlugin { public async Task Say(object sender, MyPluginEventArgs e) @@ -144,7 +156,9 @@ internal class LastSayPlugin : PluginBase, ISayPlugin Console.WriteLine($"{this.GetType().Name}------Leave"); } } +#endregion +#region 插件系统注册委托方法 public class SayHelloAction : PluginBase { protected override void Loaded(IPluginManager pluginManager) @@ -171,7 +185,9 @@ public class SayHelloAction : PluginBase Console.WriteLine($"{this.GetType().Name}------Leave"); } } +#endregion +#region 插件系统源生成插件 public partial class SayHelloGenerator : PluginBase, ISayPlugin { /// @@ -195,4 +211,5 @@ public partial class SayHelloGenerator : PluginBase, ISayPlugin await e.InvokeNext(); Console.WriteLine($"{this.GetType().Name}------Leave"); } -} \ No newline at end of file +} +#endregion \ No newline at end of file diff --git a/examples/Core/TouchSocketBitConverterConsoleApp/Program.cs b/examples/Core/TouchSocketBitConverterConsoleApp/Program.cs new file mode 100644 index 000000000..aeb3a7a0c --- /dev/null +++ b/examples/Core/TouchSocketBitConverterConsoleApp/Program.cs @@ -0,0 +1,364 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Runtime.InteropServices; +using TouchSocket.Core; + +namespace TouchSocketBitConverterConsoleApp; + +internal class Program +{ + private static void Main(string[] args) + { + TouchSocketBitConverterDemo.RunAll(); + } +} +/// +/// TouchSocketBitConverter 使用示例 +/// +public static class TouchSocketBitConverterDemo +{ + public static void RunAll() + { + BasicGetBytesAndTo(); + ChangeDefaultEndian(); + WriteBytesIntoExistingBuffer(); + ToValuesFromByteSequence(); + ConvertValuesBetweenTypes(); + ConvertBoolBitPacking(); + CrossEndianBulkConversion(); + StructReadWrite(); + } + + #region 基本GetBytes与To示例 + private static void BasicGetBytesAndTo() + { + var value = 0x12345678; + + // 按小端获取字节 + var littleBytes = TouchSocketBitConverter.LittleEndian.GetBytes(value); + // 按大端获取字节 + var bigBytes = TouchSocketBitConverter.BigEndian.GetBytes(value); + + Console.WriteLine($"小端字节: {ToHex(littleBytes.Span)}"); + Console.WriteLine($"大端字节: {ToHex(bigBytes.Span)}"); + + // 使用与写入相同的端解析 + var v1 = TouchSocketBitConverter.LittleEndian.To(littleBytes.Span); + var v2 = TouchSocketBitConverter.BigEndian.To(bigBytes.Span); + + // 交叉解析(故意错误端),会得到不同数值 + var wrong = TouchSocketBitConverter.BigEndian.To(littleBytes.Span); + + Console.WriteLine($"正确解析小端 => {v1:X8}"); + Console.WriteLine($"正确解析大端 => {v2:X8}"); + Console.WriteLine($"以大端错误解析小端数据 => {wrong:X8}"); + Console.WriteLine(); + } + #endregion + + #region 大小端转换器转换整型 + private static void ConvertInt32Example() + { + // int -> byte[] + var data = TouchSocketBitConverter.BigEndian.GetBytes(0x12345678); + + // byte[] -> int + int value = TouchSocketBitConverter.BigEndian.To(data.Span); + } + #endregion + + #region 大小端转换器转换浮点型 + private static void ConvertFloatExample() + { + // float -> byte[] + float num = 3.14f; + var bytes = TouchSocketBitConverter.LittleEndian.GetBytes(num); + + // byte[] -> float + float result = TouchSocketBitConverter.LittleEndian.To(bytes.Span); + } + #endregion + + #region 大小端转换器转换长整型 + private static void ConvertInt64Example() + { + // long -> byte[] + long bigValue = 0x123456789ABCDEF0; + var data = TouchSocketBitConverter.Default.GetBytes(bigValue); + + // byte[] -> long + long restored = TouchSocketBitConverter.Default.To(data.Span); + } + #endregion + + #region 大小端转换器转换高精度小数 + private static void ConvertDecimalExample() + { + // decimal -> byte[] + decimal money = 123456.78m; + var decimalBytes = TouchSocketBitConverter.BigEndian.GetBytes(money); + + // byte[] -> decimal + decimal result = TouchSocketBitConverter.BigEndian.To(decimalBytes.Span); + } + #endregion + + #region 大小端转换器不安全内存操作 + private static void UnsafeMemoryExample() + { + byte[] buffer = new byte[8]; + long value = 0x1122334455667788; + + // 直接内存写入 + TouchSocketBitConverter.LittleEndian.WriteBytes(buffer, value); + + // 直接内存读取 + long readValue = TouchSocketBitConverter.LittleEndian.To(buffer); + } + #endregion + + #region 大小端转换器布尔数组转换 + private static void ConvertBoolArrayExample() + { + // bool[] -> byte[] + bool[] flags = { true, false, true, true, false, true, false, true }; + var byteCount = TouchSocketBitConverter.GetConvertedLength(flags.Length); + byte[] boolBytes = new byte[byteCount]; + TouchSocketBitConverter.ConvertValues(flags, boolBytes); + + // byte[] -> bool[] + bool[] decodedFlags = new bool[flags.Length]; + TouchSocketBitConverter.ConvertValues(boolBytes, decodedFlags); + } + #endregion + + #region 大小端转换器字节序验证 + private static void CheckEndianCompatibility() + { + // 检查当前配置是否与系统字节序一致 + bool isCompatible = TouchSocketBitConverter.Default.IsSameOfSet(); + } + #endregion + + #region 大小端转换器交换端序模式 + private static void SwapEndianExample() + { + // 使用 BigSwap 模式处理网络数据包 + var swappedData = TouchSocketBitConverter.BigSwapEndian.GetBytes(0xAABBCCDD); + } + #endregion + + #region 大小端转换器网络数据包处理 + private static void NetworkPacketExample() + { + // 配置全局大端模式 + TouchSocketBitConverter.DefaultEndianType = EndianType.Big; + + // 构造数据包 + var packet = new byte[16]; + int header = 0x4D534754; // "MSGT" + float payload = 1024.5f; + + // 写入数据 + TouchSocketBitConverter.Default.WriteBytes(packet.AsSpan(0, 4), header); + TouchSocketBitConverter.Default.WriteBytes(packet.AsSpan(4, 4), payload); + + // 解析数据 + int parsedHeader = TouchSocketBitConverter.Default.To(packet.AsSpan(0, 4)); + float parsedPayload = TouchSocketBitConverter.Default.To(packet.AsSpan(4, 4)); + } + #endregion + + #region 修改默认字节序示例 + private static void ChangeDefaultEndian() + { + Console.WriteLine($"当前默认端: {TouchSocketBitConverter.DefaultEndianType}"); + TouchSocketBitConverter.DefaultEndianType = EndianType.Big; + Console.WriteLine($"修改后默认端: {TouchSocketBitConverter.DefaultEndianType}"); + + // Default引用自动指向新的实例 + var bytes = TouchSocketBitConverter.Default.GetBytes((short)0x1234); + Console.WriteLine($"默认端(大端)写出: {ToHex(bytes.Span)}"); + + // 还原 + TouchSocketBitConverter.DefaultEndianType = EndianType.Little; + Console.WriteLine($"还原默认端: {TouchSocketBitConverter.DefaultEndianType}"); + Console.WriteLine(); + } + #endregion + + #region WriteBytes写入既有缓冲区示例 + private static void WriteBytesIntoExistingBuffer() + { + var value = 0x0A0B0C0D; + Span buffer = stackalloc byte[4]; + + TouchSocketBitConverter.BigEndian.WriteBytes(buffer, value); + Console.WriteLine($"大端写入: {ToHex(buffer)}"); + + TouchSocketBitConverter.LittleEndian.WriteBytes(buffer, value); + Console.WriteLine($"小端覆盖: {ToHex(buffer)}"); + Console.WriteLine(); + } + #endregion + + #region ToValues将字节批量转为数组示例 + private static void ToValuesFromByteSequence() + { + // 准备 3 个UInt16(小端) + ushort[] data = { 0x1122, 0x3344, 0x5566 }; + var bytes = new byte[data.Length * 2]; + var conv = TouchSocketBitConverter.LittleEndian; + var span = bytes.AsSpan(); + for (var i = 0; i < data.Length; i++) + { + conv.WriteBytes(span.Slice(i * 2, 2), data[i]); + } + + Console.WriteLine($"原始字节(小端): {ToHex(bytes)}"); + + // 按小端解析 + var u16 = TouchSocketBitConverter.ToValues(bytes, EndianType.Little); + Console.WriteLine("解析结果: " + string.Join(", ", u16.Span.ToArray().Select(v => $"0x{v:X4}"))); + Console.WriteLine(); + } + #endregion + + #region ConvertValues类型批量转换示例 + private static void ConvertValuesBetweenTypes() + { + int[] ints = { 1, 2, 3, 0x10203040 }; + // int[] -> byte[] + var byteCount = TouchSocketBitConverter.GetConvertedLength(ints.Length); + var buffer = new byte[byteCount]; + TouchSocketBitConverter.ConvertValues(ints, buffer); + + Console.WriteLine($"int数组 => byte: {ToHex(buffer)}"); + + // 反向 byte -> int + var back = new int[ints.Length]; + TouchSocketBitConverter.ConvertValues(buffer, back); + Console.WriteLine("还原int: " + string.Join(", ", back.Select(v => $"0x{v:X8}"))); + Console.WriteLine(); + } + #endregion + + #region ConvertValues布尔位打包示例 + private static void ConvertBoolBitPacking() + { + bool[] bools = + { + true,false,true,true, false,false,false,true, + true,true,false,false,false,false,false,false + }; + + // bool -> byte(按位打包) + var byteLength = TouchSocketBitConverter.GetConvertedLength(bools.Length); + var packed = new byte[byteLength]; + TouchSocketBitConverter.ConvertValues(bools, packed); + Console.WriteLine($"bool打包 => {ToHex(packed)} (总位:{bools.Length})"); + + // byte -> bool + var unpacked = new bool[bools.Length]; + TouchSocketBitConverter.ConvertValues(packed, unpacked); + Console.WriteLine("解包结果: " + string.Join("", unpacked.Select(b => b ? '1' : '0'))); + Console.WriteLine(); + } + #endregion + + #region ConvertValues跨端批量转换示例 + private static void CrossEndianBulkConversion() + { + uint[] values = { 0x11223344, 0xAABBCCDD }; + // 源认为大端存储 -> 转成小端字节序的byte[] + var byteLength = TouchSocketBitConverter.GetConvertedLength(values.Length); + var littleBytes = new byte[byteLength]; + TouchSocketBitConverter.ConvertValues(values, littleBytes, EndianType.Big, EndianType.Little); + Console.WriteLine($"大端uint -> 小端byte: {ToHex(littleBytes)}"); + + // 再按小端解释为uint + var round = new uint[values.Length]; + TouchSocketBitConverter.ConvertValues(littleBytes, round, EndianType.Little, EndianType.Little); + Console.WriteLine("还原uint: " + string.Join(", ", round.Select(v => $"0x{v:X8}"))); + Console.WriteLine(); + } + #endregion + + #region 自定义结构读写示例 + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct MyPacket + { + public ushort Id; + public int Value; + public byte Flag; + } + + private static void StructReadWrite() + { + var pkt = new MyPacket + { + Id = 0x1234, + Value = 0x11223344, + Flag = 0x5A + }; + + // 逐字段写入(控制端) + Span buffer = stackalloc byte[2 + 4 + 1]; + var big = TouchSocketBitConverter.BigEndian; + big.WriteBytes(buffer.Slice(0, 2), pkt.Id); + big.WriteBytes(buffer.Slice(2, 4), pkt.Value); + buffer[6] = pkt.Flag; + + Console.WriteLine($"MyPacket序列化(大端): {ToHex(buffer)}"); + + // 读取 + var id = big.To(buffer.Slice(0, 2)); + var val = big.To(buffer.Slice(2, 4)); + var flag = buffer[6]; + + Console.WriteLine($"解析 => Id=0x{id:X4}, Value=0x{val:X8}, Flag=0x{flag:X2}"); + Console.WriteLine(); + } + #endregion + + #region 工具方法 + private static string ToHex(ReadOnlySpan span) + { + if (span.Length == 0) + { + return string.Empty; + } + + // 每个字节需要2个十六进制字符,字节间需要1个空格(除了最后一个) + var resultLength = span.Length * 3 - 1; + Span chars = stackalloc char[resultLength]; + + const string hexChars = "0123456789ABCDEF"; + var pos = 0; + + for (var i = 0; i < span.Length; i++) + { + var b = span[i]; + chars[pos++] = hexChars[b >> 4]; // 高4位 + chars[pos++] = hexChars[b & 0x0F]; // 低4位 + + if (i < span.Length - 1) // 不是最后一个字节时添加空格 + { + chars[pos++] = ' '; + } + } + + return new string(chars); + } + #endregion +} \ No newline at end of file diff --git a/examples/Core/TouchSocketBitConverterConsoleApp/TouchSocketBitConverterConsoleApp.csproj b/examples/Core/TouchSocketBitConverterConsoleApp/TouchSocketBitConverterConsoleApp.csproj new file mode 100644 index 000000000..b2377b2c0 --- /dev/null +++ b/examples/Core/TouchSocketBitConverterConsoleApp/TouchSocketBitConverterConsoleApp.csproj @@ -0,0 +1,13 @@ + + + + Exe + net9.0 + enable + enable + + + + + + diff --git a/examples/Directory.Build.props b/examples/Directory.Build.props index c53ab6b1d..47f12524f 100644 --- a/examples/Directory.Build.props +++ b/examples/Directory.Build.props @@ -5,6 +5,5 @@ Copyright © 2024 若汝棋茗 若汝棋茗 IDE0290;IDE0090;IDE0305 - \ No newline at end of file diff --git a/examples/Directory.Packages.props b/examples/Directory.Packages.props new file mode 100644 index 000000000..c37a18d57 --- /dev/null +++ b/examples/Directory.Packages.props @@ -0,0 +1,47 @@ + + + + true + 4.0.0-rc.51 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/Dmtp/AotDmtpRpcConsoleApp/DmtpRpcConsoleApp.csproj b/examples/Dmtp/AotDmtpRpcConsoleApp/DmtpRpcConsoleApp.csproj index f6f67dfad..e2b5cc634 100644 --- a/examples/Dmtp/AotDmtpRpcConsoleApp/DmtpRpcConsoleApp.csproj +++ b/examples/Dmtp/AotDmtpRpcConsoleApp/DmtpRpcConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -9,6 +9,6 @@ - + diff --git a/examples/Dmtp/AotDmtpRpcConsoleApp/Program.cs b/examples/Dmtp/AotDmtpRpcConsoleApp/Program.cs index c8f4036e5..bb479cdc7 100644 --- a/examples/Dmtp/AotDmtpRpcConsoleApp/Program.cs +++ b/examples/Dmtp/AotDmtpRpcConsoleApp/Program.cs @@ -1,5 +1,16 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.ComponentModel; -using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using TouchSocket.Core; using TouchSocket.Dmtp; @@ -12,7 +23,7 @@ namespace DmtpRpcConsoleApp { internal class Program { - static async Task Main(string[] args) + private static async Task Main(string[] args) { try { @@ -29,11 +40,10 @@ namespace DmtpRpcConsoleApp continue; } - var invokeOption = new DmtpInvokeOption() + var invokeOption = new DmtpInvokeOption(5000) { FeedbackType = FeedbackType.WaitInvoke, - SerializationType = SerializationType.FastBinary, - Timeout = 5000 + SerializationType = SerializationType.FastBinary }; var result = await client.GetDmtpRpcActor().LoginAsync(strs[0], strs[1], invokeOption); @@ -47,7 +57,7 @@ namespace DmtpRpcConsoleApp } } - static async Task GetClient() + private static async Task GetClient() { var client = new TcpDmtpClient(); await client.SetupAsync(new TouchSocketConfig() @@ -58,28 +68,29 @@ namespace DmtpRpcConsoleApp .SetRemoteIPHost("127.0.0.1:7789") .ConfigurePlugins(a => { - a.UseDmtpRpc() - .ConfigureDefaultSerializationSelector(selector => + a.UseDmtpRpc(options => { - //配置Fast序列化器 - selector.FastSerializerContext = new AppFastSerializerContext(); - - //配置System.Text.Json序列化器 - selector.UseSystemTextJson(options => - { - options.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); - }); + options.ConfigureDefaultSerializationSelector(selector => + { + //配置Fast序列化器 + selector.FastSerializerContext = new AppFastSerializerContext(); + //配置System.Text.Json序列化器 + selector.UseSystemTextJson(options => + { + options.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); + }); + }); }); }) - .SetDmtpOption(new DmtpOption() - { - VerifyToken = "Rpc" - })); + .SetDmtpOption(options => + { + options.VerifyToken = "Rpc"; + })); await client.ConnectAsync(); client.Logger.Info($"客户端已连接"); return client; } - static async Task GetService() + private static async Task GetService() { var service = new TcpDmtpService(); var config = new TouchSocketConfig()//配置 @@ -94,22 +105,24 @@ namespace DmtpRpcConsoleApp }) .ConfigurePlugins(a => { - a.UseDmtpRpc() - .ConfigureDefaultSerializationSelector(selector => + a.UseDmtpRpc(options => { - //配置Fast序列化器 - selector.FastSerializerContext = new AppFastSerializerContext(); - - //配置System.Text.Json序列化器 - selector.UseSystemTextJson(options => + options.ConfigureDefaultSerializationSelector(selector => { - options.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); + //配置Fast序列化器 + selector.FastSerializerContext = new AppFastSerializerContext(); + + //配置System.Text.Json序列化器 + selector.UseSystemTextJson(options => + { + options.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); + }); }); }); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Rpc" + options.VerifyToken = "Rpc"; }); await service.SetupAsync(config); @@ -124,7 +137,7 @@ namespace DmtpRpcConsoleApp [FastSerializable(typeof(MyResult))] [FastSerializable(typeof(IMyRpcServer), TypeMode.All)]//直接按类型,搜索其属性,字段,方法参数,方法返回值的类型进行注册序列化 - partial class AppFastSerializerContext : FastSerializerContext + internal partial class AppFastSerializerContext : FastSerializerContext { } diff --git a/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj b/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj index 59585b20b..5fdbe036a 100644 --- a/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj +++ b/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe net9.0 @@ -7,6 +7,6 @@ true - + diff --git a/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/Program.cs b/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/Program.cs index b4e26ab71..adb3e7318 100644 --- a/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/Program.cs +++ b/examples/Dmtp/AotDmtpRpcPerformanceConsoleApp/Program.cs @@ -1,5 +1,16 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Dmtp; using TouchSocket.Dmtp.Rpc; @@ -10,7 +21,7 @@ namespace RpcPerformanceConsoleApp { internal class Program { - static async Task Main(string[] args) + private static async Task Main(string[] args) { var consoleAction = new ConsoleAction("h|help|?");//设置帮助命令 consoleAction.OnException += ConsoleAction_OnException;//订阅执行异常输出 @@ -19,9 +30,9 @@ namespace RpcPerformanceConsoleApp var count = 100000; - consoleAction.Add("3.1", "DmtpRpc测试Sum", async () =>await StartSumClient(count)); + consoleAction.Add("3.1", "DmtpRpc测试Sum", async () => await StartSumClient(count)); consoleAction.Add("3.2", "DmtpRpc测试GetBytes", async () => await StartGetBytesClient(count)); - consoleAction.Add("3.3", "DmtpRpc测试BigString", async () =>await StartBigStringClient(count)); + consoleAction.Add("3.3", "DmtpRpc测试BigString", async () => await StartBigStringClient(count)); consoleAction.ShowAll(); @@ -45,9 +56,9 @@ namespace RpcPerformanceConsoleApp { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Rpc"//设定连接口令,作用类似账号密码 + options.VerifyToken = "Rpc";//设定连接口令,作用类似账号密码 }); await service.SetupAsync(config); @@ -58,13 +69,13 @@ namespace RpcPerformanceConsoleApp public static async Task StartSumClient(int count) { - var client =await GetClient(); + var client = await GetClient(); var timeSpan = TimeMeasurer.Run(async () => { var actor = client.GetDmtpRpcActor(); for (var i = 0; i < count; i++) { - var rs =await actor.InvokeTAsync("Sum", InvokeOption.WaitInvoke, i, i); + var rs = await actor.InvokeTAsync("Sum", InvokeOption.WaitInvoke, i, i); if (rs != i + i) { Console.WriteLine("调用结果不一致"); @@ -87,9 +98,9 @@ namespace RpcPerformanceConsoleApp a.UseDmtpRpc(); }) .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Rpc" + options.VerifyToken = "Rpc"; })); await client.ConnectAsync(); return client; @@ -102,7 +113,7 @@ namespace RpcPerformanceConsoleApp var actor = client.GetDmtpRpcActor(); for (var i = 1; i < count; i++) { - var rs =await actor.InvokeTAsync("GetBytes", InvokeOption.WaitInvoke, i);//测试10k数据 + var rs = await actor.InvokeTAsync("GetBytes", InvokeOption.WaitInvoke, i);//测试10k数据 if (rs.Length != i) { Console.WriteLine("调用结果不一致"); @@ -118,13 +129,13 @@ namespace RpcPerformanceConsoleApp public static async Task StartBigStringClient(int count) { - var client =await GetClient(); + var client = await GetClient(); var timeSpan = TimeMeasurer.Run(async () => { var actor = client.GetDmtpRpcActor(); for (var i = 0; i < count; i++) { - var rs =await actor.InvokeTAsync("GetBigString", InvokeOption.WaitInvoke); + var rs = await actor.InvokeTAsync("GetBigString", InvokeOption.WaitInvoke); if (i % 1000 == 0) { Console.WriteLine(i); diff --git a/examples/Dmtp/CreateDmtpConsoleApp/CreateDmtpConsoleApp.csproj b/examples/Dmtp/CreateDmtpConsoleApp/CreateDmtpConsoleApp.csproj new file mode 100644 index 000000000..2bb9784a4 --- /dev/null +++ b/examples/Dmtp/CreateDmtpConsoleApp/CreateDmtpConsoleApp.csproj @@ -0,0 +1,16 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + + + diff --git a/examples/Dmtp/CreateDmtpConsoleApp/Program.cs b/examples/Dmtp/CreateDmtpConsoleApp/Program.cs new file mode 100644 index 000000000..3d3020059 --- /dev/null +++ b/examples/Dmtp/CreateDmtpConsoleApp/Program.cs @@ -0,0 +1,480 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using TouchSocket.Core; +using TouchSocket.Dmtp; +using TouchSocket.NamedPipe; +using TouchSocket.Sockets; + +namespace CreateDmtpConsoleApp; + +internal class Program +{ + private static async Task Main(string[] args) + { + var tcpDmtpService = await CreateTcpDmtpService(); + } + + private static async Task CreateTcpDmtpService() + { + #region 创建TcpDmtpService + var service = new TcpDmtpService(); + var config = new TouchSocketConfig()//配置 + .SetListenIPHosts(7789) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + }) + #region Dmtp服务器基础配置 + .SetDmtpOption(options => + { + options.VerifyToken = "Dmtp";//设定连接口令,作用类似账号密码 + options.VerifyTimeout = TimeSpan.FromSeconds(3);//设定账号密码验证超时时间 + }) + #endregion + ; + + await service.SetupAsync(config); + await service.StartAsync(); + #endregion + + service.Logger.Info($"{service.GetType().Name}已启动"); + return service; + } + + private static async Task CreateUdpDmtpService() + { + #region 创建UdpDmtp + var udpDmtp = new UdpDmtp(); + + var config = new TouchSocketConfig(); + config.SetBindIPHost(new IPHost(7789)) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }); + + await udpDmtp.SetupAsync(config); + + await udpDmtp.StartAsync(); + #endregion + + udpDmtp.Logger.Info($"{udpDmtp.GetType().Name}已启动"); + return udpDmtp; + } + private static async Task CreateHttpDmtpService() + { + #region 创建HttpDmtpService + var service = new HttpDmtpService(); + var config = new TouchSocketConfig()//配置 + .SetListenIPHosts(7789) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + }); + + await service.SetupAsync(config); + + await service.StartAsync(); + #endregion + + service.Logger.Info($"{service.GetType().Name}已启动"); + return service; + } + + private static async Task CreateNamedPipeDmtpService() + { + #region 创建NamedPipeDmtpService + var service = new NamedPipeDmtpService(); + var config = new TouchSocketConfig()//配置 + .SetPipeName("TouchSocketPipe")//设置管道名称 + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + }); + + await service.SetupAsync(config); + + await service.StartAsync(); + #endregion + + service.Logger.Info($"{service.GetType().Name}已启动"); + return service; + } + private static async Task CreateAspNetCoreWebSocketDmtpService(string[] args) + { + #region 创建WebSocket协议的Dmtp服务器 + var builder = WebApplication.CreateBuilder(args); + + #region AspNetCore统一配置容器 + builder.Services.ConfigureContainer(container => + { + container.AddAspNetCoreLogger(); + }); + #endregion + + + builder.Services.AddWebSocketDmtpService(config => + { + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + }) + .ConfigurePlugins(a => + { + }); + }); + + var app = builder.Build(); + app.UseWebSockets(); + app.UseWebSocketDmtp("/WebSocketDmtp");//WebSocketDmtp必须在UseWebSockets之后使用。 + #endregion + + await app.RunAsync(); + } + + private static async Task CreateAspNetCoreHttpDmtpService(string[] args) + { + #region 创建基于AspNetCore的Http协议的Dmtp服务器 + var builder = WebApplication.CreateBuilder(args); + + builder.Services.ConfigureContainer(container => + { + container.AddAspNetCoreLogger(); + }); + + builder.Services.AddHttpMiddlewareDmtpService(config => + { + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + }) + .ConfigurePlugins(a => + { + //添加插件 + }); + }); + + var app = builder.Build(); + app.UseHttpDmtp(); //HttpDmtp可以单独直接使用。不需要其他。 + #endregion + + } + + #region 客户端 + private static async Task CreateTcpDmtpClient() + { + #region 创建TcpDmtpClient + var client = new TcpDmtpClient(); + + //配置项目 + var config = new TouchSocketConfig(); + config.SetRemoteIPHost("tcp://127.0.0.1:7789"); + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + options.Metadata = new Metadata().Add("a", "a"); + }); + + //配置容器 + config.ConfigureContainer(a => + { + //注入日志组件 + a.AddConsoleLogger(); + }); + + //配置插件 + config.ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + //a.UseDmtpRpc(); + }); + + //应用配置 + await client.SetupAsync(config); + + //连接 + await client.ConnectAsync(); + #endregion + + } + private static async Task CreateUdpDmtpClient() + { + #region 创建UdpDmtpClient + var client = new UdpDmtp(); + + //配置项目 + var config = new TouchSocketConfig(); + config.SetRemoteIPHost("udp://127.0.0.1:7797");//远程地址 + config.UseUdpReceive();//使用Udp接收 + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + options.Metadata = new Metadata().Add("a", "a"); + }); + + //配置容器 + config.ConfigureContainer(a => + { + //注入日志组件 + a.AddConsoleLogger(); + }); + + //配置插件 + config.ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + //a.UseDmtpRpc(); + }); + + //应用配置 + await client.SetupAsync(config); + + //启动 + await client.StartAsync(); + #endregion + } + private static async Task CreateHttpDmtpClient() + { + #region 创建HttpDmtpClient + var client = new HttpDmtpClient(); + + //配置项目 + var config = new TouchSocketConfig(); + config.SetRemoteIPHost("http://127.0.0.1:7789"); + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + options.Metadata = new Metadata().Add("a", "a"); + }); + + //配置容器 + config.ConfigureContainer(a => + { + //注入日志组件 + a.AddConsoleLogger(); + }); + + //配置插件 + config.ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + //a.UseDmtpRpc(); + }); + + //应用配置 + await client.SetupAsync(config); + + //连接 + await client.ConnectAsync(); + #endregion + } + private static async Task CreateWebSocketDmtpClient() + { + #region 创建WebSocketDmtpClient + var client = new WebSocketDmtpClient(); + + //配置项目 + var config = new TouchSocketConfig(); + config.SetRemoteIPHost("ws://127.0.0.1:7789/WebSocketDmtp"); + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + options.Metadata = new Metadata().Add("a", "a"); + }); + + //配置容器 + config.ConfigureContainer(a => + { + //注入日志组件 + a.AddConsoleLogger(); + }); + + //配置插件 + config.ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + //a.UseDmtpRpc(); + }); + + //应用配置 + await client.SetupAsync(config); + + //连接 + await client.ConnectAsync(); + #endregion + } + + private static async Task CreateNamedPipeDmtpClient() + { + #region 创建NamedPipeDmtpClient + var client = new NamedPipeDmtpClient(); + + //配置项目 + var config = new TouchSocketConfig(); + config.SetPipeName("TouchSocketPipe"); + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + options.Metadata = new Metadata().Add("a", "a"); + }); + + //配置容器 + config.ConfigureContainer(a => + { + //注入日志组件 + a.AddConsoleLogger(); + }); + + //配置插件 + config.ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + //a.UseDmtpRpc(); + }); + + //应用配置 + await client.SetupAsync(config); + + //连接 + await client.ConnectAsync(); + #endregion + } + private static async Task CreateTcpDmtpClientFactory() + { + #region 创建TcpDmtpClientFactory + var clientFactory = new TcpDmtpClientFactory(); + + //配置工厂 + clientFactory.GetConfig = () => + { + //配置项目 + var config = new TouchSocketConfig(); + config.SetRemoteIPHost("tcp://127.0.0.1:7789"); + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + options.Metadata = new Metadata().Add("a", "a"); + }); + + //配置容器 + config.ConfigureContainer(a => + { + //注入日志组件 + a.AddConsoleLogger(); + }); + + //配置插件 + config.ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + //a.UseDmtpRpc(); + }); + + return config; + }; + + //在链接工厂获取客户端时,如果没有可用客户端时的最大等待时间。 + //超过该时间将新创建客户端。 + clientFactory.MaxWaitTime = TimeSpan.FromSeconds(1); + + clientFactory.MinCount = 2;//最小连接数 + clientFactory.MaxCount = 5;//最大连接数 + + using var cts = new CancellationTokenSource(10 * 1000); + + //获取客户端 + using (var clientFactoryResult = await clientFactory.GetClient(cts.Token)) + { + //获取到的池中的客户端 + //注意:该客户端只能在当前using作用域中使用。 + var client = clientFactoryResult.Client; + } + #endregion + } + + private static async Task CreateHttpDmtpClientFactory() + { + #region 创建HttpDmtpClientFactory + var clientFactory = new HttpDmtpClientFactory(); + + //配置工厂 + clientFactory.GetConfig = () => + { + //配置项目 + var config = new TouchSocketConfig(); + config.SetRemoteIPHost("http://127.0.0.1:7789"); + config.SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + options.Metadata = new Metadata().Add("a", "a"); + }); + + //配置容器 + config.ConfigureContainer(a => + { + //注入日志组件 + a.AddConsoleLogger(); + }); + + //配置插件 + config.ConfigurePlugins(a => + { + //添加插件 + //a.Add(); + //a.UseDmtpRpc(); + }); + + return config; + }; + + //在链接工厂获取客户端时,如果没有可用客户端时的最大等待时间。 + //超过该时间将新创建客户端。 + clientFactory.MaxWaitTime = TimeSpan.FromSeconds(1); + + clientFactory.MinCount = 2;//最小连接数 + clientFactory.MaxCount = 5;//最大连接数 + + using var cts = new CancellationTokenSource(10 * 1000); + + //获取客户端 + using (var clientFactoryResult = await clientFactory.GetClient(cts.Token)) + { + //获取到的池中的客户端 + //注意:该客户端只能在当前using作用域中使用。 + var client = clientFactoryResult.Client; + } + #endregion + } + #endregion +} diff --git a/examples/Dmtp/CustomDmtpActorConsoleApp/CustomDmtpActorConsoleApp.csproj b/examples/Dmtp/CustomDmtpActorConsoleApp/CustomDmtpActorConsoleApp.csproj index 32cf36851..f5bdf5081 100644 --- a/examples/Dmtp/CustomDmtpActorConsoleApp/CustomDmtpActorConsoleApp.csproj +++ b/examples/Dmtp/CustomDmtpActorConsoleApp/CustomDmtpActorConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,6 @@ - + diff --git a/examples/Dmtp/CustomDmtpActorConsoleApp/Program.cs b/examples/Dmtp/CustomDmtpActorConsoleApp/Program.cs index 6c4562bc2..432006637 100644 --- a/examples/Dmtp/CustomDmtpActorConsoleApp/Program.cs +++ b/examples/Dmtp/CustomDmtpActorConsoleApp/Program.cs @@ -34,7 +34,7 @@ internal class Program try { - actor.Invoke(methodName); + await actor.Invoke(methodName, CancellationToken.None); Console.WriteLine("调用成功"); } catch (Exception ex) @@ -48,9 +48,9 @@ internal class Program { var client = await new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "File" + options.VerifyToken = "File"; }) .ConfigureContainer(a => { @@ -59,10 +59,6 @@ internal class Program .ConfigurePlugins(a => { a.UseSimpleDmtpRpc(); - - a.UseDmtpHeartbeat()//使用Dmtp心跳 - .SetTick(TimeSpan.FromSeconds(3)) - .SetMaxFailCount(3); }) .BuildClientAsync(); @@ -87,9 +83,9 @@ internal class Program a.UseSimpleDmtpRpc() .RegisterRpc(new MyServer()); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "File"//连接验证口令。 + options.VerifyToken = "File";//连接验证口令。 }); await service.SetupAsync(config); diff --git a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/ISimpleDmtpRpcActor.cs b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/ISimpleDmtpRpcActor.cs index 3479c41de..3775ef581 100644 --- a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/ISimpleDmtpRpcActor.cs +++ b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/ISimpleDmtpRpcActor.cs @@ -16,7 +16,7 @@ namespace CustomDmtpActorConsoleApp.SimpleDmtpRpc; internal interface ISimpleDmtpRpcActor : IActor { - void Invoke(string methodName); + Task Invoke(string methodName, CancellationToken token); - void Invoke(string targetId, string methodName); + Task Invoke(string targetId, string methodName, CancellationToken token); } \ No newline at end of file diff --git a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/SimpleDmtpRpcActor.cs b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/SimpleDmtpRpcActor.cs index b039e85cd..b91015fa0 100644 --- a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/SimpleDmtpRpcActor.cs +++ b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Actor/SimpleDmtpRpcActor.cs @@ -15,7 +15,7 @@ using TouchSocket.Dmtp; namespace CustomDmtpActorConsoleApp.SimpleDmtpRpc; -internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor +internal class SimpleDmtpRpcActor : DisposableObject, ISimpleDmtpRpcActor { private readonly ushort m_invoke_Request = 1000; private readonly ushort m_invoke_Response = 1001; @@ -30,20 +30,21 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor public async Task InputReceivedData(DmtpMessage message) { - var byteBlock = message.BodyByteBlock; + var memory = message.Memory; + var reader = new BytesReader(memory); if (message.ProtocolFlags == this.m_invoke_Request) { try { var rpcPackage = new SimpleDmtpRpcPackage(); - rpcPackage.UnpackageRouter(ref byteBlock); + rpcPackage.UnpackageRouter(ref reader); if (rpcPackage.Route && this.DmtpActor.AllowRoute) { if (await this.DmtpActor.TryRouteAsync(new PackageRouterEventArgs(new RouteType("SimpleRpc"), rpcPackage))) { if (await this.DmtpActor.TryFindDmtpActor(rpcPackage.TargetId) is DmtpActor actor) { - await actor.SendAsync(this.m_invoke_Request, byteBlock.Memory); + await actor.SendAsync(this.m_invoke_Request, memory); return true; } else @@ -56,15 +57,23 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor rpcPackage.Status = 3; } - byteBlock.Reset(); rpcPackage.SwitchId(); - rpcPackage.Package(ref byteBlock); - await this.DmtpActor.SendAsync(this.m_invoke_Response, byteBlock.Memory); + var byteBlock = new ByteBlock(1024); + try + { + rpcPackage.Package(ref byteBlock); + await this.DmtpActor.SendAsync(this.m_invoke_Response, byteBlock.Memory); + } + finally + { + byteBlock.Dispose(); + } + } else { - rpcPackage.UnpackageBody(ref byteBlock); + rpcPackage.UnpackageBody(ref reader); _ = Task.Factory.StartNew(this.InvokeThis, rpcPackage); } } @@ -79,18 +88,18 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor try { var rpcPackage = new SimpleDmtpRpcPackage(); - rpcPackage.UnpackageRouter(ref byteBlock); + rpcPackage.UnpackageRouter(ref reader); if (this.DmtpActor.AllowRoute && rpcPackage.Route) { if (await this.DmtpActor.TryFindDmtpActor(rpcPackage.TargetId) is DmtpActor actor) { - await actor.SendAsync(this.m_invoke_Response, byteBlock.Memory); + await actor.SendAsync(this.m_invoke_Response, memory); } } else { - rpcPackage.UnpackageBody(ref byteBlock); - this.DmtpActor.WaitHandlePool.SetRun(rpcPackage); + rpcPackage.UnpackageBody(ref reader); + this.DmtpActor.WaitHandlePool.Set(rpcPackage); } } catch (Exception ex) @@ -109,7 +118,7 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor var methodModel = this.TryFindMethod.Invoke(package.MethodName); if (methodModel == null) { - var byteBlock = new ByteBlock(1024*64); + var byteBlock = new ByteBlock(1024 * 64); try { package.Status = 4; @@ -127,7 +136,7 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor try { methodModel.Method.Invoke(methodModel.Target, default); - var byteBlock = new ByteBlock(1024*64); + var byteBlock = new ByteBlock(1024 * 64); try { package.Status = 1; @@ -143,7 +152,7 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor } catch (Exception ex) { - var byteBlock = new ByteBlock(1024*64); + var byteBlock = new ByteBlock(1024 * 64); try { package.Status = 5; @@ -176,12 +185,12 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor return default; } - public void Invoke(string methodName) + public async Task Invoke(string methodName, CancellationToken token) { - this.PrivateInvoke(default, methodName); + await this.PrivateInvoke(default, methodName, token); } - public async void Invoke(string targetId, string methodName) + public async Task Invoke(string targetId, string methodName, CancellationToken token) { if (string.IsNullOrEmpty(targetId)) { @@ -195,14 +204,14 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor if (this.DmtpActor.AllowRoute && await this.TryFindDmtpRpcActor(targetId) is SimpleDmtpRpcActor actor) { - actor.Invoke(methodName); + await actor.Invoke(methodName, token); return; } - this.PrivateInvoke(targetId, methodName); + await this.PrivateInvoke(targetId, methodName, token); } - private async void PrivateInvoke(string id, string methodName) + private async Task PrivateInvoke(string id, string methodName, CancellationToken token) { var package = new SimpleDmtpRpcPackage() { @@ -211,11 +220,11 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor TargetId = id }; - var waitData = this.DmtpActor.WaitHandlePool.GetWaitData(package); + var waitData = this.DmtpActor.WaitHandlePool.GetWaitDataAsync(package); try { - var byteBlock = new ByteBlock(1024*64); + var byteBlock = new ByteBlock(1024 * 64); try { package.Package(ref byteBlock); @@ -226,10 +235,10 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor byteBlock.Dispose(); } - switch (waitData.Wait(5000)) + switch (await waitData.WaitAsync(token)) { - case WaitDataStatus.SetRunning: - var result = (SimpleDmtpRpcPackage)waitData.WaitResult; + case WaitDataStatus.Success: + var result = (SimpleDmtpRpcPackage)waitData.CompletedData; result.CheckStatus(); return; @@ -246,7 +255,7 @@ internal class SimpleDmtpRpcActor :DisposableObject, ISimpleDmtpRpcActor } finally { - this.DmtpActor.WaitHandlePool.Destroy(package.Sign); + waitData.Dispose(); } } } \ No newline at end of file diff --git a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Common/SimpleDmtpRpcPackage.cs b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Common/SimpleDmtpRpcPackage.cs index c1863edd9..0fccf5e05 100644 --- a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Common/SimpleDmtpRpcPackage.cs +++ b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/Common/SimpleDmtpRpcPackage.cs @@ -24,13 +24,13 @@ internal class SimpleDmtpRpcPackage : WaitRouterPackage public override void PackageBody(ref TByteBlock byteBlock) { base.PackageBody(ref byteBlock); - byteBlock.WriteString(this.MethodName); + WriterExtension.WriteString(ref byteBlock, this.MethodName); } public override void UnpackageBody(ref TByteBlock byteBlock) { base.UnpackageBody(ref byteBlock); - this.MethodName = byteBlock.ReadString(); + this.MethodName = ReaderExtension.ReadString(ref byteBlock); } public void CheckStatus() diff --git a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/SimpleDmtpRpcFeature.cs b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/SimpleDmtpRpcFeature.cs index 081a0477a..29f747faf 100644 --- a/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/SimpleDmtpRpcFeature.cs +++ b/examples/Dmtp/CustomDmtpActorConsoleApp/SimpleDmtpRpc/SimpleDmtpRpcFeature.cs @@ -16,11 +16,11 @@ using TouchSocket.Dmtp; namespace CustomDmtpActorConsoleApp.SimpleDmtpRpc; -internal class SimpleDmtpRpcFeature : PluginBase, IDmtpHandshakingPlugin, IDmtpReceivedPlugin +internal class SimpleDmtpRpcFeature : PluginBase, IDmtpConnectingPlugin, IDmtpReceivedPlugin { private readonly Dictionary m_pairs = new Dictionary(); - public async Task OnDmtpHandshaking(IDmtpActorObject client, DmtpVerifyEventArgs e) + public async Task OnDmtpConnecting(IDmtpActorObject client, DmtpVerifyEventArgs e) { var actor = new SimpleDmtpRpcActor(client.DmtpActor) { diff --git a/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/DispatchProxyDmtpRpcConsoleApp.csproj b/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/DispatchProxyDmtpRpcConsoleApp.csproj index cd878d4fe..e09ee2012 100644 --- a/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/DispatchProxyDmtpRpcConsoleApp.csproj +++ b/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/DispatchProxyDmtpRpcConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/Program.cs b/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/Program.cs index bc54b4df3..50d71db43 100644 --- a/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/Program.cs +++ b/examples/Dmtp/DispatchProxyDmtpRpcConsoleApp/Program.cs @@ -58,9 +58,9 @@ internal class Program a.UseDmtpRpc(); }) .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); client.ConnectAsync(); client.Logger.Info($"连接成功,Id={client.Id}"); diff --git a/examples/Dmtp/DmtpAspnetcoreConsoleApp/DmtpAspnetcoreConsoleApp.csproj b/examples/Dmtp/DmtpAspnetcoreConsoleApp/DmtpAspnetcoreConsoleApp.csproj index 177290819..ace6afa72 100644 --- a/examples/Dmtp/DmtpAspnetcoreConsoleApp/DmtpAspnetcoreConsoleApp.csproj +++ b/examples/Dmtp/DmtpAspnetcoreConsoleApp/DmtpAspnetcoreConsoleApp.csproj @@ -8,7 +8,7 @@ - + diff --git a/examples/Dmtp/DmtpAspnetcoreConsoleApp/Program.cs b/examples/Dmtp/DmtpAspnetcoreConsoleApp/Program.cs index 2d73f4fce..da40936c0 100644 --- a/examples/Dmtp/DmtpAspnetcoreConsoleApp/Program.cs +++ b/examples/Dmtp/DmtpAspnetcoreConsoleApp/Program.cs @@ -23,9 +23,9 @@ internal class Program //WebSocketDmtpClient连接 var websocketDmtpClient = new WebSocketDmtpClient(); await websocketDmtpClient.SetupAsync(new TouchSocketConfig() - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }) .SetRemoteIPHost("ws://localhost:5174/WebSocketDmtp")); await websocketDmtpClient.ConnectAsync(); @@ -34,9 +34,9 @@ internal class Program //HttpDmtpClient连接 var httpDmtpClient = new HttpDmtpClient(); await httpDmtpClient.SetupAsync(new TouchSocketConfig() - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }) .SetRemoteIPHost("http://127.0.0.1:5174")); await httpDmtpClient.ConnectAsync(); diff --git a/examples/Dmtp/DmtpChannelConsoleApp/DmtpChannelConsoleApp.csproj b/examples/Dmtp/DmtpChannelConsoleApp/DmtpChannelConsoleApp.csproj index cd878d4fe..e09ee2012 100644 --- a/examples/Dmtp/DmtpChannelConsoleApp/DmtpChannelConsoleApp.csproj +++ b/examples/Dmtp/DmtpChannelConsoleApp/DmtpChannelConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Dmtp/DmtpChannelConsoleApp/Program.cs b/examples/Dmtp/DmtpChannelConsoleApp/Program.cs index 6d085e1cb..2ab19efe5 100644 --- a/examples/Dmtp/DmtpChannelConsoleApp/Program.cs +++ b/examples/Dmtp/DmtpChannelConsoleApp/Program.cs @@ -38,13 +38,10 @@ internal class Program //HoldOn的使用,主要是解决同一个通道中,多个数据流传输的情况。 //1.创建通道,同时支持通道路由和元数据传递 - using (var channel =await client.CreateChannelAsync()) + using (var channel = await client.CreateChannelAsync()) { - //设置限速 - //channel.MaxSpeed = 1024 * 1024; - ConsoleLogger.Default.Info($"通道创建成功,即将写入"); - var bytes = new byte[1024]; + var bytes = new byte[100]; for (var i = 0; i < 100; i++)//循环100次 { @@ -65,73 +62,67 @@ internal class Program private static async Task RunComplete(IDmtpActorObject client) { - var count = 1024 * 1;//测试1Gb数据 + #region TcpDmtpClient创建Channel + var count = 1024; //1.创建通道,同时支持通道路由和元数据传递 - using (var channel =await client.CreateChannelAsync()) - { - //设置限速 - //channel.MaxSpeed = 1024 * 1024; - ConsoleLogger.Default.Info($"通道创建成功,即将写入{count}Mb数据"); - var bytes = new byte[1024 * 1024]; + using var cts = new CancellationTokenSource(1000 * 10); + var metadata = new Metadata(); + + using (var channel = await client.CreateChannelAsync(metadata, cts.Token)) + { + ConsoleLogger.Default.Info($"通道创建成功"); + var bytes = new byte[1000]; for (var i = 0; i < count; i++) { + if (!channel.CanWrite) + { + //通道不可写,即客户端可能已经断开连接 + break; + } + using var writeCts = new CancellationTokenSource(1000 * 5); //2.持续写入数据 - await channel.WriteAsync(bytes); + await channel.WriteAsync(bytes, writeCts.Token); } //3.在写入完成后调用终止指令。例如:Complete、Cancel、HoldOn、Dispose等 await channel.CompleteAsync("我完成了"); ConsoleLogger.Default.Info("通道写入结束"); } + #endregion + } private static async Task GetTcpDmtpClient() { var client = await new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Channel" + options.VerifyToken = "Channel"; }) - .SetSendTimeout(0) .ConfigureContainer(a => { a.AddConsoleLogger(); }) - .ConfigurePlugins(a => - { - a.Add(); + #region Dmtp心跳重连插件 + .ConfigurePlugins(a => + { + a.Add(); - //使用重连 - a.UseDmtpReconnection() - .UsePolling(TimeSpan.FromSeconds(3))//使用轮询,每3秒检测一次 - .SetActionForCheck(async (c, i) =>//重新定义检活策略 - { - //方法1,直接判断是否在握手状态。使用该方式,最好和心跳插件配合使用。因为如果直接断网,则检测不出来 - //await Task.CompletedTask;//消除Task - //return c.Online;//判断是否在握手状态 + //使用重连 + a.UseReconnection(options => + { + //重连间隔3秒 + options.PollingInterval = TimeSpan.FromSeconds(3); - //方法2,直接ping,如果true,则客户端必在线。如果false,则客户端不一定不在线,原因是可能当前传输正在忙 - if (await c.PingAsync()) - { - return true; - } - //返回false时可以判断,如果最近活动时间不超过3秒,则猜测客户端确实在忙,所以跳过本次重连 - else if (DateTime.Now - c.GetLastActiveTime() < TimeSpan.FromSeconds(3)) - { - return null; - } - //否则,直接重连。 - else - { - return false; - } - }); + //使用Dmtp状态、心跳等联合检测作为连接状态检查依据。 + options.UseDmtpCheckAction(); + }); + }) + #endregion - - }) .BuildClientAsync(); client.Logger.Info("连接成功"); @@ -152,9 +143,9 @@ internal class Program { a.Add(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Channel"//连接验证口令。 + options.VerifyToken = "Channel";//连接验证口令。 }); await service.SetupAsync(config); @@ -164,6 +155,7 @@ internal class Program } } +#region TcpDmtpService使用插件订阅Channel internal class MyPlugin : PluginBase, IDmtpCreatedChannelPlugin { private readonly ILog m_logger; @@ -175,30 +167,41 @@ internal class MyPlugin : PluginBase, IDmtpCreatedChannelPlugin public async Task OnDmtpCreatedChannel(IDmtpActorObject client, CreateChannelEventArgs e) { + //1.订阅通道 if (client.TrySubscribeChannel(e.ChannelId, out var channel)) { - //设定读取超时时间 - //channel.Timeout = TimeSpan.FromSeconds(30); + //2.准备处理通道数据 using (channel) { this.m_logger.Info("通道开始接收"); - //此判断主要是探测是否有Hold操作 - while (channel.CanMoveNext) + long count = 0; + + //3.持续读取数据 + while (channel.CanRead) { - long count = 0; - foreach (var byteBlock in channel) + //4.设置读取超时 + using var cts = new CancellationTokenSource(10 * 1000); + + //5.读取到的数据 + var memory = await channel.ReadAsync(cts.Token); + + //6.可以判断通道状态 + if (channel.Status == ChannelStatus.HoldOn) { - //这里处理数据 - count += byteBlock.Length; - this.m_logger.Info($"通道已接收:{count}字节"); + Console.WriteLine($"HoldOn:{channel.LastOperationMes}"); } - this.m_logger.Info($"通道接收结束,状态={channel.Status},短语={channel.LastOperationMes},共接收{count / (1048576.0):0.00}Mb字节"); + //这里处理数据 + count += memory.Length; + this.m_logger.Info($"通道已接收:{count}字节"); } + + this.m_logger.Info($"通道接收结束,状态={channel.Status},短语={channel.LastOperationMes},共接收{count / (1048576.0):0.00}Mb字节"); } } await e.InvokeNext(); } -} \ No newline at end of file +} +#endregion diff --git a/examples/Dmtp/DmtpConsoleApp/DmtpConsoleApp.csproj b/examples/Dmtp/DmtpConsoleApp/DmtpConsoleApp.csproj index 3d64cc538..1b5465cb5 100644 --- a/examples/Dmtp/DmtpConsoleApp/DmtpConsoleApp.csproj +++ b/examples/Dmtp/DmtpConsoleApp/DmtpConsoleApp.csproj @@ -7,26 +7,8 @@ enable - - - + diff --git a/examples/Dmtp/DmtpConsoleApp/Program.cs b/examples/Dmtp/DmtpConsoleApp/Program.cs index 1d0e241d7..87383443a 100644 --- a/examples/Dmtp/DmtpConsoleApp/Program.cs +++ b/examples/Dmtp/DmtpConsoleApp/Program.cs @@ -53,17 +53,17 @@ internal class Program //此处使用委托注册插件。和类插件功能一样 a.AddDmtpReceivedPlugin(async (c, e) => { - var msg = e.DmtpMessage.BodyByteBlock.ToString(); + var msg = e.DmtpMessage.Memory.Span.ToString(Encoding.UTF8); await Console.Out.WriteLineAsync($"收到服务器回信,协议{e.DmtpMessage.ProtocolFlags}收到信息,内容:{msg}"); await e.InvokeNext(); }); }) .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp",//设置Token验证连接 - Id = "defaultId",//设置默认Id - Metadata = new Metadata().Add("a", "a")//设置Metadata,可以传递更多的验证信息 + options.VerifyToken = "Dmtp";//设置Token验证连接 + options.Id = "defaultId";//设置默认Id + options.Metadata = new Metadata().Add("a", "a");//设置Metadata,可以传递更多的验证信息 })); await client.ConnectAsync(); @@ -76,8 +76,12 @@ internal class Program //DmtpRpc会用[20,25)的协议。 //文件传输会用[25,35)的协议。 + + #region Dmtp发送消息 //此处使用1000,基本就不会冲突。 await client.SendAsync(1000, Encoding.UTF8.GetBytes("hello")); + #endregion + } /// @@ -86,25 +90,7 @@ internal class Program /// private static async Task Connect_2() { - using var tcpClient = new TcpClient();//创建一个普通的tcp客户端。 - tcpClient.Received = (client, e) => - { - //此处接收服务器返回的消息 - - var head = e.ByteBlock.ToArray(0, 2); - e.ByteBlock.Seek(2, SeekOrigin.Begin); - var flags = e.ByteBlock.ReadUInt16(EndianType.Big); - var length = e.ByteBlock.ReadInt32(EndianType.Big); - - var json = e.ByteBlock.Span.ToString(Encoding.UTF8); - - ConsoleLogger.Default.Info($"收到响应:flags={flags},length={length},json={json.Replace("\r\n", string.Empty).Replace(" ", string.Empty)}"); - - - return Task.CompletedTask; - }; - - #region 基础Flag协议 + #region Dmtp基础Flag协议 Console.WriteLine($"{nameof(DmtpActor.P0_Close)}-flag-->{DmtpActor.P0_Close}"); Console.WriteLine($"{nameof(DmtpActor.P1_Handshake_Request)}-flag-->{DmtpActor.P1_Handshake_Request}"); @@ -119,7 +105,26 @@ internal class Program #endregion 基础Flag协议 - #region 连接 + #region Dmtp以普通Tcp模拟连接 + using var tcpClient = new TcpClient();//创建一个普通的tcp客户端。 + tcpClient.Received = (client, e) => + { + //此处接收服务器返回的消息 + + var span = e.Memory.Span; + var head = span[..2]; + + span = span[2..]; + var flags = span.ReadValue(EndianType.Big); + var length = span.ReadValue(EndianType.Big); + + var json = e.Memory.Span.ToString(Encoding.UTF8); + + ConsoleLogger.Default.Info($"收到响应:flags={flags},length={length},json={json.Replace("\r\n", string.Empty).Replace(" ", string.Empty)}"); + + + return Task.CompletedTask; + }; //开始链接服务器 await tcpClient.ConnectAsync("127.0.0.1:7789"); @@ -133,36 +138,38 @@ internal class Program //将json转为utf-8编码。 var jsonBytes = Encoding.UTF8.GetBytes(json); - using (var byteBlock = new ByteBlock(1024*64)) + using (var byteBlock = new ByteBlock(1024 * 64)) { //按照Head+Flags+Length+Data的格式。 byteBlock.Write(Encoding.ASCII.GetBytes("dm")); - byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes((ushort)1)); - byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes(jsonBytes.Length)); + byteBlock.WriteValue((ushort)1, EndianType.Big); + byteBlock.WriteValue(jsonBytes.Length, EndianType.Big); byteBlock.Write(jsonBytes); await tcpClient.SendAsync(byteBlock.Memory); } - #endregion 连接 + #endregion - #region Ping + #region Dmtp以普通Tcp模拟Ping json = "{\"Sign\":2,\"Route\":false,\"SourceId\":null,\"TargetId\":null}"; jsonBytes = Encoding.UTF8.GetBytes(json); - using (var byteBlock = new ByteBlock(1024*64)) + using (var byteBlock = new ByteBlock(1024 * 64)) { //按照Head+Flags+Length+Data的格式。 byteBlock.Write(Encoding.ASCII.GetBytes("dm")); - byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes((ushort)5)); - byteBlock.Write(TouchSocketBitConverter.BigEndian.GetBytes(jsonBytes.Length)); + byteBlock.WriteValue((ushort)5, EndianType.Big); + byteBlock.WriteValue(jsonBytes.Length, EndianType.Big); byteBlock.Write(jsonBytes); await tcpClient.SendAsync(byteBlock.Memory); } - #endregion Ping + #endregion + + await Task.Delay(2000); } @@ -182,11 +189,11 @@ internal class Program a.AddConsoleLogger(); }) .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp",//设置Token验证连接 - Id = "defaultId",//设置默认Id - Metadata = new Metadata().Add("a", "a")//设置Metadata,可以传递更多的验证信息 + options.VerifyToken = "Dmtp";//设置Token验证连接 + options.Id = "defaultId";//设置默认Id + options.Metadata = new Metadata().Add("a", "a");//设置Metadata,可以传递更多的验证信息 })); await client.ConnectAsync(); @@ -209,9 +216,9 @@ internal class Program a.Add(); a.Add(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp"//设定连接口令,作用类似账号密码 + options.VerifyToken = "Dmtp";//设定连接口令,作用类似账号密码 }); await service.SetupAsync(config); @@ -220,11 +227,28 @@ internal class Program service.Logger.Info($"{service.GetType().Name}已启动"); return service; } + + private static async Task CreateConfig() + { + var config = new TouchSocketConfig(); + + #region Dmtp配置 + config.SetDmtpOption(options => + { + options.Id = Guid.NewGuid().ToString();//仅当在客户端,连接时,如果指定Id,则该链接将使用设定的id。 + options.VerifyToken = "Dmtp";//连接口令,作用类似账号密码 + options.VerifyTimeout = TimeSpan.FromSeconds(3);//仅当在服务器,验证连接的超时时间 + options.Metadata = new Metadata().Add("a", "a");//仅当在客户端,连接时,可以传递更多的验证信息 + }); + #endregion + + } } -internal class MyVerifyPlugin : PluginBase, IDmtpHandshakingPlugin +#region Dmtp动态验证连接 +internal class MyVerifyPlugin : PluginBase, IDmtpConnectingPlugin { - public async Task OnDmtpHandshaking(IDmtpActorObject client, DmtpVerifyEventArgs e) + public async Task OnDmtpConnecting(IDmtpActorObject client, DmtpVerifyEventArgs e) { if (e.Metadata["a"] != "a") { @@ -235,23 +259,26 @@ internal class MyVerifyPlugin : PluginBase, IDmtpHandshakingPlugin } if (e.Token == "Dmtp") { - e.IsPermitOperation = true; - e.Handled = true; + e.IsPermitOperation = true;//允许连接 + e.Handled = true;//表示该消息已在此处处理。 return; } await e.InvokeNext(); } } +#endregion + +#region Dmtp接收数据 internal class MyFlagsPlugin : PluginBase, IDmtpReceivedPlugin { public async Task OnDmtpReceived(IDmtpActorObject client, DmtpMessageEventArgs e) { if (e.DmtpMessage.ProtocolFlags == 1000) { - //判断完协议以后,从 e.DmtpMessage.BodyByteBlock可以拿到实际的数据 - var msg = e.DmtpMessage.BodyByteBlock.ToString(); + //判断完协议以后,从 e.DmtpMessage.Memory可以拿到实际的数据 + var msg = e.DmtpMessage.Memory.Span.ToUtf8String(); await Console.Out.WriteLineAsync($"从协议{e.DmtpMessage.ProtocolFlags}收到信息,内容:{msg}"); //向客户端回发消息 @@ -262,4 +289,5 @@ internal class MyFlagsPlugin : PluginBase, IDmtpReceivedPlugin //flags不满足,调用下一个插件 await e.InvokeNext(); } -} \ No newline at end of file +} +#endregion diff --git a/examples/Dmtp/DmtpRedisConsoleApp/DmtpRedisConsoleApp.csproj b/examples/Dmtp/DmtpRedisConsoleApp/DmtpRedisConsoleApp.csproj index 177290819..ace6afa72 100644 --- a/examples/Dmtp/DmtpRedisConsoleApp/DmtpRedisConsoleApp.csproj +++ b/examples/Dmtp/DmtpRedisConsoleApp/DmtpRedisConsoleApp.csproj @@ -8,7 +8,7 @@ - + diff --git a/examples/Dmtp/DmtpRedisConsoleApp/Program.cs b/examples/Dmtp/DmtpRedisConsoleApp/Program.cs index 91516f823..82861230a 100644 --- a/examples/Dmtp/DmtpRedisConsoleApp/Program.cs +++ b/examples/Dmtp/DmtpRedisConsoleApp/Program.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 // 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 // CSDN博客:https://blog.csdn.net/qq_40374647 @@ -24,16 +24,18 @@ internal class Program var service = await GetTcpDmtpService(); var client = await GetTcpDmtpClient(); + #region Redis基本使用 + //获取Redis var redis = client.GetDmtpRedisActor(); //执行Set - var result = await redis.SetAsync("1", "1"); + var result = await redis.SetAsync("1", "1", 60 * 1000, CancellationToken.None); client.Logger.Info($"Set result={result}"); client.Logger.Info($"ContainsCache result={await redis.ContainsCacheAsync("1")}"); //执行Get - var result1 = await redis.GetAsync("1"); + var result1 = await redis.GetAsync("1", CancellationToken.None); client.Logger.Info($"Get result={result}"); //执行Remove @@ -41,17 +43,21 @@ internal class Program client.Logger.Info($"Get result={result}"); await redis.ClearCacheAsync(); + #endregion Redis基本使用 + Console.ReadKey(); } private static async Task GetTcpDmtpClient() { + #region Redis客户端配置 + var client = new TcpDmtpClient(); await client.SetupAsync(new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }) .ConfigureContainer(a => { @@ -63,10 +69,14 @@ internal class Program })); await client.ConnectAsync(); return client; + + #endregion Redis客户端配置 } private static async Task GetTcpDmtpService() { + #region Redis服务器配置 + var service = await new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => @@ -75,15 +85,44 @@ internal class Program }) .ConfigurePlugins(a => { - a.UseDmtpRedis()//必须添加Redis访问插件 - .SetCache(new MemoryCache());//这里可以设置缓存持久化,此处仍然是使用内存缓存。 + a.UseDmtpRedis(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp"//连接验证口令。 + options.VerifyToken = "Dmtp";//连接验证口令。 }) .BuildServiceAsync();//此处build相当于new TcpDmtpService,然后SetupAsync,然后StartAsync。 service.Logger.Info("服务器成功启动"); return service; + + #endregion Redis服务器配置 } -} \ No newline at end of file + + private static async Task GetTcpDmtpServiceWithCache() + { + #region Redis缓存持久化配置 + + var service = await new TouchSocketConfig()//配置 + .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.UseDmtpRedis(options => + { + options.Cache = new MemoryCache>();//这里可以设置缓存持久化,此处仍然是使用内存缓存。 + }); + }) + .SetDmtpOption(options => + { + options.VerifyToken = "Dmtp";//连接验证口令。 + }) + .BuildServiceAsync();//此处build相当于new TcpDmtpService,然后SetupAsync,然后StartAsync。 + service.Logger.Info("服务器成功启动"); + return service; + + #endregion Redis缓存持久化配置 + } +} diff --git a/examples/Dmtp/DmtpRpcClientApp/DmtpRpcClientApp.csproj b/examples/Dmtp/DmtpRpcClientApp/DmtpRpcClientApp.csproj index 4a7641c2b..867bd928f 100644 --- a/examples/Dmtp/DmtpRpcClientApp/DmtpRpcClientApp.csproj +++ b/examples/Dmtp/DmtpRpcClientApp/DmtpRpcClientApp.csproj @@ -1,4 +1,4 @@ - + Exe net9.0-windows @@ -6,11 +6,11 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/examples/Dmtp/DmtpRpcClientApp/Form1.cs b/examples/Dmtp/DmtpRpcClientApp/Form1.cs index d7ef9c5e2..61fea3590 100644 --- a/examples/Dmtp/DmtpRpcClientApp/Form1.cs +++ b/examples/Dmtp/DmtpRpcClientApp/Form1.cs @@ -12,7 +12,6 @@ using RpcProxy; using System; -using System.Threading.Tasks; using System.Windows.Forms; using TouchSocket.Core; using TouchSocket.Dmtp; @@ -36,7 +35,7 @@ public partial class Form1 : Form //直接调用时,第一个参数为调用键,服务类全名+方法名(必须全小写) //第二个参数为调用配置参数,可设置调用超时时间,取消调用等功能。 //后续参数为调用参数。 - var result =await this.m_client.GetDmtpRpcActor().InvokeTAsync("Login", InvokeOption.WaitInvoke, this.textBox1.Text, this.textBox2.Text); + var result = await this.m_client.GetDmtpRpcActor().InvokeTAsync("Login", InvokeOption.WaitInvoke, this.textBox1.Text, this.textBox2.Text); MessageBox.Show(result.ToString()); } @@ -72,41 +71,17 @@ public partial class Form1 : Form { a.UseDmtpRpc(); - //使用心跳保活,或者避免异常连接。达到最大失败次数会断开,不会重连。 - a.UseDmtpHeartbeat() - .SetTick(TimeSpan.FromSeconds(3)) - .SetMaxFailCount(3); - //使用重连 - a.UseDmtpReconnection() - .UsePolling(TimeSpan.FromSeconds(3)) - .SetActionForCheck(async (c, i) =>//重新定义检活策略 + a.UseReconnection(options => { - //方法1,直接判断是否在握手状态。使用该方式,最好和心跳插件配合使用 - //await Task.CompletedTask;//消除Task - //return c.IsHandshaked;//判断是否在握手状态 + options.PollingInterval = TimeSpan.FromSeconds(3); - //方法2,直接ping,如果true,则客户端必在线。如果false,则客户端不一定不在线,原因是可能当前传输正在忙 - if (await c.PingAsync()) - { - return true; - } - //返回false时可以判断,如果最近活动时间不超过3秒,则猜测客户端确实在忙,所以跳过本次重连 - else if (DateTime.Now - c.GetLastActiveTime() < TimeSpan.FromSeconds(3)) - { - return null; - } - //否则,直接重连。 - else - { - return false; - } }); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Rpc", - Id = "asdasd" + options.VerifyToken = "Rpc"; + options.Id = "asdasd"; })); this.m_client.ConnectAsync(); diff --git a/examples/Dmtp/DmtpRpcClientApp/Program.cs b/examples/Dmtp/DmtpRpcClientApp/Program.cs index 6e8419082..529fb2a4c 100644 --- a/examples/Dmtp/DmtpRpcClientApp/Program.cs +++ b/examples/Dmtp/DmtpRpcClientApp/Program.cs @@ -55,11 +55,11 @@ internal static class Program }) .ConfigurePlugins(a => { - a.Add(typeof(IDmtpHandshakingPlugin), async (c, e) => + a.Add(typeof(IDmtpConnectingPlugin), async (c, e) => { await e.InvokeNext(); }); - a.Add(typeof(IDmtpHandshakedPlugin), async (c, e) => + a.Add(typeof(IDmtpConnectedPlugin), async (c, e) => { await e.InvokeNext(); }); @@ -70,9 +70,9 @@ internal static class Program { a.AddConsoleLogger(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Rpc" + options.VerifyToken = "Rpc"; }); await service.SetupAsync(config); diff --git a/examples/Dmtp/DmtpRpcClientApp/RpcProxy.cs b/examples/Dmtp/DmtpRpcClientApp/RpcProxy.cs index c5c61dbfa..96bf780c2 100644 --- a/examples/Dmtp/DmtpRpcClientApp/RpcProxy.cs +++ b/examples/Dmtp/DmtpRpcClientApp/RpcProxy.cs @@ -32,14 +32,14 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default); + System.Boolean Login(System.String account, System.String password, InvokeOption invokeOption = default); /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default); + Task LoginAsync(System.String account, System.String password, InvokeOption invokeOption = default); /// ///注册 @@ -47,14 +47,14 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - System.Boolean Register(RegisterModel register, IInvokeOption invokeOption = default); + System.Boolean Register(RegisterModel register, InvokeOption invokeOption = default); /// ///注册 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task RegisterAsync(RegisterModel register, IInvokeOption invokeOption = default); + Task RegisterAsync(RegisterModel register, InvokeOption invokeOption = default); /// ///性能测试 @@ -62,14 +62,14 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - System.Int32 Performance(System.Int32 a, IInvokeOption invokeOption = default); + System.Int32 Performance(System.Int32 a, InvokeOption invokeOption = default); /// ///性能测试 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task PerformanceAsync(System.Int32 a, IInvokeOption invokeOption = default); + Task PerformanceAsync(System.Int32 a, InvokeOption invokeOption = default); /// ///测试out @@ -77,14 +77,14 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - System.Boolean OutBytes(System.Byte[] bytes, IInvokeOption invokeOption = default); + System.Boolean OutBytes(System.Byte[] bytes, InvokeOption invokeOption = default); /// ///测试out /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task OutBytesAsync(System.Byte[] bytes, IInvokeOption invokeOption = default); + Task OutBytesAsync(System.Byte[] bytes, InvokeOption invokeOption = default); } public class MyRpcServer : IMyRpcServer @@ -100,7 +100,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public System.Boolean Login(System.String account, System.String password, IInvokeOption invokeOption = default) + public System.Boolean Login(System.String account, System.String password, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -113,7 +113,7 @@ namespace RpcProxy /// ///登录 /// - public async Task LoginAsync(System.String account, System.String password, IInvokeOption invokeOption = default) + public async Task LoginAsync(System.String account, System.String password, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -129,7 +129,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public System.Boolean Register(RegisterModel register, IInvokeOption invokeOption = default) + public System.Boolean Register(RegisterModel register, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -142,7 +142,7 @@ namespace RpcProxy /// ///注册 /// - public async Task RegisterAsync(RegisterModel register, IInvokeOption invokeOption = default) + public async Task RegisterAsync(RegisterModel register, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -158,7 +158,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public System.Int32 Performance(System.Int32 a, IInvokeOption invokeOption = default) + public System.Int32 Performance(System.Int32 a, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -171,7 +171,7 @@ namespace RpcProxy /// ///性能测试 /// - public async Task PerformanceAsync(System.Int32 a, IInvokeOption invokeOption = default) + public async Task PerformanceAsync(System.Int32 a, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -187,7 +187,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public System.Boolean OutBytes(System.Byte[] bytes, IInvokeOption invokeOption = default) + public System.Boolean OutBytes(System.Byte[] bytes, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -200,7 +200,7 @@ namespace RpcProxy /// ///测试out /// - public async Task OutBytesAsync(System.Byte[] bytes, IInvokeOption invokeOption = default) + public async Task OutBytesAsync(System.Byte[] bytes, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -219,7 +219,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static System.Boolean Login(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient : + public static System.Boolean Login(this TClient client, System.String account, System.String password, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] @_parameters = new object[] { account, password }; @@ -229,7 +229,7 @@ namespace RpcProxy /// ///登录 /// - public static async Task LoginAsync(this TClient client, System.String account, System.String password, IInvokeOption invokeOption = default) where TClient : + public static async Task LoginAsync(this TClient client, System.String account, System.String password, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] parameters = new object[] { account, password }; @@ -242,7 +242,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static System.Boolean Register(this TClient client, RegisterModel register, IInvokeOption invokeOption = default) where TClient : + public static System.Boolean Register(this TClient client, RegisterModel register, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] @_parameters = new object[] { register }; @@ -252,7 +252,7 @@ namespace RpcProxy /// ///注册 /// - public static async Task RegisterAsync(this TClient client, RegisterModel register, IInvokeOption invokeOption = default) where TClient : + public static async Task RegisterAsync(this TClient client, RegisterModel register, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] parameters = new object[] { register }; @@ -265,7 +265,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static System.Int32 Performance(this TClient client, System.Int32 a, IInvokeOption invokeOption = default) where TClient : + public static System.Int32 Performance(this TClient client, System.Int32 a, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] @_parameters = new object[] { a }; @@ -275,7 +275,7 @@ namespace RpcProxy /// ///性能测试 /// - public static async Task PerformanceAsync(this TClient client, System.Int32 a, IInvokeOption invokeOption = default) where TClient : + public static async Task PerformanceAsync(this TClient client, System.Int32 a, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] parameters = new object[] { a }; @@ -288,7 +288,7 @@ namespace RpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static System.Boolean OutBytes(this TClient client, System.Byte[] bytes, IInvokeOption invokeOption = default) where TClient : + public static System.Boolean OutBytes(this TClient client, System.Byte[] bytes, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] @_parameters = new object[] { bytes }; @@ -298,7 +298,7 @@ namespace RpcProxy /// ///测试out /// - public static async Task OutBytesAsync(this TClient client, System.Byte[] bytes, IInvokeOption invokeOption = default) where TClient : + public static async Task OutBytesAsync(this TClient client, System.Byte[] bytes, InvokeOption invokeOption = default) where TClient : TouchSocket.Rpc.IRpcClient { object[] parameters = new object[] { bytes }; diff --git a/examples/Dmtp/DmtpRpcClientConsoleApp/DmtpRpcClientConsoleApp.csproj b/examples/Dmtp/DmtpRpcClientConsoleApp/DmtpRpcClientConsoleApp.csproj index d5ec6da5e..e3c1adb40 100644 --- a/examples/Dmtp/DmtpRpcClientConsoleApp/DmtpRpcClientConsoleApp.csproj +++ b/examples/Dmtp/DmtpRpcClientConsoleApp/DmtpRpcClientConsoleApp.csproj @@ -12,6 +12,7 @@ - + + diff --git a/examples/Dmtp/DmtpRpcClientConsoleApp/Program.cs b/examples/Dmtp/DmtpRpcClientConsoleApp/Program.cs index 0a868b7a5..edf7495eb 100644 --- a/examples/Dmtp/DmtpRpcClientConsoleApp/Program.cs +++ b/examples/Dmtp/DmtpRpcClientConsoleApp/Program.cs @@ -10,6 +10,7 @@ // 感谢您的下载和使用 //------------------------------------------------------------------------------ +using MemoryPack; using RpcProxy; using TouchSocket.Core; using TouchSocket.Dmtp; @@ -68,11 +69,10 @@ internal class Program //创建一个指定时间可取消令箭源,可用于取消Rpc的调用。 using (var tokenSource = new CancellationTokenSource(5000)) { - var invokeOption = new DmtpInvokeOption()//调用配置 + var invokeOption = new DmtpInvokeOption(5000)//调用配置 { FeedbackType = FeedbackType.WaitInvoke,//调用反馈类型 SerializationType = SerializationType.FastBinary,//序列化类型 - Timeout = 5000,//调用超时设置 Token = tokenSource.Token//配置可取消令箭 }; @@ -110,33 +110,64 @@ internal class Program { var client = await GetTcpDmtpClient(); + #region DmtpRpc直接调用 //设置调用配置 - var tokenSource = new CancellationTokenSource();//可取消令箭源,可用于取消Rpc的调用 + using var cts = new CancellationTokenSource(5000);//可取消令箭源,可用于取消Rpc的调用 var invokeOption = new DmtpInvokeOption()//调用配置 { FeedbackType = FeedbackType.WaitInvoke,//调用反馈类型 SerializationType = SerializationType.FastBinary,//序列化类型 - Timeout = 5000,//调用超时设置 - Token = tokenSource.Token//配置可取消令箭 + Token = cts.Token//配置可取消令箭 }; + //获取RpcActor,用于后续的rpc调用 + var rpcActor = client.GetDmtpRpcActor(); - var sum = await client.GetDmtpRpcActor().InvokeTAsync("Add", invokeOption, 10, 20); + //调用Add方法 + var sum = await rpcActor.InvokeTAsync("Add", invokeOption, 10, 20); client.Logger.Info($"调用Add方法成功,结果:{sum}"); + #endregion + } + private static async Task RunInvokeWithProxy() + { + using var client = await GetTcpDmtpClient(); + + #region DmtpRpc代理调用 + //设置调用配置 + using var cts = new CancellationTokenSource(5000);//可取消令箭源,可用于取消Rpc的调用 + var invokeOption = new DmtpInvokeOption()//调用配置 + { + FeedbackType = FeedbackType.WaitInvoke,//调用反馈类型 + SerializationType = SerializationType.FastBinary,//序列化类型 + Token = cts.Token//配置可取消令箭 + }; + //获取RpcActor,用于后续的rpc调用 + var rpcActor = client.GetDmtpRpcActor(); + + //调用Add方法 + var sum = await rpcActor.AddAsync(10, 20, invokeOption); + client.Logger.Info($"调用Add方法成功,结果:{sum}"); + #endregion + + } + + #region DmtpRpc客户端请求流数据 private static async Task RunRpcPullChannel() { using var client = await GetTcpDmtpClient(); var status = ChannelStatus.Default; var size = 0; - var channel =await client.CreateChannelAsync();//创建通道 - var task = Task.Run(() =>//这里必须用异步 + var channel = await client.CreateChannelAsync();//创建通道 + var task = Task.Run(async () =>//这里必须用异步 { using (channel) { - foreach (var currentByteBlock in channel) + while (channel.CanRead) { - size += currentByteBlock.Length;//此处可以处理传递来的流数据 + using var cts = new CancellationTokenSource(10 * 1000); + var memory = await channel.ReadAsync(cts.Token); + size += memory.Length; } status = channel.Status;//最后状态 } @@ -145,7 +176,9 @@ internal class Program await task;//等待异步接收完成 Console.WriteLine($"状态:{status},size={size}"); } + #endregion + #region DmtpRpc客户端推送流数据 private static async Task RunRpcPushChannel() { using var client = await GetTcpDmtpClient(); @@ -168,33 +201,57 @@ internal class Program await task;//等待异步接收完成 Console.WriteLine($"状态:{status},result={result}"); } + #endregion + + private static async Task CreateDmtpRpcClient() + { + #region 创建DmtpRpc客户端 + var client = new TcpDmtpClient(); + await client.SetupAsync(new TouchSocketConfig() + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + //启用dmtp rpc插件 + a.UseDmtpRpc(); + }) + .SetRemoteIPHost("127.0.0.1:7789") + .SetDmtpOption(options => + { + options.VerifyToken = "Dmtp"; + })); + await client.ConnectAsync(); + #endregion + } private static async Task GetTcpDmtpClient() { var client = new TcpDmtpClient(); await client.SetupAsync(new TouchSocketConfig() - .ConfigureContainer(a => - { - a.AddConsoleLogger(); - a.AddRpcStore(store => - { - store.RegisterServer(); - }); - }) + + #region 客户端注册反向DmtpRpc服务 + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + a.AddRpcStore(store => + { + store.RegisterServer(); + }); + }) + #endregion .ConfigurePlugins(a => { - a.UseDmtpRpc() - //.SetSerializationSelector(new MySerializationSelector())//自定义序列化器 - .SetCreateDmtpRpcActor((actor, serverprovider, dispatcher) => new MyDmtpRpcActor(actor, serverprovider, dispatcher)); - - a.UseDmtpHeartbeat() - .SetTick(TimeSpan.FromSeconds(3)) - .SetMaxFailCount(3); + a.UseDmtpRpc(options => + { + options.SetCreateDmtpRpcActor((actor, serverprovider, dispatcher) => new MyDmtpRpcActor(actor, serverprovider, dispatcher)); + }); }) .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); await client.ConnectAsync(); @@ -206,6 +263,7 @@ internal class Program } } +#region DmtpRpc限制代理接口声明 internal interface IRpcClient1 : IDmtpRpcActor { } @@ -220,7 +278,44 @@ internal class MyDmtpRpcActor : DmtpRpcActor, IRpcClient1, IRpcClient2 { } } +#endregion +#region DmtpRpc限制代理接口配置 +internal class LimitInterfaceExample +{ + public async Task ConfigLimitInterface() + { + var client = new TcpDmtpClient(); + await client.SetupAsync(new TouchSocketConfig() + .ConfigurePlugins(a => + { + a.UseDmtpRpc(options => + { + options.SetCreateDmtpRpcActor((actor, serverprovider, dispatcher) => new MyDmtpRpcActor(actor, serverprovider, dispatcher)); + }); + }) + .SetRemoteIPHost("127.0.0.1:7789") + .SetDmtpOption(options => + { + options.VerifyToken = "Rpc";//连接验证口令。 + })); + await client.ConnectAsync(); + } +} +#endregion + +#region DmtpRpc限制代理接口使用 +internal class UseLimitInterfaceExample +{ + public void UseLimitInterface(TcpDmtpClient client) + { + IRpcClient1 rpcClient1 = client.GetDmtpRpcActor(); + IRpcClient2 rpcClient2 = client.GetDmtpRpcActor(); + } +} +#endregion + +#region 声明反向DmtpRpc服务 internal partial class MyClientRpcServer : SingletonRpcServer { private readonly ILog m_logger; @@ -238,18 +333,206 @@ internal partial class MyClientRpcServer : SingletonRpcServer } } +#endregion + /// /// 序列化选择器 /// public class MySerializationSelector : ISerializationSelector { - public object DeserializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, Type parameterType) where TByteBlock : IByteBlock + public object DeserializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, Type parameterType) where TByteBlock : IBytesReader { throw new NotImplementedException(); } - public void SerializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, in object parameter) where TByteBlock : IByteBlock + public void SerializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, in object parameter) where TByteBlock : IBytesWriter { throw new NotImplementedException(); } -} \ No newline at end of file +} + +#region DmtpRpc配置路由 +internal class ConfigureRouteExample +{ + public void ConfigureRoute() + { + var service = new TcpDmtpService(); + var config = new TouchSocketConfig() + .ConfigureContainer(a => + { + a.AddDmtpRouteService(); + a.AddConsoleLogger(); + }); + } +} +#endregion + +#region DmtpRpc设置最大包大小 +internal class SetMaxPackageSizeExample +{ + public void ConfigMaxPackageSize() + { + var config = new TouchSocketConfig();//配置 + config.SetAdapterOption(options => + { + options.MaxPackageSize = 10 * 1024 * 1024;//设置最大包大小为10MB + }); + } +} +#endregion + +#region DmtpRpc配置序列化选择器 +internal class ConfigureSerializationSelectorExample +{ + public void ConfigSerializationSelector() + { + var config = new TouchSocketConfig() + .ConfigurePlugins(a => + { + a.UseDmtpRpc(options => + { + options.ConfigureDefaultSerializationSelector(selector => + { + selector.JsonSerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; + selector.FastSerializerContext = default; + }); + }); + }); + } +} +#endregion + +#region DmtpRpc自定义序列化配置 +internal class CustomSerializationExample +{ + public void ConfigCustomSerialization() + { + var config = new TouchSocketConfig() + .ConfigurePlugins(a => + { + a.UseDmtpRpc(options => + { + options.SerializationSelector = new MemoryPackSerializationSelector(); + }); + }); + } +} + +public class MemoryPackSerializationSelector : ISerializationSelector +{ + public object DeserializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, Type parameterType) where TByteBlock : IBytesReader + { + var len = ReaderExtension.ReadValue(ref byteBlock); + var span = ReaderExtension.ReadToSpan(ref byteBlock, len); + return MemoryPackSerializer.Deserialize(parameterType, span); + } + + public void SerializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, in object parameter) where TByteBlock : IBytesWriter + { + var writerAnchor = new WriterAnchor(ref byteBlock, 4); + + var memoryPackWriter = new MemoryPackWriter(ref byteBlock, null); + + MemoryPackSerializer.Serialize(parameter.GetType(), ref memoryPackWriter, parameter); + + var span = writerAnchor.Rewind(ref byteBlock, out var len); + span.WriteValue(memoryPackWriter.WrittenCount); + } +} +#endregion + +#region DmtpRpc使用自定义序列化类型 +internal class UseCustomSerializationTypeExample +{ + public async Task UseCustomSerializationType() + { + var client = new TcpDmtpClient(); + var invokeOption = new DmtpInvokeOption()//调用配置 + { + FeedbackType = FeedbackType.WaitInvoke,//调用反馈类型 + SerializationType = (SerializationType)4,//序列化类型 + Timeout = 5000,//调用超时设置 + }; + } +} +#endregion + +#region DmtpRpc使用Metadata +internal partial class MetadataRpcServer : SingletonRpcServer +{ + [DmtpRpc(MethodInvoke = true)] + public Metadata CallContextMetadata(IDmtpRpcCallContext callContext) + { + return callContext.Metadata; + } +} +#endregion + +#region DmtpRpc客户端使用Metadata +internal class ClientUseMetadataExample +{ + public async Task UseMetadata() + { + var client = new TcpDmtpClient(); + var invokeOption = new DmtpInvokeOption()//调用配置 + { + FeedbackType = FeedbackType.WaitInvoke,//调用反馈类型 + SerializationType = SerializationType.FastBinary,//序列化类型 + Timeout = 5000,//调用超时设置 + Metadata = new Metadata() { { "a", "a" } } + }; + + var metadata = await client.GetDmtpRpcActor().InvokeTAsync("CallContextMetadata", invokeOption); + } +} +#endregion + +#region DmtpRpc使用CancellationToken +internal class UseCancellationTokenExample +{ + public async Task UseCancellationToken() + { + var client = new TcpDmtpClient(); + + //设置调用配置 + var tokenSource = new CancellationTokenSource();//可取消令箭源,可用于取消Rpc的调用 + var invokeOption = new DmtpInvokeOption()//调用配置 + { + FeedbackType = FeedbackType.WaitInvoke,//调用反馈类型 + SerializationType = SerializationType.FastBinary,//序列化类型 + Timeout = 5000,//调用超时设置 + Token = tokenSource.Token//配置可取消令箭 + }; + + var sum = await client.GetDmtpRpcActor().InvokeTAsync("Add", invokeOption, 10, 20); + client.Logger.Info($"调用Add方法成功,结果:{sum}"); + } +} +#endregion + +#region DmtpRpc客户端互Call示例 +internal class ClientToClientCallExample +{ + public async Task CallBetweenClients() + { + var client1 = new TcpDmtpClient(); + var client2 = new TcpDmtpClient(); + + await client1.GetDmtpRpcActor().InvokeTAsync(client2.Id, "Notice", InvokeOption.WaitInvoke, "Hello"); + } +} +#endregion + +#region DmtpRpc客户端互Call使用目标RpcActor +internal class ClientToClientCallWithTargetExample +{ + public async Task CallWithTarget() + { + var client1 = new TcpDmtpClient(); + var client2 = new TcpDmtpClient(); + + var targetRpcClient = client1.CreateTargetDmtpRpcActor(client2.Id); + await targetRpcClient.InvokeTAsync("Notice", InvokeOption.WaitInvoke, "Hello"); + } +} +#endregion diff --git a/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/DmtpRpcDelayPerformanceConsoleApp.csproj b/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/DmtpRpcDelayPerformanceConsoleApp.csproj index 6e94fdf8e..9e67fd647 100644 --- a/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/DmtpRpcDelayPerformanceConsoleApp.csproj +++ b/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/DmtpRpcDelayPerformanceConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/Program.cs b/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/Program.cs index 51aebc81c..d3b91e777 100644 --- a/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/Program.cs +++ b/examples/Dmtp/DmtpRpcDelayPerformanceConsoleApp/Program.cs @@ -1,6 +1,17 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.ComponentModel; using System.Diagnostics; -using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.Dmtp; using TouchSocket.Dmtp.Rpc; @@ -11,13 +22,13 @@ namespace RpcDelayPerConsoleApp { internal class Program { - static async Task Main(string[] args) + private static async Task Main(string[] args) { var service = await GetService(); var client = await GetClient(); - List tasks = new List(); + var tasks = new List(); Console.WriteLine("按任意键开始"); Console.ReadKey(); @@ -41,7 +52,7 @@ namespace RpcDelayPerConsoleApp } - static async Task GetService() + private static async Task GetService() { var service = new TcpDmtpService(); var config = new TouchSocketConfig()//配置 @@ -57,9 +68,9 @@ namespace RpcDelayPerConsoleApp { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Rpc" + options.VerifyToken = "Rpc"; }); await service.SetupAsync(config); @@ -69,7 +80,7 @@ namespace RpcDelayPerConsoleApp return service; } - static async Task GetClient() + private static async Task GetClient() { var client = new TcpDmtpClient(); await client.SetupAsync(new TouchSocketConfig() @@ -78,9 +89,9 @@ namespace RpcDelayPerConsoleApp { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Rpc" + options.VerifyToken = "Rpc"; })); await client.ConnectAsync(); @@ -91,23 +102,23 @@ namespace RpcDelayPerConsoleApp public partial class MyRpcServer : SingletonRpcServer { - Timer m_timer; + private readonly Timer m_timer; public MyRpcServer() { - m_timer = new Timer((s) => + this.m_timer = new Timer((s) => { - Console.WriteLine(m_count); + Console.WriteLine(this.m_count); }, default, 1000, 1000); } - int m_count = 0; + private int m_count = 0; [Description("登录")]//服务描述,在生成代理时,会变成注释。 [DmtpRpc(InvokeKey = "Login")]//服务注册的函数键,此处为显式指定。默认不传参的时候,为该函数类全名+方法名的全小写。 public async Task Login(string account, string password) { await Task.Delay(1000 * 3); - Interlocked.Increment(ref m_count); + Interlocked.Increment(ref this.m_count); if (account == "123" && password == "abc") { return true; diff --git a/examples/Dmtp/DmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj b/examples/Dmtp/DmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj index 773848ccd..ed2a63ce7 100644 --- a/examples/Dmtp/DmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj +++ b/examples/Dmtp/DmtpRpcPerformanceConsoleApp/DmtpRpcPerformanceConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -8,16 +8,16 @@ - - - + + + - + diff --git a/examples/Dmtp/FileTransferConsoleApp/Program.cs b/examples/Dmtp/FileTransferConsoleApp/Program.cs index 4fcf2539d..be4af98fe 100644 --- a/examples/Dmtp/FileTransferConsoleApp/Program.cs +++ b/examples/Dmtp/FileTransferConsoleApp/Program.cs @@ -54,11 +54,103 @@ internal class Program consoleAction.Add("9", "测试客户端工厂向服务器请求文件", async () => await MultithreadingClientPullFileFromService()); consoleAction.Add("10", "测试客户端工厂向服务器推送文件", async () => await MultithreadingClientPushFileFromService()); + consoleAction.Add("11", "测试Token取消传输", async () => await TestCancelWithToken()); + consoleAction.Add("12", "测试CancellationFileOperator取消传输", async () => await TestCancelWithCancellationFileOperator()); + consoleAction.ShowAll(); await consoleAction.RunCommandLineAsync(); } + /// + /// 测试使用Token取消传输 + /// + private static async Task TestCancelWithToken() + { + var client = await GetTcpDmtpClient(); + ConsoleLogger.Default.Info("开始测试Token取消传输"); + + var filePath = "TestCancelWithToken.Test"; + var saveFilePath = "SaveTestCancelWithToken.Test"; + if (!File.Exists(filePath)) + { + using (var stream = File.OpenWrite(filePath)) + { + stream.SetLength(FileLength); + } + } + + #region 文件传输Token取消 + var tokenSource = new CancellationTokenSource(); + + _ = Task.Run(async () => + { + //此处模拟五秒后自动取消传输 + await Task.Delay(5000); + tokenSource.Cancel(); + }); + + var metadata = new Metadata(); + var fileOperator = new FileOperator + { + SavePath = saveFilePath, + ResourcePath = filePath, + Metadata = metadata, + TryCount = 10, + FileSectionSize = 1024 * 512, + Token = tokenSource.Token + }; + + fileOperator.MaxSpeed = MaxSpeed; + + var result = await client.GetDmtpFileTransferActor().PullFileAsync(fileOperator); + #endregion + + ConsoleLogger.Default.Info($"Token取消传输测试结束,结果:{result}"); + File.Delete(filePath); + File.Delete(saveFilePath); + } + + /// + /// 测试使用CancellationFileOperator取消传输 + /// + private static async Task TestCancelWithCancellationFileOperator() + { + var client = await GetTcpDmtpClient(); + ConsoleLogger.Default.Info("开始测试CancellationFileOperator取消传输"); + + var filePath = "TestCancelWithCancellationFileOperator.Test"; + var saveFilePath = "SaveTestCancelWithCancellationFileOperator.Test"; + if (!File.Exists(filePath)) + { + using (var stream = File.OpenWrite(filePath)) + { + stream.SetLength(FileLength); + } + } + + #region 文件传输CancellationFileOperator取消 + var fileOperator = new CancellationFileOperator + { + SavePath = saveFilePath, + ResourcePath = filePath, + TryCount = 10, + FileSectionSize = 1024 * 512 + }; + + fileOperator.MaxSpeed = MaxSpeed; + + //模拟五秒后自动取消传输,或者直接Cancel + fileOperator.CancelAfter(TimeSpan.FromSeconds(5)); + + var result = await client.GetDmtpFileTransferActor().PullFileAsync(fileOperator); + #endregion + + ConsoleLogger.Default.Info($"CancellationFileOperator取消传输测试结束,结果:{result}"); + File.Delete(filePath); + File.Delete(saveFilePath); + } + /// /// 多线程推送文件 /// @@ -81,6 +173,7 @@ internal class Program } /****此处的逻辑是在程序运行目录下创建一个空内容,但是有长度的文件,用于测试****/ + #region 文件传输多线程推送文件 var metadata = new Metadata();//传递到服务器的元数据 metadata.Add("1", "1"); metadata.Add("2", "2"); @@ -90,7 +183,6 @@ internal class Program SavePath = saveFilePath,//客户端本地保存路径 ResourcePath = filePath,//请求文件的资源路径 Metadata = metadata,//传递到服务器的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512,//分包大小,当网络较差时,应该适当减小该值 MultithreadingCount = 10//多线程数量 @@ -111,7 +203,8 @@ internal class Program _ = loopAction.RunAsync(); //此方法会等待,直到传输结束 - IResult result = await clientFactory.PushFileAsync(fileOperator); + var result = await clientFactory.PushFileAsync(fileOperator); + #endregion ConsoleLogger.Default.Info($"向服务器推送文件结束,{result}"); @@ -141,6 +234,7 @@ internal class Program } /****此处的逻辑是在程序运行目录下创建一个空内容,但是有长度的文件,用于测试****/ + #region 文件传输多线程请求文件 var metadata = new Metadata();//传递到服务器的元数据 metadata.Add("1", "1"); metadata.Add("2", "2"); @@ -150,7 +244,6 @@ internal class Program SavePath = saveFilePath,//客户端本地保存路径 ResourcePath = filePath,//请求文件的资源路径 Metadata = metadata,//传递到服务器的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512,//分包大小,当网络较差时,应该适当减小该值 MultithreadingCount = 10//多线程数量 @@ -171,7 +264,8 @@ internal class Program _ = loopAction.RunAsync(); //此方法会等待,直到传输结束 - IResult result = await clientFactory.PullFileAsync(fileOperator); + var result = await clientFactory.PullFileAsync(fileOperator); + #endregion ConsoleLogger.Default.Info($"从服务器下载文件结束,{result}"); @@ -197,16 +291,18 @@ internal class Program } } + #region 文件传输推送小文件 var metadata = new Metadata();//传递到服务器的元数据 metadata.Add("1", "1"); metadata.Add("2", "2"); //此方法会阻塞,直到传输结束,也可以使用PullSmallFileAsync - var result = await client.GetDmtpFileTransferActor().PushSmallFileAsync(saveFilePath, new FileInfo(filePath), metadata); + var result = await client.GetDmtpFileTransferActor().PushSmallFileAsync(saveFilePath, new FileInfo(filePath), metadata, CancellationToken.None); if (result.IsSuccess) { //成功 } + #endregion ConsoleLogger.Default.Info($"从服务器下载小文件结束,结果:{result}"); client.Logger.Info(result.ToString()); @@ -236,14 +332,16 @@ internal class Program } /****此处的逻辑是在程序运行目录下创建一个空内容,但是有长度的文件,用于测试****/ + #region 文件传输拉取小文件 var metadata = new Metadata();//传递到服务器的元数据 metadata.Add("1", "1"); metadata.Add("2", "2"); //此方法会阻塞,直到传输结束,也可以使用PullSmallFileAsync - var result = await client.GetDmtpFileTransferActor().PullSmallFileAsync(filePath, metadata); + var result = await client.GetDmtpFileTransferActor().PullSmallFileAsync(filePath, metadata, CancellationToken.None); var data = result.Value;//此处即是下载的小文件的实际数据 - result.Save(saveFilePath, overwrite: true);//将数据保存到指定路径。 + await result.SaveAsync(saveFilePath, overwrite: true);//将数据保存到指定路径。 + #endregion ConsoleLogger.Default.Info("从服务器下载小文件结束"); client.Logger.Info(result.ToString()); @@ -289,7 +387,6 @@ internal class Program SavePath = saveFilePath,//客户端本地保存路径 ResourcePath = filePath,//请求文件的资源路径 Metadata = metadata,//传递到服务器的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值 }; @@ -309,7 +406,7 @@ internal class Program _ = loopAction.RunAsync(); //此方法会阻塞,直到传输结束,也可以使用PullFileAsync - IResult result = await client1.GetDmtpFileTransferActor().PushFileAsync(client2.Id, fileOperator); + var result = await client1.GetDmtpFileTransferActor().PushFileAsync(client2.Id, fileOperator); ConsoleLogger.Default.Info("从其他客户端下载文件结束"); client1.Logger.Info(result.ToString()); @@ -350,7 +447,6 @@ internal class Program SavePath = saveFilePath,//客户端本地保存路径 ResourcePath = filePath,//请求文件的资源路径 Metadata = metadata,//传递到服务器的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值 }; @@ -370,7 +466,7 @@ internal class Program _ = loopAction.RunAsync(); //此方法会阻塞,直到传输结束,也可以使用PullFileAsync - IResult result = await client1.GetDmtpFileTransferActor().PullFileAsync(client2.Id, fileOperator); + var result = await client1.GetDmtpFileTransferActor().PullFileAsync(client2.Id, fileOperator); ConsoleLogger.Default.Info("从其他客户端下载文件结束"); client1.Logger.Info(result.ToString()); @@ -387,6 +483,7 @@ internal class Program /// 服务器要请求的客户端Id private static async Task ServicePushFileFromClient(TcpDmtpService service, string targetId) { + #region 文件传输服务器推送文件 if (!service.TryGetClient(targetId, out var socketClient)) { throw new Exception($"没有找到Id={targetId}的客户端"); @@ -415,7 +512,6 @@ internal class Program SavePath = saveFilePath,//客户端本地保存路径 ResourcePath = filePath,//服务器文件的资源路径 Metadata = metadata,//传递到客户端的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值 }; @@ -435,7 +531,8 @@ internal class Program _ = loopAction.RunAsync(); //此方法会阻塞,直到传输结束,也可以使用PushFileAsync - IResult result = await socketClient.GetDmtpFileTransferActor().PushFileAsync(fileOperator); + var result = await socketClient.GetDmtpFileTransferActor().PushFileAsync(fileOperator); + #endregion ConsoleLogger.Default.Info("服务器主动推送客户端文件结束"); socketClient.Logger.Info(result.ToString()); @@ -452,6 +549,7 @@ internal class Program /// 服务器要请求的客户端Id private static async Task ServicePullFileFromClient(TcpDmtpService service, string targetId) { + #region 文件传输服务器请求文件 if (!service.TryGetClient(targetId, out var socketClient)) { throw new Exception($"没有找到Id={targetId}的客户端"); @@ -480,7 +578,6 @@ internal class Program SavePath = saveFilePath,//服务器本地保存路径 ResourcePath = filePath,//请求客户端文件的资源路径 Metadata = metadata,//传递到客户端的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值 }; @@ -500,7 +597,8 @@ internal class Program _ = loopAction.RunAsync(); //此方法会阻塞,直到传输结束,也可以使用PullFileAsync - IResult result = await socketClient.GetDmtpFileTransferActor().PullFileAsync(fileOperator); + var result = await socketClient.GetDmtpFileTransferActor().PullFileAsync(fileOperator); + #endregion ConsoleLogger.Default.Info("从客户端下载文件结束"); socketClient.Logger.Info(result.ToString()); @@ -528,8 +626,9 @@ internal class Program stream.SetLength(FileLength); } } - /****此处的逻辑是在程序运行目录下创建一个空内容,但是有长度的文件,用于测试****/ + /****此处的逻辑是在程序运行目录下创建一个空内容,但是有长度的文件,用于测试****/ + #region 文件传输客户端请求文件 var metadata = new Metadata();//传递到服务器的元数据 metadata.Add("1", "1"); metadata.Add("2", "2"); @@ -539,7 +638,6 @@ internal class Program SavePath = saveFilePath,//客户端本地保存路径 ResourcePath = filePath,//请求文件的资源路径 Metadata = metadata,//传递到服务器的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值 }; @@ -559,8 +657,10 @@ internal class Program _ = loopAction.RunAsync(); //此方法会阻塞,直到传输结束,也可以使用PullFileAsync - IResult result = await client.GetDmtpFileTransferActor().PullFileAsync(fileOperator); + var result = await client.GetDmtpFileTransferActor().PullFileAsync(fileOperator); + #endregion + #region 文件传输断点续传持久化 ////关于断点续传 ////在执行完PullFile(fileOperator)或PushFile(fileOperator)时。只要返回的结果不是Success。 ////那么就意味着传输没有完成。 @@ -584,6 +684,7 @@ internal class Program // var resourceInfo = new FileResourceInfo(byteBlock); // //然后把resourceInfo赋值给新建的FileOperator的ResourceInfo属性。 //} + #endregion ConsoleLogger.Default.Info("从服务器下载文件结束"); client.Logger.Info(result.ToString()); @@ -613,6 +714,7 @@ internal class Program } /****此处的逻辑是在程序运行目录下创建一个空内容,但是有长度的文件,用于测试****/ + #region 文件传输客户端推送文件 var metadata = new Metadata();//传递到服务器的元数据 metadata.Add("1", "1"); metadata.Add("2", "2"); @@ -622,7 +724,6 @@ internal class Program SavePath = saveFilePath,//服务器本地保存路径 ResourcePath = filePath,//客户端本地即将上传文件的资源路径 Metadata = metadata,//传递到服务器的元数据 - Timeout = TimeSpan.FromSeconds(60),//传输超时时长 TryCount = 10,//当遇到失败时,尝试次数 FileSectionSize = 1024 * 512//分包大小,当网络较差时,应该适当减小该值 }; @@ -642,7 +743,8 @@ internal class Program _ = loopAction.RunAsync(); //此方法会阻塞,直到传输结束,也可以使用PushFileAsync - IResult result = await client.GetDmtpFileTransferActor().PushFileAsync(fileOperator); + var result = await client.GetDmtpFileTransferActor().PushFileAsync(fileOperator); + #endregion ConsoleLogger.Default.Info("上传文件到服务器结束"); client.Logger.Info(result.ToString()); @@ -656,9 +758,9 @@ internal class Program { var client = await new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "File" + options.VerifyToken = "File"; }) .ConfigureContainer(a => { @@ -669,10 +771,6 @@ internal class Program a.UseDmtpFileTransfer();//必须添加文件传输插件 a.Add(); - - a.UseDmtpHeartbeat()//使用Dmtp心跳 - .SetTick(TimeSpan.FromSeconds(3)) - .SetMaxFailCount(3); }) .BuildClientAsync(); @@ -684,25 +782,29 @@ internal class Program { var service = new TcpDmtpService(); + #region 文件传输配置插件 var config = new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.AddConsoleLogger(); - + #region 文件传输添加路由策略 a.AddDmtpRouteService();//添加路由策略 + #endregion }) .ConfigurePlugins(a => { - a.UseDmtpFileTransfer()//必须添加文件传输插件 - //.SetRootPath("C:\\新建文件夹")//设置RootPath - .SetMaxSmallFileLength(1024 * 1024);//设置小文件的最大限制长度 + a.UseDmtpFileTransfer(options => + { + options.MaxSmallFileLength = 1024 * 1024 * 2;//设置小文件的最大限制长度 + }); a.Add(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "File"//连接验证口令。 + options.VerifyToken = "File";//连接验证口令。 }); + #endregion await service.SetupAsync(config); await service.StartAsync(); @@ -720,6 +822,8 @@ internal class Program { ConsoleLogger.Default.Exception(ex); } + + #region 文件传输多线程配置 var clientFactory = new TcpDmtpClientFactory() { MinCount = 5, @@ -728,9 +832,9 @@ internal class Program { return new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "File" + options.VerifyToken = "File"; }) .ConfigurePlugins(a => { @@ -738,7 +842,9 @@ internal class Program }); } }; + #endregion + #region 文件传输多线程获取目标传输客户端Id clientFactory.SetFindTransferIds((targetId) => { //此处的操作不唯一,可能需要rpc实现。 @@ -747,10 +853,13 @@ internal class Program return new string[] { targetId };//此处为模拟结果。 }); + #endregion + return clientFactory; } } +#region 文件传输插件定义 internal class MyPlugin : PluginBase, IDmtpFileTransferringPlugin, IDmtpFileTransferredPlugin, IDmtpRoutingPlugin { private readonly ILog m_logger; @@ -811,6 +920,7 @@ internal class MyPlugin : PluginBase, IDmtpFileTransferringPlugin, IDmtpFileTran await e.InvokeNext(); } + #region 文件传输同意路由 public async Task OnDmtpRouting(IDmtpActorObject client, PackageRouterEventArgs e) { e.IsPermitOperation = true;//允许路由 @@ -818,4 +928,6 @@ internal class MyPlugin : PluginBase, IDmtpFileTransferringPlugin, IDmtpFileTran await e.InvokeNext(); } -} \ No newline at end of file + #endregion +} +#endregion \ No newline at end of file diff --git a/examples/Dmtp/GeneratorRpcProxyConsoleApp/GeneratorRpcProxyConsoleApp.csproj b/examples/Dmtp/GeneratorRpcProxyConsoleApp/GeneratorRpcProxyConsoleApp.csproj index 8328d5ea7..f769ddcae 100644 --- a/examples/Dmtp/GeneratorRpcProxyConsoleApp/GeneratorRpcProxyConsoleApp.csproj +++ b/examples/Dmtp/GeneratorRpcProxyConsoleApp/GeneratorRpcProxyConsoleApp.csproj @@ -8,12 +8,12 @@ - - - - - - + + + + + + diff --git a/examples/Dmtp/GeneratorRpcProxyConsoleApp/Program.cs b/examples/Dmtp/GeneratorRpcProxyConsoleApp/Program.cs index dff394a96..2e0f1e5ef 100644 --- a/examples/Dmtp/GeneratorRpcProxyConsoleApp/Program.cs +++ b/examples/Dmtp/GeneratorRpcProxyConsoleApp/Program.cs @@ -11,7 +11,6 @@ //------------------------------------------------------------------------------ using System.ComponentModel; -using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.Dmtp; using TouchSocket.Dmtp.Rpc; @@ -41,9 +40,9 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp"//设定连接口令,作用类似账号密码 + options.VerifyToken = "Dmtp";//设定连接口令,作用类似账号密码 }); await service.SetupAsync(config); @@ -59,9 +58,9 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); await client.ConnectAsync(); diff --git a/examples/Dmtp/NamedPipeDmtpConsoleApp/NamedPipeDmtpConsoleApp.csproj b/examples/Dmtp/NamedPipeDmtpConsoleApp/NamedPipeDmtpConsoleApp.csproj index eeadb366b..1b5465cb5 100644 --- a/examples/Dmtp/NamedPipeDmtpConsoleApp/NamedPipeDmtpConsoleApp.csproj +++ b/examples/Dmtp/NamedPipeDmtpConsoleApp/NamedPipeDmtpConsoleApp.csproj @@ -8,7 +8,7 @@ - + diff --git a/examples/Dmtp/NamedPipeDmtpConsoleApp/Program.cs b/examples/Dmtp/NamedPipeDmtpConsoleApp/Program.cs index 61402e723..79360da19 100644 --- a/examples/Dmtp/NamedPipeDmtpConsoleApp/Program.cs +++ b/examples/Dmtp/NamedPipeDmtpConsoleApp/Program.cs @@ -10,7 +10,6 @@ // 感谢您的下载和使用 //------------------------------------------------------------------------------ -using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.Dmtp; using TouchSocket.NamedPipe; @@ -45,9 +44,9 @@ internal class Program a.AddConsoleLogger(); }) .SetPipeName("TouchSocketPipe")//设置管道名称 - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); await client.ConnectAsync(); @@ -64,9 +63,9 @@ internal class Program { a.AddConsoleLogger(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp"//设定连接口令,作用类似账号密码 + options.VerifyToken = "Dmtp";//设定连接口令,作用类似账号密码 }); await service.SetupAsync(config); diff --git a/examples/Dmtp/RealityProxyDmtpRpcConsoleApp/Program.cs b/examples/Dmtp/RealityProxyDmtpRpcConsoleApp/Program.cs deleted file mode 100644 index 3ce1f1018..000000000 --- a/examples/Dmtp/RealityProxyDmtpRpcConsoleApp/Program.cs +++ /dev/null @@ -1,89 +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 TouchSocket.Core; -using TouchSocket.Dmtp; -using TouchSocket.Dmtp.Rpc; -using TouchSocket.Sockets; - -namespace RealityProxyDmtpRpcConsoleApp; - -/// -/// 调用前先启动DmtpRpcServerConsoleApp项目 -/// -internal class Program -{ - private static void Main(string[] args) - { - var myDmtpRpcRealityProxy = new MyDmtpRpcRealityProxy(); - - var myRpcServer = myDmtpRpcRealityProxy.GetTransparentProxy(); - - var result = myRpcServer.Add(10, 20); - Console.WriteLine(result); - Console.ReadKey(); - } -} - -/// -/// 新建一个类,按照需要,继承DmtpRpcRealityProxy,亦或者RpcRealityProxy基类。 -/// 然后实现抽象方法,主要是能获取到调用的IRpcClient派生接口。 -/// -internal class MyDmtpRpcRealityProxy : DmtpRpcRealityProxy -{ - private readonly TcpDmtpClient m_client; - - public MyDmtpRpcRealityProxy() - { - this.m_client = GetTcpDmtpClient(); - } - - private static TcpDmtpClient GetTcpDmtpClient() - { - var client = new TcpDmtpClient(); - client.SetupAsync(new TouchSocketConfig() - .ConfigureContainer(a => - { - a.AddConsoleLogger(); - }) - .ConfigurePlugins(a => - { - a.UseDmtpRpc(); - }) - .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() - { - VerifyToken = "Dmtp" - })); - client.ConnectAsync().GetFalseAwaitResult(); - client.Logger.Info($"连接成功,Id={client.Id}"); - return client; - } - - public override IDmtpRpcActor GetClient() - { - return this.m_client.GetDmtpRpcActor(); - } -} - -internal interface IMyRpcServer -{ - /// - /// 将两个数相加 - /// - /// - /// - /// - [DmtpRpc(MethodInvoke = true)]//使用函数名直接调用 - int Add(int a, int b); -} \ No newline at end of file diff --git a/examples/Dmtp/RealityProxyDmtpRpcConsoleApp/RealityProxyDmtpRpcConsoleApp.csproj b/examples/Dmtp/RealityProxyDmtpRpcConsoleApp/RealityProxyDmtpRpcConsoleApp.csproj deleted file mode 100644 index 1c0f326a4..000000000 --- a/examples/Dmtp/RealityProxyDmtpRpcConsoleApp/RealityProxyDmtpRpcConsoleApp.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - Exe - net461 - - - - - - - diff --git a/examples/Dmtp/RecommendRpcConsoleApp/Program.cs b/examples/Dmtp/RecommendRpcConsoleApp/Program.cs index 810f165a9..d677583ab 100644 --- a/examples/Dmtp/RecommendRpcConsoleApp/Program.cs +++ b/examples/Dmtp/RecommendRpcConsoleApp/Program.cs @@ -43,9 +43,9 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; });//设定连接口令,作用类似账号密码 await service.SetupAsync(config); @@ -60,14 +60,14 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); await client.ConnectAsync(); //Login即为在RpcClassLibrary中自动生成的项目 - var response =await client.GetDmtpRpcActor().LoginAsync(new RpcClassLibrary.Models.LoginRequest() { Account = "Account", Password = "Account" }); + var response = await client.GetDmtpRpcActor().LoginAsync(new RpcClassLibrary.Models.LoginRequest() { Account = "Account", Password = "Account" }); Console.WriteLine(response.Result); Console.ReadKey(); } diff --git a/examples/Dmtp/RecommendRpcConsoleApp/RecommendRpcConsoleApp.csproj b/examples/Dmtp/RecommendRpcConsoleApp/RecommendRpcConsoleApp.csproj index fc6b617b5..c7cefb7b3 100644 --- a/examples/Dmtp/RecommendRpcConsoleApp/RecommendRpcConsoleApp.csproj +++ b/examples/Dmtp/RecommendRpcConsoleApp/RecommendRpcConsoleApp.csproj @@ -8,7 +8,7 @@ - + diff --git a/examples/Dmtp/RemoteAccessApp/Form1.cs b/examples/Dmtp/RemoteAccessApp/Form1.cs index b3ed5dd3d..c68a8d0ab 100644 --- a/examples/Dmtp/RemoteAccessApp/Form1.cs +++ b/examples/Dmtp/RemoteAccessApp/Form1.cs @@ -28,11 +28,12 @@ public partial class Form1 : Form private void Form1_Load(object? sender, EventArgs e) { + #region 远程文件系统配置客户端 this.m_client.SetupAsync(new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }) .ConfigureContainer(a => { @@ -45,9 +46,10 @@ public partial class Form1 : Form { a.UseDmtpRemoteAccess(); })); + #endregion this.m_client.ConnectAsync(); - this.m_client.Logger.Info("�ɹ�����"); + this.m_client.Logger.Info("成功连接"); } private readonly TcpDmtpClient m_client = new TcpDmtpClient(); @@ -58,7 +60,7 @@ public partial class Form1 : Form { if (this.textBox1.Text.IsNullOrEmpty()) { - this.m_client.Logger.Warning("·������Ϊ�ա�"); + this.m_client.Logger.Warning("路径不能为空。"); return; } var result = await this.m_client.GetRemoteAccessActor().CreateDirectoryAsync(this.textBox1.Text, millisecondsTimeout: 30 * 1000); @@ -76,7 +78,7 @@ public partial class Form1 : Form { if (this.textBox1.Text.IsNullOrEmpty()) { - this.m_client.Logger.Warning("·������Ϊ�ա�"); + this.m_client.Logger.Warning("路径不能为空。"); return; } var result = await this.m_client.GetRemoteAccessActor().DeleteDirectoryAsync(this.textBox1.Text, millisecondsTimeout: 30 * 1000); @@ -94,11 +96,13 @@ public partial class Form1 : Form { if (this.textBox1.Text.IsNullOrEmpty()) { - this.m_client.Logger.Warning("·������Ϊ�ա�"); + this.m_client.Logger.Warning("路径不能为空。"); return; } + #region 远程文件系统获取目录信息 var result = await this.m_client.GetRemoteAccessActor().GetDirectoryInfoAsync(this.textBox1.Text, millisecondsTimeout: 30 * 1000); - this.m_client.Logger.Info($"�����{result.ResultCode}����Ϣ��{result.Message}��������Ϣ����Ի�á�"); + #endregion + this.m_client.Logger.Info($"结果:{result.ResultCode},信息:{result.Message},详细信息请在对话框获取。"); } catch (Exception ex) { @@ -112,7 +116,7 @@ public partial class Form1 : Form { if (this.textBox1.Text.IsNullOrEmpty()) { - this.m_client.Logger.Warning("·������Ϊ�ա�"); + this.m_client.Logger.Warning("路径不能为空。"); return; } var result = await this.m_client.GetRemoteAccessActor().DeleteFileAsync(this.textBox1.Text, millisecondsTimeout: 30 * 1000); @@ -130,11 +134,11 @@ public partial class Form1 : Form { if (this.textBox1.Text.IsNullOrEmpty()) { - this.m_client.Logger.Warning("·������Ϊ�ա�"); + this.m_client.Logger.Warning("路径不能为空。"); return; } var result = await this.m_client.GetRemoteAccessActor().GetFileInfoAsync(this.textBox1.Text, millisecondsTimeout: 30 * 1000); - this.m_client.Logger.Info($"�����{result.ResultCode}����Ϣ��{result.Message}������Ϣ����Ի�á�"); + this.m_client.Logger.Info($"结果:{result.ResultCode},信息:{result.Message},详细信息请在对话框获取。"); } catch (Exception ex) { diff --git a/examples/Dmtp/RemoteAccessApp/Program.cs b/examples/Dmtp/RemoteAccessApp/Program.cs index 548d8e44a..f7df6145f 100644 --- a/examples/Dmtp/RemoteAccessApp/Program.cs +++ b/examples/Dmtp/RemoteAccessApp/Program.cs @@ -43,36 +43,39 @@ internal static class Program private static async Task GetTcpDmtpService() { - var service = await new TouchSocketConfig()//���� + var service = await new TouchSocketConfig()//配置 .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigureContainer(a => { a.AddConsoleLogger(); }) + #region 远程文件系统配置插件 .ConfigurePlugins(a => { - a.UseDmtpRemoteAccess();//��������Զ�̷��ʲ�� + a.UseDmtpRemoteAccess();//使用Dmtp远程访问插件 a.Add(); }) - .SetDmtpOption(new DmtpOption() + #endregion + .SetDmtpOption(options=> { - VerifyToken = "Dmtp"//������֤��� + options.VerifyToken = "Dmtp";//连接验证口令 }) - .BuildServiceAsync();//�˴�build�൱��new TcpDmtpService��Ȼ��SetupAsync��Ȼ��StartAsync�� - service.Logger.Info("�������ɹ�����"); + .BuildServiceAsync();//此处build相当于new TcpDmtpService,然后SetupAsync,然后StartAsync。 + service.Logger.Info("服务器成功启动"); return service; } + #region 远程文件系统响应端插件 public class MyRemoteAccessPlugin : PluginBase, IDmtpRemoteAccessingPlugin { public async Task OnRemoteAccessing(IDmtpActorObject client, RemoteAccessingEventArgs e) { - //Console.WriteLine($"�пͻ�����������Զ�̲���"); - //Console.WriteLine($"���ͣ�{e.AccessType}��ģʽ��{e.AccessMode}"); - //Console.WriteLine($"����·����{e.Path}"); - //Console.WriteLine($"Ŀ��·����{e.TargetPath}"); + //Console.WriteLine($"有客户端正在请求远程操作"); + //Console.WriteLine($"类型:{e.AccessType},模式:{e.AccessMode}"); + //Console.WriteLine($"源路径:{e.Path}"); + //Console.WriteLine($"目标路径:{e.TargetPath}"); - //Console.WriteLine("������y/n�����Ƿ����������?"); + //Console.WriteLine("请输入y/n,表示是否允许该操作?"); //var input = Console.ReadLine(); //if (input == "y") @@ -81,8 +84,9 @@ internal static class Program // return; //} - //�����ǰ�����������ת����һ����� + //如果当前插件无法处理,请转至下一个插件 await e.InvokeNext(); } } + #endregion } \ No newline at end of file diff --git a/examples/Dmtp/RemoteAccessApp/RemoteAccessApp.csproj b/examples/Dmtp/RemoteAccessApp/RemoteAccessApp.csproj index e6c039ba4..7b9f9271a 100644 --- a/examples/Dmtp/RemoteAccessApp/RemoteAccessApp.csproj +++ b/examples/Dmtp/RemoteAccessApp/RemoteAccessApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -10,11 +10,11 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/examples/Dmtp/RemoteStreamConsoleApp/Program.cs b/examples/Dmtp/RemoteStreamConsoleApp/Program.cs index 388b5ba03..f11e793cd 100644 --- a/examples/Dmtp/RemoteStreamConsoleApp/Program.cs +++ b/examples/Dmtp/RemoteStreamConsoleApp/Program.cs @@ -34,16 +34,22 @@ internal class Program var client = await GetTcpDmtpClient(); + #region 远程流映射请求端 //元数据可以传递一些字符串数据 var metadata = new Metadata(); metadata.Add("tag", "tag1"); - var remoteStream = await client.GetDmtpRemoteStreamActor().LoadRemoteStreamAsync(metadata); + var remoteStream = await client.GetDmtpRemoteStreamActor().LoadRemoteStreamAsync(metadata, CancellationToken.None); + #endregion client.Logger.Info("已经成功载入流,请输入任意字符"); //可以持续写入流,但在此处只写入了一次 - await remoteStream.WriteAsync(Encoding.UTF8.GetBytes(Console.ReadLine())); + var input = Console.ReadLine(); + if (input != null) + { + await remoteStream.WriteAsync(Encoding.UTF8.GetBytes(input)); + } //可以使用下列代码完成持续读流 //while (true) @@ -71,9 +77,9 @@ internal class Program var client = new TcpDmtpClient(); await client.SetupAsync(new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }) .ConfigureContainer(a => { @@ -82,10 +88,6 @@ internal class Program .ConfigurePlugins(a => { a.UseDmtpRemoteStream(); - - a.UseDmtpHeartbeat()//使用Dmtp心跳 - .SetTick(TimeSpan.FromSeconds(3)) - .SetMaxFailCount(3); })); await client.ConnectAsync(); return client; @@ -101,19 +103,40 @@ internal class Program }) .ConfigurePlugins(a => { + #region 远程流映射启用插件 a.UseDmtpRemoteStream();//必须添加远程流访问插件 + #endregion a.Add(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp"//连接验证口令。 + options.VerifyToken = "Dmtp";//连接验证口令。 }) .BuildServiceAsync();//此处build相当于new TcpDmtpService,然后SetupAsync,然后StartAsync。 service.Logger.Info("服务器成功启动"); return service; } + + #region 远程流映射读写操作 + private static async Task RemoteStreamReadWrite(TcpDmtpClient client) + { + var metadata = new Metadata(); + metadata.Add("tag", "tag1"); + var remoteStream = await client.GetDmtpRemoteStreamActor().LoadRemoteStreamAsync(metadata, CancellationToken.None); + + byte[] data = new byte[] { 0, 1, 2, 3, 4 }; + await remoteStream.WriteAsync(data); + + remoteStream.Position = 0; + byte[] buffer = new byte[5]; + await remoteStream.ReadAsync(buffer); + + remoteStream.Dispose(); + } + #endregion } +#region 远程流映射响应端插件 internal class MyRemoteStreamPlugin : PluginBase, IDmtpRemoteStreamPlugin { private readonly ILog m_logger; @@ -133,7 +156,7 @@ internal class MyRemoteStreamPlugin : PluginBase, IDmtpRemoteStreamPlugin //此处加载的是一个内存流,实际上只要是Stream,都可以,例如:FileStream using (var stream = new MemoryStream()) { - await e.WaitingLoadStreamAsync(stream, TimeSpan.FromSeconds(60)); + await e.WaitingLoadStreamAsync(stream, CancellationToken.None); this.m_logger.Info($"载入的流已被释放,流中信息:{Encoding.UTF8.GetString(stream.ToArray())}"); } @@ -144,4 +167,5 @@ internal class MyRemoteStreamPlugin : PluginBase, IDmtpRemoteStreamPlugin //如果不满足,调用下一个插件 await e.InvokeNext(); } -} \ No newline at end of file +} +#endregion \ No newline at end of file diff --git a/examples/Dmtp/RemoteStreamConsoleApp/RemoteStreamConsoleApp.csproj b/examples/Dmtp/RemoteStreamConsoleApp/RemoteStreamConsoleApp.csproj index eeadb366b..1b5465cb5 100644 --- a/examples/Dmtp/RemoteStreamConsoleApp/RemoteStreamConsoleApp.csproj +++ b/examples/Dmtp/RemoteStreamConsoleApp/RemoteStreamConsoleApp.csproj @@ -8,7 +8,7 @@ - + diff --git a/examples/Dmtp/ReverseRpcConsoleApp/Program.cs b/examples/Dmtp/ReverseRpcConsoleApp/Program.cs index 7ca7e00a8..a7f69cddd 100644 --- a/examples/Dmtp/ReverseRpcConsoleApp/Program.cs +++ b/examples/Dmtp/ReverseRpcConsoleApp/Program.cs @@ -52,9 +52,9 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }); service.SetupAsync(config); @@ -81,9 +81,9 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); client.ConnectAsync(); diff --git a/examples/Dmtp/ReverseRpcConsoleApp/ReverseRpcConsoleApp.csproj b/examples/Dmtp/ReverseRpcConsoleApp/ReverseRpcConsoleApp.csproj index e61b4ab6f..c5ca9ba39 100644 --- a/examples/Dmtp/ReverseRpcConsoleApp/ReverseRpcConsoleApp.csproj +++ b/examples/Dmtp/ReverseRpcConsoleApp/ReverseRpcConsoleApp.csproj @@ -6,11 +6,11 @@ - - - - - - + + + + + + diff --git a/examples/Dmtp/RouterPackageConsoleApp/Program.cs b/examples/Dmtp/RouterPackageConsoleApp/Program.cs index 7270cb345..0a2fd8a0b 100644 --- a/examples/Dmtp/RouterPackageConsoleApp/Program.cs +++ b/examples/Dmtp/RouterPackageConsoleApp/Program.cs @@ -30,7 +30,7 @@ internal class Program { ConsoleLogger.Default.Info(ex.Message); } - var service =await GetTcpDmtpService(); + var service = await GetTcpDmtpService(); var consoleAction = new ConsoleAction(); consoleAction.OnException += ConsoleAction_OnException; @@ -56,7 +56,7 @@ internal class Program }; //发起请求,然后等待一个自定义的响应包。 - var response = await client.GetDmtpRouterPackageActor().RequestAsync(requestPackage); + var response = await client.GetDmtpRouterPackageActor().RequestAsync(requestPackage, CancellationToken.None); client.Logger.Info($"自定义响应成功,{response}"); } @@ -65,6 +65,7 @@ internal class Program private static async Task RequestMyResponsePackage() { using var client = await GetTcpDmtpClient(); + #region 路由包请求端 using (var byteBlock = new ByteBlock(1024 * 512)) { //此处模拟一个大数据块,实际情况中请使用write写入实际数据。 @@ -76,10 +77,11 @@ internal class Program }; //发起请求,然后等待一个自定义的响应包。 - var response = await client.GetDmtpRouterPackageActor().RequestAsync(requestPackage); + var response = await client.GetDmtpRouterPackageActor().RequestAsync(requestPackage, CancellationToken.None); client.Logger.Info($"自定义响应成功,{response.Message}"); } + #endregion } private static void ConsoleAction_OnException(Exception obj) @@ -89,11 +91,12 @@ internal class Program private static async Task GetTcpDmtpClient() { + #region 路由包添加插件 var client = await new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }) .ConfigureContainer(a => { @@ -104,6 +107,7 @@ internal class Program a.UseDmtpRouterPackage();//添加路由包功能插件 }) .BuildClientAsync(); + #endregion client.Logger.Info("连接成功"); return client; @@ -128,9 +132,9 @@ internal class Program a.Add(); a.Add(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options=> { - VerifyToken = "Dmtp"//连接验证口令。 + options.VerifyToken = "Dmtp";//连接验证口令。 }); await service.SetupAsync(config); @@ -142,10 +146,11 @@ internal class Program /// /// 定义请求包 /// + #region 路由包定义请求包 private class MyRequestPackage : DmtpRouterPackage { /// - /// 包尺寸大小。此值并非需要精准数值,只需要估计数据即可。其作用为申请内存池。所以数据应当大小合适。 + /// 包尺寸大小。此值并非需要精准数值,只需要估计数据即可。其作用为申请内存池。所以数据应当大小合适。 /// public override int PackageSize => 1024 * 1024; @@ -157,19 +162,22 @@ internal class Program public override void PackageBody(ref TByteBlock byteBlock) { base.PackageBody(ref byteBlock); - byteBlock.WriteByteBlock(this.ByteBlock); + WriterExtension.WriteByteBlock(ref byteBlock, this.ByteBlock); } public override void UnpackageBody(ref TByteBlock byteBlock) { base.UnpackageBody(ref byteBlock); - this.ByteBlock = byteBlock.ReadByteBlock(); + + this.ByteBlock = ReaderExtension.ReadByteBlock(ref byteBlock); } } + #endregion /// /// 定义响应包 /// + #region 路由包定义响应包 private class MyResponsePackage : DmtpRouterPackage { /// @@ -177,7 +185,9 @@ internal class Program /// public override int PackageSize => 1024; } + #endregion + #region 路由包响应端插件 private class MyPlugin1 : PluginBase, IDmtpRouterPackagePlugin { private readonly ILog m_logger; @@ -209,6 +219,7 @@ internal class Program await e.InvokeNext(); } } + #endregion private class MyPlugin2 : PluginBase, IDmtpRouterPackagePlugin { diff --git a/examples/Dmtp/RouterPackageConsoleApp/RouterPackageConsoleApp.csproj b/examples/Dmtp/RouterPackageConsoleApp/RouterPackageConsoleApp.csproj index 117ad74df..276ed914e 100644 --- a/examples/Dmtp/RouterPackageConsoleApp/RouterPackageConsoleApp.csproj +++ b/examples/Dmtp/RouterPackageConsoleApp/RouterPackageConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,6 @@ - + diff --git a/examples/Dmtp/RpcClassLibrary/RpcClassLibrary.csproj b/examples/Dmtp/RpcClassLibrary/RpcClassLibrary.csproj index 1bc660f1b..09a2d53d5 100644 --- a/examples/Dmtp/RpcClassLibrary/RpcClassLibrary.csproj +++ b/examples/Dmtp/RpcClassLibrary/RpcClassLibrary.csproj @@ -5,7 +5,7 @@ - + diff --git a/examples/Dmtp/RpcFactoryConsoleApp/Program.cs b/examples/Dmtp/RpcFactoryConsoleApp/Program.cs index 8cc4c18b0..0891d2ce1 100644 --- a/examples/Dmtp/RpcFactoryConsoleApp/Program.cs +++ b/examples/Dmtp/RpcFactoryConsoleApp/Program.cs @@ -23,7 +23,8 @@ internal class Program { var clientFactory = CreateTcpClientFactory(); - using (var clientFactoryResult = await clientFactory.GetClient()) + var cts = new CancellationTokenSource(1000 * 10); + using (var clientFactoryResult = await clientFactory.GetClient(cts.Token)) { //这里可以让得到的通讯单体进行业务交流 var client = clientFactoryResult.Client; diff --git a/examples/Dmtp/RpcFactoryConsoleApp/RpcFactoryConsoleApp.csproj b/examples/Dmtp/RpcFactoryConsoleApp/RpcFactoryConsoleApp.csproj index 8328d5ea7..f769ddcae 100644 --- a/examples/Dmtp/RpcFactoryConsoleApp/RpcFactoryConsoleApp.csproj +++ b/examples/Dmtp/RpcFactoryConsoleApp/RpcFactoryConsoleApp.csproj @@ -8,12 +8,12 @@ - - - - - - + + + + + + diff --git a/examples/Dmtp/RpcImplementationClassLibrary/RpcImplementationClassLibrary.csproj b/examples/Dmtp/RpcImplementationClassLibrary/RpcImplementationClassLibrary.csproj index 7bb4ca9db..f7f7d462c 100644 --- a/examples/Dmtp/RpcImplementationClassLibrary/RpcImplementationClassLibrary.csproj +++ b/examples/Dmtp/RpcImplementationClassLibrary/RpcImplementationClassLibrary.csproj @@ -5,7 +5,7 @@ - + diff --git a/examples/Dmtp/RpcStreamConsoleApp/Program.cs b/examples/Dmtp/RpcStreamConsoleApp/Program.cs index 5bb3da851..d2f764ceb 100644 --- a/examples/Dmtp/RpcStreamConsoleApp/Program.cs +++ b/examples/Dmtp/RpcStreamConsoleApp/Program.cs @@ -40,9 +40,9 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); client.ConnectAsync(); return client; @@ -65,9 +65,9 @@ internal class Program { a.UseDmtpRpc(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Rpc" + options.VerifyToken = "Rpc"; }); service.SetupAsync(config); @@ -84,20 +84,23 @@ internal class Program var client = CreateClient(); //测试客户端持续请求数据 var size = 0; - var channel =await client.CreateChannelAsync();//创建通道 - var task = Task.Run(() =>//这里必须用异步 + var channel = await client.CreateChannelAsync();//创建通道 + var task = Task.Run(async () =>//这里必须用异步 { using (channel) { - foreach (var byteBlock in channel) + while (channel.CanRead) { - size += byteBlock.Length; + using var cts = new CancellationTokenSource(10 * 1000); + var memory = await channel.ReadAsync(cts.Token); + //这里处理数据 + size += memory.Length; } } }); //此处是直接调用,真正使用时,可以生成代理调用。 - var result =await client.GetDmtpRpcActor().InvokeTAsync("RpcPullChannel", InvokeOption.WaitInvoke, channel.Id); + var result = await client.GetDmtpRpcActor().InvokeTAsync("RpcPullChannel", InvokeOption.WaitInvoke, channel.Id); await task;//等待异步接收完成 Console.WriteLine($"客户端接收结束,状态:{channel.Status},size={size}"); //测试客户端持续请求数据 @@ -111,7 +114,7 @@ internal class Program var client = CreateClient(); var size = 0; var package = 1024 * 1024; - var channel =await client.CreateChannelAsync();//创建通道 + var channel = await client.CreateChannelAsync();//创建通道 var task = Task.Run(async () =>//这里必须用异步 { for (var i = 0; i < Program.Count; i++) @@ -123,7 +126,7 @@ internal class Program }); //此处是直接调用,真正使用时,可以生成代理调用。 - var result =await client.GetDmtpRpcActor().InvokeTAsync("RpcPushChannel", InvokeOption.WaitInvoke, channel.Id); + var result = await client.GetDmtpRpcActor().InvokeTAsync("RpcPushChannel", InvokeOption.WaitInvoke, channel.Id); await task;//等待异步接收完成 channel.Dispose(); @@ -165,7 +168,7 @@ internal class Program /// [Description("测试ServiceToClient创建通道,从而实现流数据的传输")] [DmtpRpc(MethodInvoke = true)]//此处设置直接使用方法名调用 - public int RpcPushChannel(ICallContext callContext, int channelID) + public async Task RpcPushChannel(ICallContext callContext, int channelID) { var size = 0; @@ -173,9 +176,12 @@ internal class Program { if (socketClient.TrySubscribeChannel(channelID, out var channel)) { - foreach (var byteBlock in channel) + while (channel.CanRead) { - size += byteBlock.Length; + using var cts = new CancellationTokenSource(10 * 1000); + var memory = await channel.ReadAsync(cts.Token); + //这里处理数据 + size += memory.Length; } Console.WriteLine($"服务器接收结束,状态:{channel.Status},长度:{size}"); } diff --git a/examples/Dmtp/RpcStreamConsoleApp/RpcStreamConsoleApp.csproj b/examples/Dmtp/RpcStreamConsoleApp/RpcStreamConsoleApp.csproj index f18b62f22..6608859ea 100644 --- a/examples/Dmtp/RpcStreamConsoleApp/RpcStreamConsoleApp.csproj +++ b/examples/Dmtp/RpcStreamConsoleApp/RpcStreamConsoleApp.csproj @@ -8,12 +8,12 @@ - - - - - - + + + + + + diff --git a/examples/Dmtp/SerializationSelectorClassLibrary/MemoryPackSerializationSelector.cs b/examples/Dmtp/SerializationSelectorClassLibrary/MemoryPackSerializationSelector.cs index b48aa6b40..d2022286c 100644 --- a/examples/Dmtp/SerializationSelectorClassLibrary/MemoryPackSerializationSelector.cs +++ b/examples/Dmtp/SerializationSelectorClassLibrary/MemoryPackSerializationSelector.cs @@ -11,190 +11,60 @@ //------------------------------------------------------------------------------ using MemoryPack; -using Newtonsoft.Json; using System; -using System.IO; using TouchSocket.Core; using TouchSocket.Dmtp.Rpc; -using TouchSocket.Rpc; namespace SerializationSelectorClassLibrary; public class MemoryPackSerializationSelector : ISerializationSelector { - public object DeserializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, Type parameterType) where TByteBlock : IByteBlock + public object DeserializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, Type parameterType) where TByteBlock : IBytesReader { - var len = byteBlock.ReadInt32(); - var span = byteBlock.ReadToSpan(len); + var len = ReaderExtension.ReadValue(ref byteBlock); + var span = ReaderExtension.ReadToSpan(ref byteBlock, len); return MemoryPackSerializer.Deserialize(parameterType, span); } - public void SerializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, in object parameter) where TByteBlock : IByteBlock + public void SerializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, in object parameter) where TByteBlock : IBytesWriter { - var pos = byteBlock.Position; - byteBlock.Seek(4, SeekOrigin.Current); + var writerAnchor = new WriterAnchor(ref byteBlock, 4); + var memoryPackWriter = new MemoryPackWriter(ref byteBlock, null); MemoryPackSerializer.Serialize(parameter.GetType(), ref memoryPackWriter, parameter); - var newPos = byteBlock.Position; - byteBlock.Position = pos; - byteBlock.WriteInt32(memoryPackWriter.WrittenCount); - byteBlock.Position = newPos; + var span = writerAnchor.Rewind(ref byteBlock, out var len); + span.WriteValue(memoryPackWriter.WrittenCount); } } -internal sealed class DefaultSerializationSelector : ISerializationSelector +internal sealed class MyDefaultSerializationSelector : DefaultSerializationSelector { - /// - /// 根据指定的序列化类型反序列化字节块中的数据。 - /// - /// 包含序列化数据的字节块。 - /// 指定的序列化类型。 - /// 预期反序列化出的对象类型。 - /// 反序列化后的对象。 - /// 抛出当未识别序列化类型时。 - public object DeserializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, Type parameterType) where TByteBlock : IByteBlock + public override object DeserializeParameter(ref TReader reader, SerializationType serializationType, Type parameterType) { - // 根据序列化类型选择不同的反序列化方式 - switch (serializationType) + if ((byte)serializationType == 4) { - case SerializationType.FastBinary: - // 使用FastBinary格式进行反序列化 - return FastBinaryFormatter.Deserialize(ref byteBlock, parameterType); - case SerializationType.SystemBinary: - // 检查字节块是否为null - if (byteBlock.ReadIsNull()) - { - // 如果为null,则返回该类型的默认值 - return parameterType.GetDefault(); - } - - // 使用SystemBinary格式进行反序列化 - using (var block = byteBlock.ReadByteBlock()) - { - // 将字节块转换为流并进行反序列化 - return SerializeConvert.BinaryDeserialize(block.AsStream()); - } - case SerializationType.Json: - // 检查字节块是否为null - if (byteBlock.ReadIsNull()) - { - // 如果为null,则返回该类型的默认值 - return parameterType.GetDefault(); - } - - // 使用Json格式进行反序列化 - return JsonConvert.DeserializeObject(byteBlock.ReadString(), parameterType); - - case SerializationType.Xml: - // 检查字节块是否为null - if (byteBlock.ReadIsNull()) - { - // 如果为null,则返回该类型的默认值 - return parameterType.GetDefault(); - } - // 使用Xml格式进行反序列化 - return SerializeConvert.XmlDeserializeFromBytes(byteBlock.ReadBytesPackage(), parameterType); - case (SerializationType)4: - { - var len = byteBlock.ReadInt32(); - var span = byteBlock.ReadToSpan(len); - return MemoryPackSerializer.Deserialize(parameterType, span); - } - default: - // 如果序列化类型未识别,则抛出异常 - throw new RpcException("未指定的反序列化方式"); + var len = ReaderExtension.ReadValue(ref reader); + var span = ReaderExtension.ReadToSpan(ref reader, len); + return MemoryPackSerializer.Deserialize(parameterType, span); } + return base.DeserializeParameter(ref reader, serializationType, parameterType); } - /// - /// 序列化参数 - /// - /// 字节块引用,用于存储序列化后的数据 - /// 序列化类型,决定了使用哪种方式序列化 - /// 待序列化的参数对象 - /// 字节块类型,必须实现IByteBlock接口 - public void SerializeParameter(ref TByteBlock byteBlock, SerializationType serializationType, in object parameter) where TByteBlock : IByteBlock + public override void SerializeParameter(ref TWriter writer, SerializationType serializationType, in object parameter) { - // 根据序列化类型选择不同的序列化方法 - switch (serializationType) + if ((byte)serializationType == 4) { - case SerializationType.FastBinary: - { - // 使用FastBinaryFormatter进行序列化 - FastBinaryFormatter.Serialize(ref byteBlock, parameter); - break; - } - case SerializationType.SystemBinary: - { - // 参数为null时,写入空值标记 - if (parameter is null) - { - byteBlock.WriteNull(); - } - else - { - // 参数不为null时,标记并序列化参数 - byteBlock.WriteNotNull(); - using (var block = new ByteBlock(1024 * 64)) - { - // 使用System.Runtime.Serialization.BinaryFormatter进行序列化 - SerializeConvert.BinarySerialize(block.AsStream(), parameter); - // 将序列化后的字节块写入byteBlock - byteBlock.WriteByteBlock(block); - } - } - break; - } - case SerializationType.Json: - { - // 参数为null时,写入空值标记 - if (parameter is null) - { - byteBlock.WriteNull(); - } - else - { - // 参数不为null时,标记并转换为JSON字符串 - byteBlock.WriteNotNull(); - byteBlock.WriteString(JsonConvert.SerializeObject(parameter)); - } - break; - } - case SerializationType.Xml: - { - // 参数为null时,写入空值标记 - if (parameter is null) - { - byteBlock.WriteNull(); - } - else - { - // 参数不为null时,标记并转换为Xml字节 - byteBlock.WriteNotNull(); - byteBlock.WriteBytesPackage(SerializeConvert.XmlSerializeToBytes(parameter)); - } - break; - } - case (SerializationType)4: - { - var pos = byteBlock.Position; - byteBlock.Seek(4, SeekOrigin.Current); - var memoryPackWriter = new MemoryPackWriter(ref byteBlock, null); + var writerAnchor = new WriterAnchor(ref writer, 4); - MemoryPackSerializer.Serialize(parameter.GetType(), ref memoryPackWriter, parameter); + var memoryPackWriter = new MemoryPackWriter(ref writer, null); - var newPos = byteBlock.Position; - byteBlock.Position = pos; - byteBlock.WriteInt32(memoryPackWriter.WrittenCount); - byteBlock.Position = newPos; + MemoryPackSerializer.Serialize(parameter.GetType(), ref memoryPackWriter, parameter); - break; - } - default: - // 抛出异常,提示未指定的序列化方式 - throw new RpcException("未指定的序列化方式"); + var span = writerAnchor.Rewind(ref writer, out var len); + span.WriteValue(memoryPackWriter.WrittenCount); } + base.SerializeParameter(ref writer, serializationType, parameter); } } \ No newline at end of file diff --git a/examples/Dmtp/SerializationSelectorClassLibrary/SerializationSelectorClassLibrary.csproj b/examples/Dmtp/SerializationSelectorClassLibrary/SerializationSelectorClassLibrary.csproj index a43de4651..b3fab3ddf 100644 --- a/examples/Dmtp/SerializationSelectorClassLibrary/SerializationSelectorClassLibrary.csproj +++ b/examples/Dmtp/SerializationSelectorClassLibrary/SerializationSelectorClassLibrary.csproj @@ -5,13 +5,13 @@ - - - - - - - + + + + + + + diff --git a/examples/Dmtp/SerializationSelectorConsoleApp/Program.cs b/examples/Dmtp/SerializationSelectorConsoleApp/Program.cs index ff828a4b9..d6e4101a2 100644 --- a/examples/Dmtp/SerializationSelectorConsoleApp/Program.cs +++ b/examples/Dmtp/SerializationSelectorConsoleApp/Program.cs @@ -29,11 +29,10 @@ internal class Program var client = await CreateClient(); - InvokeOption invokeOption = new DmtpInvokeOption() + InvokeOption invokeOption = new DmtpInvokeOption(1000 * 10) { FeedbackType = FeedbackType.WaitInvoke, - SerializationType = (SerializationType)4, - Timeout = 1000 * 10 + SerializationType = (SerializationType)4 }; var msg = await client.GetDmtpRpcActor().LoginAsync(new LoginModel() { Account = "Account", Password = "Password" }, invokeOption); @@ -48,8 +47,10 @@ internal class Program .SetRemoteIPHost("127.0.0.1:7789") .ConfigurePlugins(a => { - a.UseDmtpRpc() - .SetSerializationSelector(new MemoryPackSerializationSelector()); + a.UseDmtpRpc(options => + { + options.SerializationSelector = new MemoryPackSerializationSelector(); + }); //a.UseDmtpRpc() // .SetSerializationSelector(new DefaultSerializationSelector() @@ -60,9 +61,9 @@ internal class Program // SerializationBinder = default, // }); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; })); await client.ConnectAsync(); return client; @@ -75,8 +76,10 @@ internal class Program .SetListenIPHosts(new IPHost[] { new IPHost(7789) }) .ConfigurePlugins(a => { - a.UseDmtpRpc() - .SetSerializationSelector(new MemoryPackSerializationSelector()); + a.UseDmtpRpc(options => + { + options.SerializationSelector = new MemoryPackSerializationSelector(); + }); }) .ConfigureContainer(a => { @@ -86,9 +89,9 @@ internal class Program store.RegisterServer(); }); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp" + options.VerifyToken = "Dmtp"; }); await service.SetupAsync(config); diff --git a/examples/Dmtp/SerializationSelectorConsoleApp/SerializationSelectorConsoleApp.csproj b/examples/Dmtp/SerializationSelectorConsoleApp/SerializationSelectorConsoleApp.csproj index 9a6c6e7ef..d7c3f04f6 100644 --- a/examples/Dmtp/SerializationSelectorConsoleApp/SerializationSelectorConsoleApp.csproj +++ b/examples/Dmtp/SerializationSelectorConsoleApp/SerializationSelectorConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,12 +7,12 @@ enable - - - - - - + + + + + + diff --git a/examples/Examples-All.sln b/examples/Examples-All.sln index b09dc5c52..c9cc3dbd3 100644 --- a/examples/Examples-All.sln +++ b/examples/Examples-All.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.3.32922.545 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.11018.127 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tcp", "Tcp", "{FB46E926-0EEC-488C-B950-A16D2E7F694B}" EndProject @@ -116,7 +116,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DmtpWebApplication", "Dmtp\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteStreamConsoleApp", "Dmtp\RemoteStreamConsoleApp\RemoteStreamConsoleApp.csproj", "{4019C53F-2185-4ACF-A816-C659607B05E5}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dmtp", "Dmtp", "{57B547B6-D725-4C3E-82A7-39ED03BD438B}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "创建Dmtp", "创建Dmtp", "{57B547B6-D725-4C3E-82A7-39ED03BD438B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DmtpConsoleApp", "Dmtp\DmtpConsoleApp\DmtpConsoleApp.csproj", "{44AE2CE8-5EE2-42F6-A1CA-E562EC697445}" EndProject @@ -166,10 +166,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpServiceForWebApi", "Tcp\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpCommandLineConsoleApp", "Tcp\TcpCommandLineConsoleApp\TcpCommandLineConsoleApp.csproj", "{01EB9E70-4A13-41E3-8609-8DFD9C2BC0A4}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "同步请求", "同步请求", "{50312210-D0AC-4E25-B819-BE2F1CC70581}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpWaitingClientWinFormsApp", "Tcp\TcpWaitingClientWinFormsApp\TcpWaitingClientWinFormsApp.csproj", "{DF384D76-50A5-4D7B-A1D2-15CA00B844D4}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpServiceConsoleApp", "Http\HttpServiceConsoleApp\HttpServiceConsoleApp.csproj", "{FADFD5E7-A5AD-49D9-A03F-70DB8E98AD38}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HttpClientConsoleApp", "Http\HttpClientConsoleApp\HttpClientConsoleApp.csproj", "{9F96589A-C7F8-4E33-BD6E-3BDA40205D07}" @@ -184,12 +180,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rpc", "Rpc", "{D01CF5F0-67D EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenerateProxyFromServerConsoleApp", "Rpc\GenerateProxyFromServerConsoleApp\GenerateProxyFromServerConsoleApp.csproj", "{09ABC5EB-0896-4693-A057-A03B35E0294C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdapterConsoleApp", "Adapter\AdapterConsoleApp\AdapterConsoleApp.csproj", "{5F141D56-D6ED-45C7-A355-63EC641246DB}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdapterTesterConsoleApp", "Adapter\AdapterTesterConsoleApp\AdapterTesterConsoleApp.csproj", "{E1C1B35D-6336-413B-B7DE-25BC24AE401A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TLVWinFormsApp", "Adapter\TLVWinFormsApp\TLVWinFormsApp.csproj", "{E05EFE74-1D74-44BF-8DE6-AA4B0DC4BC97}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DmtpChannel", "DmtpChannel", "{01B7AC92-32D4-4864-B5CF-02752C391C9B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DmtpChannelConsoleApp", "Dmtp\DmtpChannelConsoleApp\DmtpChannelConsoleApp.csproj", "{3D418431-3CD2-439A-AE5F-2BBC7FF977C6}" @@ -230,10 +222,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispatchProxyJsonRpcClientC EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispatchProxyXmlRpcClientConsoleApp", "XmlRpc\DispatchProxyXmlRpcClientConsoleApp\DispatchProxyXmlRpcClientConsoleApp.csproj", "{8AFB1C99-7E16-4912-B662-91C5328C6BAE}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RealityProxy", "RealityProxy", "{995183D4-74FD-4EDD-8FDF-8B6BC0410A06}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RealityProxyDmtpRpcConsoleApp", "Dmtp\RealityProxyDmtpRpcConsoleApp\RealityProxyDmtpRpcConsoleApp.csproj", "{C94B9E69-3B48-4AAB-B3C3-80AA190640C2}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosting", "Hosting", "{0E116F60-01DE-4648-B4EE-5B944EED42AA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HostingWorkerService", "Hosting\HostingWorkerService\HostingWorkerService.csproj", "{866798F5-FD69-49D2-B4FA-279DC7188A54}" @@ -256,8 +244,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcRateLimitingConsoleApp", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PluginPassingParameters", "PluginPassingParameters", "{B9AD57A2-89FB-459B-8D58-41C770CCA89B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReuseAddressServerConsoleApp", "Tcp\ReuseAddressServerConsoleApp\ReuseAddressServerConsoleApp.csproj", "{1E65E919-C7D8-4678-8BFD-1434CC8293BF}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DmtpAspnetcoreConsoleApp", "Dmtp\DmtpAspnetcoreConsoleApp\DmtpAspnetcoreConsoleApp.csproj", "{7208999A-BC28-4476-BBFD-572C8D43E35E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "基于NamedPipe的Dmtp", "基于NamedPipe的Dmtp", "{1B6092F9-4776-4502-818F-B35D153D19D6}" @@ -267,6 +253,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Solutions", ".Solutions", "{043D35EB-9819-4E9A-BDC7-2974A122195D}" ProjectSection(SolutionItems) = preProject Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TcpServiceReadAsyncConsoleApp", "Tcp\TcpServiceReadAsyncConsoleApp\TcpServiceReadAsyncConsoleApp.csproj", "{03EE9539-60C6-4BB5-97D7-3F9B1A077234}" @@ -351,6 +338,32 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlcBridgesConsoleApp", "Plc EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModbusPlcBridgeConsoleApp", "PlcBridges\ModbusPlcBridgeConsoleApp\ModbusPlcBridgeConsoleApp.csproj", "{449F3FDA-0AF3-4ACE-B584-A38037C803E3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RawAdapterConsoleApp", "Adapter\RawAdapterConsoleApp\RawAdapterConsoleApp.csproj", "{A90C21AE-9552-E1EF-028A-309CB5F72843}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TouchSocketBitConverterConsoleApp", "Core\TouchSocketBitConverterConsoleApp\TouchSocketBitConverterConsoleApp.csproj", "{896858AE-13F4-473B-A5D5-B214CD04FDEF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WaitingClient", "WaitingClient", "{432C7F0A-B01D-4113-8DF3-C588B147A4C6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TcpWaitingClientWinFormsApp", "WaitingClient\TcpWaitingClientWinFormsApp\TcpWaitingClientWinFormsApp.csproj", "{90FE56EA-94C2-820D-6E26-012E0BC1BDA9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WaitingClientConsoleApp", "WaitingClient\WaitingClientConsoleApp\WaitingClientConsoleApp.csproj", "{9CC9DEE5-C96B-454E-8CBF-67A359055121}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultipacketAdapterConsoleApp", "Adapter\MultipacketAdapterConsoleApp\MultipacketAdapterConsoleApp.csproj", "{3B17545F-6B5B-C98E-9EA2-27E6FCFFE9AF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateDmtpConsoleApp", "Dmtp\CreateDmtpConsoleApp\CreateDmtpConsoleApp.csproj", "{D791EA02-3EC8-44A0-9877-614DE92BA9B5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleActionConsoleApp", "Core\ConsoleActionConsoleApp\ConsoleActionConsoleApp.csproj", "{F646A400-15A5-9DFE-D66B-76BC09579811}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppMessengerConsoleApp", "Core\AppMessengerConsoleApp\AppMessengerConsoleApp.csproj", "{E69CACF0-FE0E-01E3-0B31-0804EABFFF4D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DependencyPropertyConsoleApp", "Core\DependencyPropertyConsoleApp\DependencyPropertyConsoleApp.csproj", "{FCBCA3E2-22D3-4311-A1B7-AE029B961953}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcRegisterConsoleApp", "Rpc\RpcRegisterConsoleApp\RpcRegisterConsoleApp.csproj", "{F72A1BA0-541A-40CD-89EB-24C4F010DAC0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcAopConsoleApp", "Rpc\RpcAopConsoleApp\RpcAopConsoleApp.csproj", "{3F974BD3-A55A-4D13-AB83-C8FE94CE0041}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcCallContextConsoleApp", "Rpc\RpcCallContextConsoleApp\RpcCallContextConsoleApp.csproj", "{58069766-C855-4B2D-B547-6C256E725215}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -529,10 +542,6 @@ Global {01EB9E70-4A13-41E3-8609-8DFD9C2BC0A4}.Debug|Any CPU.Build.0 = Debug|Any CPU {01EB9E70-4A13-41E3-8609-8DFD9C2BC0A4}.Release|Any CPU.ActiveCfg = Release|Any CPU {01EB9E70-4A13-41E3-8609-8DFD9C2BC0A4}.Release|Any CPU.Build.0 = Release|Any CPU - {DF384D76-50A5-4D7B-A1D2-15CA00B844D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DF384D76-50A5-4D7B-A1D2-15CA00B844D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DF384D76-50A5-4D7B-A1D2-15CA00B844D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DF384D76-50A5-4D7B-A1D2-15CA00B844D4}.Release|Any CPU.Build.0 = Release|Any CPU {FADFD5E7-A5AD-49D9-A03F-70DB8E98AD38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FADFD5E7-A5AD-49D9-A03F-70DB8E98AD38}.Debug|Any CPU.Build.0 = Debug|Any CPU {FADFD5E7-A5AD-49D9-A03F-70DB8E98AD38}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -553,18 +562,10 @@ Global {09ABC5EB-0896-4693-A057-A03B35E0294C}.Debug|Any CPU.Build.0 = Debug|Any CPU {09ABC5EB-0896-4693-A057-A03B35E0294C}.Release|Any CPU.ActiveCfg = Release|Any CPU {09ABC5EB-0896-4693-A057-A03B35E0294C}.Release|Any CPU.Build.0 = Release|Any CPU - {5F141D56-D6ED-45C7-A355-63EC641246DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F141D56-D6ED-45C7-A355-63EC641246DB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F141D56-D6ED-45C7-A355-63EC641246DB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F141D56-D6ED-45C7-A355-63EC641246DB}.Release|Any CPU.Build.0 = Release|Any CPU {E1C1B35D-6336-413B-B7DE-25BC24AE401A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E1C1B35D-6336-413B-B7DE-25BC24AE401A}.Debug|Any CPU.Build.0 = Debug|Any CPU {E1C1B35D-6336-413B-B7DE-25BC24AE401A}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1C1B35D-6336-413B-B7DE-25BC24AE401A}.Release|Any CPU.Build.0 = Release|Any CPU - {E05EFE74-1D74-44BF-8DE6-AA4B0DC4BC97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E05EFE74-1D74-44BF-8DE6-AA4B0DC4BC97}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E05EFE74-1D74-44BF-8DE6-AA4B0DC4BC97}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E05EFE74-1D74-44BF-8DE6-AA4B0DC4BC97}.Release|Any CPU.Build.0 = Release|Any CPU {3D418431-3CD2-439A-AE5F-2BBC7FF977C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D418431-3CD2-439A-AE5F-2BBC7FF977C6}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D418431-3CD2-439A-AE5F-2BBC7FF977C6}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -629,10 +630,6 @@ Global {8AFB1C99-7E16-4912-B662-91C5328C6BAE}.Debug|Any CPU.Build.0 = Debug|Any CPU {8AFB1C99-7E16-4912-B662-91C5328C6BAE}.Release|Any CPU.ActiveCfg = Release|Any CPU {8AFB1C99-7E16-4912-B662-91C5328C6BAE}.Release|Any CPU.Build.0 = Release|Any CPU - {C94B9E69-3B48-4AAB-B3C3-80AA190640C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C94B9E69-3B48-4AAB-B3C3-80AA190640C2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C94B9E69-3B48-4AAB-B3C3-80AA190640C2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C94B9E69-3B48-4AAB-B3C3-80AA190640C2}.Release|Any CPU.Build.0 = Release|Any CPU {866798F5-FD69-49D2-B4FA-279DC7188A54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {866798F5-FD69-49D2-B4FA-279DC7188A54}.Debug|Any CPU.Build.0 = Debug|Any CPU {866798F5-FD69-49D2-B4FA-279DC7188A54}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -661,10 +658,6 @@ Global {BAEBA822-4EBF-4211-A92F-797D529C2DE3}.Debug|Any CPU.Build.0 = Debug|Any CPU {BAEBA822-4EBF-4211-A92F-797D529C2DE3}.Release|Any CPU.ActiveCfg = Release|Any CPU {BAEBA822-4EBF-4211-A92F-797D529C2DE3}.Release|Any CPU.Build.0 = Release|Any CPU - {1E65E919-C7D8-4678-8BFD-1434CC8293BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E65E919-C7D8-4678-8BFD-1434CC8293BF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E65E919-C7D8-4678-8BFD-1434CC8293BF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E65E919-C7D8-4678-8BFD-1434CC8293BF}.Release|Any CPU.Build.0 = Release|Any CPU {7208999A-BC28-4476-BBFD-572C8D43E35E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7208999A-BC28-4476-BBFD-572C8D43E35E}.Debug|Any CPU.Build.0 = Debug|Any CPU {7208999A-BC28-4476-BBFD-572C8D43E35E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -809,6 +802,54 @@ Global {449F3FDA-0AF3-4ACE-B584-A38037C803E3}.Debug|Any CPU.Build.0 = Debug|Any CPU {449F3FDA-0AF3-4ACE-B584-A38037C803E3}.Release|Any CPU.ActiveCfg = Release|Any CPU {449F3FDA-0AF3-4ACE-B584-A38037C803E3}.Release|Any CPU.Build.0 = Release|Any CPU + {A90C21AE-9552-E1EF-028A-309CB5F72843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A90C21AE-9552-E1EF-028A-309CB5F72843}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A90C21AE-9552-E1EF-028A-309CB5F72843}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A90C21AE-9552-E1EF-028A-309CB5F72843}.Release|Any CPU.Build.0 = Release|Any CPU + {896858AE-13F4-473B-A5D5-B214CD04FDEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {896858AE-13F4-473B-A5D5-B214CD04FDEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {896858AE-13F4-473B-A5D5-B214CD04FDEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {896858AE-13F4-473B-A5D5-B214CD04FDEF}.Release|Any CPU.Build.0 = Release|Any CPU + {90FE56EA-94C2-820D-6E26-012E0BC1BDA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90FE56EA-94C2-820D-6E26-012E0BC1BDA9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90FE56EA-94C2-820D-6E26-012E0BC1BDA9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90FE56EA-94C2-820D-6E26-012E0BC1BDA9}.Release|Any CPU.Build.0 = Release|Any CPU + {9CC9DEE5-C96B-454E-8CBF-67A359055121}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CC9DEE5-C96B-454E-8CBF-67A359055121}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CC9DEE5-C96B-454E-8CBF-67A359055121}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CC9DEE5-C96B-454E-8CBF-67A359055121}.Release|Any CPU.Build.0 = Release|Any CPU + {3B17545F-6B5B-C98E-9EA2-27E6FCFFE9AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B17545F-6B5B-C98E-9EA2-27E6FCFFE9AF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B17545F-6B5B-C98E-9EA2-27E6FCFFE9AF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B17545F-6B5B-C98E-9EA2-27E6FCFFE9AF}.Release|Any CPU.Build.0 = Release|Any CPU + {D791EA02-3EC8-44A0-9877-614DE92BA9B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D791EA02-3EC8-44A0-9877-614DE92BA9B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D791EA02-3EC8-44A0-9877-614DE92BA9B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D791EA02-3EC8-44A0-9877-614DE92BA9B5}.Release|Any CPU.Build.0 = Release|Any CPU + {F646A400-15A5-9DFE-D66B-76BC09579811}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F646A400-15A5-9DFE-D66B-76BC09579811}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F646A400-15A5-9DFE-D66B-76BC09579811}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F646A400-15A5-9DFE-D66B-76BC09579811}.Release|Any CPU.Build.0 = Release|Any CPU + {E69CACF0-FE0E-01E3-0B31-0804EABFFF4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E69CACF0-FE0E-01E3-0B31-0804EABFFF4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E69CACF0-FE0E-01E3-0B31-0804EABFFF4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E69CACF0-FE0E-01E3-0B31-0804EABFFF4D}.Release|Any CPU.Build.0 = Release|Any CPU + {FCBCA3E2-22D3-4311-A1B7-AE029B961953}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FCBCA3E2-22D3-4311-A1B7-AE029B961953}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FCBCA3E2-22D3-4311-A1B7-AE029B961953}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FCBCA3E2-22D3-4311-A1B7-AE029B961953}.Release|Any CPU.Build.0 = Release|Any CPU + {F72A1BA0-541A-40CD-89EB-24C4F010DAC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F72A1BA0-541A-40CD-89EB-24C4F010DAC0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F72A1BA0-541A-40CD-89EB-24C4F010DAC0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F72A1BA0-541A-40CD-89EB-24C4F010DAC0}.Release|Any CPU.Build.0 = Release|Any CPU + {3F974BD3-A55A-4D13-AB83-C8FE94CE0041}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F974BD3-A55A-4D13-AB83-C8FE94CE0041}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F974BD3-A55A-4D13-AB83-C8FE94CE0041}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F974BD3-A55A-4D13-AB83-C8FE94CE0041}.Release|Any CPU.Build.0 = Release|Any CPU + {58069766-C855-4B2D-B547-6C256E725215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58069766-C855-4B2D-B547-6C256E725215}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58069766-C855-4B2D-B547-6C256E725215}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58069766-C855-4B2D-B547-6C256E725215}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -880,16 +921,12 @@ Global {CC8FCD95-0DDF-4AEA-9F8C-3D3950317B27} = {DB89FCB6-E4F9-4BD4-93F3-4E857741D749} {92F5AD36-4100-47B6-8660-8938EF7705F3} = {97C928E3-54D6-4FAE-A314-775BE9E25A14} {01EB9E70-4A13-41E3-8609-8DFD9C2BC0A4} = {5B8D8451-E920-42E5-9F6A-D6D1238A24B4} - {50312210-D0AC-4E25-B819-BE2F1CC70581} = {FB46E926-0EEC-488C-B950-A16D2E7F694B} - {DF384D76-50A5-4D7B-A1D2-15CA00B844D4} = {50312210-D0AC-4E25-B819-BE2F1CC70581} {FADFD5E7-A5AD-49D9-A03F-70DB8E98AD38} = {EFB33E23-9E98-4B85-99E4-865705D5ACD2} {9F96589A-C7F8-4E33-BD6E-3BDA40205D07} = {EFB33E23-9E98-4B85-99E4-865705D5ACD2} {E7FE662C-24E4-4915-9847-26AB4038540D} = {5126C261-9A81-4FBC-8653-7710C1D1D735} {89C3B730-4024-4C76-8CB0-FAA8BF0945B9} = {5126C261-9A81-4FBC-8653-7710C1D1D735} {09ABC5EB-0896-4693-A057-A03B35E0294C} = {D01CF5F0-67D0-44E3-B7CE-0BAD4F475C0E} - {5F141D56-D6ED-45C7-A355-63EC641246DB} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} {E1C1B35D-6336-413B-B7DE-25BC24AE401A} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} - {E05EFE74-1D74-44BF-8DE6-AA4B0DC4BC97} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} {01B7AC92-32D4-4864-B5CF-02752C391C9B} = {BF701694-E1CE-4FD1-97BA-DA832F6F3D45} {3D418431-3CD2-439A-AE5F-2BBC7FF977C6} = {01B7AC92-32D4-4864-B5CF-02752C391C9B} {2535B065-655A-4799-BF19-B57A8FABA0AD} = {8B9374B5-42D7-48C9-84C7-A560167F0D47} @@ -910,8 +947,6 @@ Global {3AEFF66C-2896-4D53-8066-4D2AFE6AE780} = {5836A018-B0F3-4D6F-8C45-FC1E9C85D51A} {0C74F825-F173-4ABC-AC1C-A0094FBBF4A6} = {969A695E-BEB5-45B8-93D8-B31640FA495D} {8AFB1C99-7E16-4912-B662-91C5328C6BAE} = {94F46729-90A8-415A-92E0-2D996D3210B4} - {995183D4-74FD-4EDD-8FDF-8B6BC0410A06} = {63EE2247-0A5B-47F9-B8AA-AED5BC8FC873} - {C94B9E69-3B48-4AAB-B3C3-80AA190640C2} = {995183D4-74FD-4EDD-8FDF-8B6BC0410A06} {866798F5-FD69-49D2-B4FA-279DC7188A54} = {0E116F60-01DE-4648-B4EE-5B944EED42AA} {EBB7E090-7309-49D6-A0C9-CD704E7FEA31} = {8911AC2E-B951-436C-A76D-7E994017069B} {3043062B-A48A-419F-8F78-9ED234383103} = {0F95EA5A-0E08-4516-89D4-C3BFC88789F9} @@ -919,7 +954,6 @@ Global {74C98BF5-D663-4CCA-B970-D9A1258B6BB9} = {0F95EA5A-0E08-4516-89D4-C3BFC88789F9} {12A8A263-EF41-4B20-97A8-3D050FF1B326} = {EFB33E23-9E98-4B85-99E4-865705D5ACD2} {BAEBA822-4EBF-4211-A92F-797D529C2DE3} = {D01CF5F0-67D0-44E3-B7CE-0BAD4F475C0E} - {1E65E919-C7D8-4678-8BFD-1434CC8293BF} = {FB46E926-0EEC-488C-B950-A16D2E7F694B} {7208999A-BC28-4476-BBFD-572C8D43E35E} = {5C17B127-95DD-480C-BDCC-7FDF5E645B0C} {1B6092F9-4776-4502-818F-B35D153D19D6} = {BF701694-E1CE-4FD1-97BA-DA832F6F3D45} {5AB49F06-014A-4CAF-9A92-F5B3783E51C6} = {1B6092F9-4776-4502-818F-B35D153D19D6} @@ -961,6 +995,18 @@ Global {8849C272-4073-1AF3-0EF1-8E7517A13F38} = {5836A018-B0F3-4D6F-8C45-FC1E9C85D51A} {BE9B0F56-849A-4BCE-A54E-6CEE7B52AB12} = {CDED01F8-D581-2FF7-E03E-F4B04DDFAC03} {449F3FDA-0AF3-4ACE-B584-A38037C803E3} = {CDED01F8-D581-2FF7-E03E-F4B04DDFAC03} + {A90C21AE-9552-E1EF-028A-309CB5F72843} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} + {896858AE-13F4-473B-A5D5-B214CD04FDEF} = {A228384F-7DF9-4144-B84E-AC8BF2F69D1B} + {90FE56EA-94C2-820D-6E26-012E0BC1BDA9} = {432C7F0A-B01D-4113-8DF3-C588B147A4C6} + {9CC9DEE5-C96B-454E-8CBF-67A359055121} = {432C7F0A-B01D-4113-8DF3-C588B147A4C6} + {3B17545F-6B5B-C98E-9EA2-27E6FCFFE9AF} = {F8C07F29-7233-4FD3-A3DC-45963071E20A} + {D791EA02-3EC8-44A0-9877-614DE92BA9B5} = {57B547B6-D725-4C3E-82A7-39ED03BD438B} + {F646A400-15A5-9DFE-D66B-76BC09579811} = {A228384F-7DF9-4144-B84E-AC8BF2F69D1B} + {E69CACF0-FE0E-01E3-0B31-0804EABFFF4D} = {A228384F-7DF9-4144-B84E-AC8BF2F69D1B} + {FCBCA3E2-22D3-4311-A1B7-AE029B961953} = {A228384F-7DF9-4144-B84E-AC8BF2F69D1B} + {F72A1BA0-541A-40CD-89EB-24C4F010DAC0} = {D01CF5F0-67D0-44E3-B7CE-0BAD4F475C0E} + {3F974BD3-A55A-4D13-AB83-C8FE94CE0041} = {D01CF5F0-67D0-44E3-B7CE-0BAD4F475C0E} + {58069766-C855-4B2D-B547-6C256E725215} = {D01CF5F0-67D0-44E3-B7CE-0BAD4F475C0E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DB787235-A13A-4A3D-B5A8-5DFEB6511EEE} diff --git a/examples/Hosting/HostingWorkerService/HostingWorkerService.csproj b/examples/Hosting/HostingWorkerService/HostingWorkerService.csproj index 17c8bff0d..605dcee96 100644 --- a/examples/Hosting/HostingWorkerService/HostingWorkerService.csproj +++ b/examples/Hosting/HostingWorkerService/HostingWorkerService.csproj @@ -8,8 +8,8 @@ - - - + + + diff --git a/examples/Hosting/HostingWorkerService/Program.cs b/examples/Hosting/HostingWorkerService/Program.cs index 2ea8c8251..27b74e3db 100644 --- a/examples/Hosting/HostingWorkerService/Program.cs +++ b/examples/Hosting/HostingWorkerService/Program.cs @@ -10,6 +10,7 @@ // 感谢您的下载和使用 //------------------------------------------------------------------------------ +using TouchSocket.Core; using TouchSocket.NamedPipe; using TouchSocket.Sockets; @@ -23,14 +24,13 @@ public class Program builder.ConfigureServices(services => { - //����TcpService�� + services.AddTcpService(config => { config.SetListenIPHosts(7789); }); - //����TcpClient - //ע�⣬Client��ķ�������������StartAsyncʱ������ִ��ConnectAsync��������Ҫ�������ӣ�������������ֵ������ + services.AddSingletonTcpClient(config => { config.SetRemoteIPHost("127.0.0.1:7789"); @@ -41,7 +41,7 @@ public class Program config.SetListenIPHosts(7790); }); - //���������ܵ����� + services.AddServiceHostedService(config => { config.SetPipeName("pipe7789"); diff --git a/examples/Http/HttpClientConsoleApp/HttpClientConsoleApp.csproj b/examples/Http/HttpClientConsoleApp/HttpClientConsoleApp.csproj index 778dcbb2a..4149e5504 100644 --- a/examples/Http/HttpClientConsoleApp/HttpClientConsoleApp.csproj +++ b/examples/Http/HttpClientConsoleApp/HttpClientConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,7 +7,7 @@ - + - + diff --git a/examples/Http/HttpServiceConsoleApp/Program.cs b/examples/Http/HttpServiceConsoleApp/Program.cs index b6399034d..c6ac55839 100644 --- a/examples/Http/HttpServiceConsoleApp/Program.cs +++ b/examples/Http/HttpServiceConsoleApp/Program.cs @@ -10,9 +10,12 @@ // 感谢您的下载和使用 //------------------------------------------------------------------------------ +using Newtonsoft.Json; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.IO; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -32,8 +35,9 @@ internal class Program //最后客户端需要先安装证书。 var service = new HttpService(); - await service.SetupAsync(new TouchSocketConfig()//加载配置 - .SetListenIPHosts(7789) + + var config = new TouchSocketConfig(); + config.SetListenIPHosts(7789) .ConfigureContainer(a => { a.AddConsoleLogger(); @@ -51,23 +55,16 @@ internal class Program a.Add(); a.Add(); - a.UseHttpStaticPage() - .SetNavigateAction(request => - { - //此处可以设置重定向 - return request.RelativeURL; - }) - .SetResponseAction(response => - { - //可以设置响应头 - }) - .AddFolder("api/");//添加静态页面文件夹 - //default插件应该最后添加,其作用是 //1、为找不到的路由返回404 //2、处理 header 为Option的探视跨域请求。 a.UseDefaultHttpServicePlugin(); - })); + }); + + ConfigureStaticPage(config); + + await service.SetupAsync(new TouchSocketConfig()//加载配置 + ); await service.StartAsync(); Console.WriteLine("Http服务器已启动"); @@ -78,6 +75,92 @@ internal class Program Console.WriteLine("Post访问 http://127.0.0.1:7789/uploadfile 上传文件"); Console.ReadKey(); } + + private static void ConfigureStaticPage(TouchSocketConfig config) + { + #region Http服务器启用静态页面插件 + config.ConfigurePlugins(a => + { + a.UseHttpStaticPage(options => + { + //添加静态页面文件夹 + options.AddFolder("api/"); + + #region 静态页面请求资源定向 + options.SetNavigateAction(request => + { + //此处可以设置重定向 + return request.RelativeURL; + }); + #endregion + + #region 静态页面响应设置 + options.SetResponseAction(response => + { + //可以设置响应头 + }); + #endregion + + #region 静态页面配置ContentType + options.SetContentTypeProvider(provider => + { + provider.Add(".txt", "text/plain"); + }); + #endregion + + }); + }); + #endregion + } + + private static async Task CreateHttpService() + { + #region 创建Http服务器 {10} + var service = new HttpService(); + await service.SetupAsync(new TouchSocketConfig()//加载配置 + .SetListenIPHosts(7789) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + //default插件应该最后添加,其作用是 + //1、为找不到的路由返回404 + //2、处理 header 为Option的探视跨域请求。 + a.UseDefaultHttpServicePlugin(); + })); + await service.StartAsync(); + #endregion + } + + private static async Task CreateHttpService1() + { + #region 创建Ssl的Http服务器 {4-8} + var service = new HttpService(); + await service.SetupAsync(new TouchSocketConfig()//加载配置 + .SetListenIPHosts(7789) + .SetServiceSslOption(options => + { + options.Certificate = new X509Certificate2("TouchSocketTestCert.pfx", "123456"); + options.SslProtocols = System.Security.Authentication.SslProtocols.Tls12; + }) + .ConfigureContainer(a => + { + a.AddConsoleLogger(); + }) + .ConfigurePlugins(a => + { + a.Add(); + //default插件应该最后添加,其作用是 + //1、为找不到的路由返回404 + //2、处理 header 为Option的探视跨域请求。 + a.UseDefaultHttpServicePlugin(); + })); + await service.StartAsync(); + #endregion + } } public class MyBigWriteHttpPlug : PluginBase, IHttpPlugin @@ -137,7 +220,7 @@ public class MyUploadBigFileHttpPlugin : PluginBase, IHttpPlugin try { var fileName = e.Context.Request.Headers["FileName"]; - if (fileName.IsNullOrEmpty()) + if (fileName.IsEmpty) { await e.Context.Response .SetStatus(502, "fileName is null") @@ -180,32 +263,40 @@ public class MyHttpPlugin4 : PluginBase, IHttpPlugin var content = await e.Context.Request.GetContentAsync(); //情况2,当数据太大时,可持续读取 + #region Http服务器持续读取Body内容 while (true) { var buffer = new byte[1024 * 64]; using (var blockResult = await e.Context.Request.ReadAsync()) { + var memory = blockResult.Memory;//本次读取的数据 + + //把本次读取的数据写入缓冲区,或者直接处理 + memory.CopyTo(buffer); + if (blockResult.IsCompleted) { + //读取完毕 break; } - - //这里可以一直处理读到的数据。 - blockResult.Memory.CopyTo(buffer); } } + #endregion //情况3,或者把数据读到流 + #region Http服务器获取Body持续写入Stream中 using (var stream = new MemoryStream()) { // await e.Context.Request.ReadCopyToAsync(stream); } + #endregion + //情况4,接收小文件。 - + #region Http服务器获取Body小文件集合 if (e.Context.Request.ContentLength > 1024 * 1024 * 100)//全部数据体超过100Mb则直接拒绝接收。 { await e.Context.Response @@ -229,12 +320,14 @@ public class MyHttpPlugin4 : PluginBase, IHttpPlugin var data = file.Data; //开始保存数据到磁盘 - using (var fileStream = File.OpenWrite(file.Name)) + using (var fileStream = File.Create(file.Name)) { await fileStream.WriteAsync(data); await fileStream.FlushAsync(); } } + #endregion + await e.Context.Response .SetStatusWithSuccess() @@ -255,6 +348,7 @@ public class MyHttpPlug3 : PluginBase, IHttpPlugin { public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) { + #region Http服务器响应页面请求 if (e.Context.Request.IsGet()) { if (e.Context.Request.UrlEquals("/html")) @@ -284,11 +378,12 @@ public class MyHttpPlug3 : PluginBase, IHttpPlugin return; } } - + #endregion await e.InvokeNext(); } } +#region Http服务器响应文件 public class MyHttpPlug2 : PluginBase, IHttpPlugin { public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) @@ -299,14 +394,45 @@ public class MyHttpPlug2 : PluginBase, IHttpPlugin { try { + //假设这是一个很大的文件 + var fileInfo = new FileInfo(@"D:\System\Windows.iso"); + + //可以重新命名下载的文件名,不设置则为本地文件名 + string fileName = null; + + //是否自动启用gzip压缩,前提是HttpRequest请求了gzip + var autoGzip = true; + + //流式传输操作,可以控制流速、获取当前流速、进度等 + var httpFlowOperator = new HttpFlowOperator(); + + //流速控制,当前设置为最大512KB/秒 + httpFlowOperator.MaxSpeed = 1024 * 512; + + //每次读取文件长度,数值越大,效率越高,但对内存要求也越高 + httpFlowOperator.BlockSize = 1024 * 8; + + //可以设置可取消令箭操作 + using var cts = new CancellationTokenSource(); + httpFlowOperator.Token = cts.Token; + + using var timer = new Timer(state => + { + //每秒打印当前流速、进度等信息 + Console.WriteLine($"当前流速:{httpFlowOperator.Speed() / 1024.0}KB/s,进度:{httpFlowOperator.Progress}"); + }, null, 1000, 1000); + //直接回应文件。 await e.Context.Response .SetStatusWithSuccess()//必须要有状态 - .FromFileAsync(new FileInfo(@"D:\System\Windows.iso"), e.Context.Request); + .FromFileAsync(fileInfo, httpFlowOperator, e.Context.Request, fileName, autoGzip); } catch (Exception ex) { - await e.Context.Response.SetStatus(403, ex.Message).FromText(ex.Message).AnswerAsync(); + await e.Context.Response + .SetStatus(403, ex.Message) + .FromText(ex.Message) + .AnswerAsync(); } return; @@ -315,13 +441,18 @@ public class MyHttpPlug2 : PluginBase, IHttpPlugin await e.InvokeNext(); } } +#endregion + +#region Http服务器使用插件 public class MyHttpPlug1 : PluginBase, IHttpPlugin { public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) { + #region HttpContext生命周期 var request = e.Context.Request;//http请求体 var response = e.Context.Response;//http响应体 + #endregion if (request.IsGet() && request.UrlEquals("/success")) { @@ -339,7 +470,126 @@ public class MyHttpPlug1 : PluginBase, IHttpPlugin await e.InvokeNext(); } } +#endregion +public class MyHttpPlug11 : PluginBase, IHttpPlugin +{ + public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) + { + var request = e.Context.Request;//http请求体 + var response = e.Context.Response;//http响应体 + + #region Http服务器获取Query参数 + var name = e.Context.Request.Query.Get("name"); + //或者 + var name2 = e.Context.Request.Query["name"]; + //或者 + if (e.Context.Request.Query.TryGetValue("name", out var nameValue)) + { + //获取成功 + } + #endregion + + #region Http服务器获取Header参数 + var nameHeader1 = e.Context.Request.Headers.Get("name"); + //或者 + var name2Header1 = e.Context.Request.Headers["name"]; + //或者 + if (e.Context.Request.Headers.TryGetValue("name", out var nameValueHeader1)) + { + //获取成功 + } + #endregion + + #region Http服务器从预设获取Header参数 + var nameHeader2 = e.Context.Request.Headers.Get(HttpHeaders.Authorization); + //或者 + var name2Header2 = e.Context.Request.Headers[HttpHeaders.Authorization]; + //或者 + if (e.Context.Request.Headers.TryGetValue(HttpHeaders.Authorization, out var nameValueHeader2)) + { + //获取成功 + } + #endregion + + #region Http服务器获取字符串Body内容 + var bodyString = await e.Context.Request.GetBodyAsync(); + #endregion + + #region Http服务器获取内存Body内容 + var content = await e.Context.Request.GetContentAsync(); + #endregion + + if (request.IsGet() && request.UrlEquals("/success")) + { + #region Http服务器设置响应状态 + e.Context.Response.SetStatus(200, "success"); + + //或者 + e.Context.Response.SetStatusWithSuccess(); + #endregion + + #region Http服务器设置响应Header + e.Context.Response.Headers.Add("1", "1"); + + //或者 + e.Context.Response.Headers["1"] = "1"; + + //或者 + e.Context.Response.Headers.TryAdd("1", "1"); + + //或者 + e.Context.Response.AddHeader("1", "1"); + + //或者 + e.Context.Response.AddHeader(HttpHeaders.Authorization, "Authorization"); + #endregion + + #region Http服务器设置响应内容 + e.Context.Response.SetContent("Hello World"); + + //或者 + e.Context.Response.FromText("Hello World"); + + //或者 + e.Context.Response.SetContent(Encoding.UTF8.GetBytes("Hello World")); + #endregion + + #region Http服务器设置响应Json内容 + var obj = new + { + Name = "TouchSocket", + Author = "若汝棋茗", + Blog = "https://blog.csdn.net/qq_40374647" + }; + e.Context.Response.FromJson(JsonConvert.SerializeObject(obj)); + #endregion + + #region Http服务器设置响应Xml内容 + var xml = @" + + + TouchSocket + 若汝棋茗 + https://blog.csdn.net/qq_40374647 +"; + e.Context.Response.FromXml(xml); + #endregion + + #region Http服务器执行响应 + //直接响应文字 + await e.Context.Response.AnswerAsync(); + #endregion + + Console.WriteLine("处理/success"); + return; + } + + + //无法处理,调用下一个插件 + await e.InvokeNext(); + } +} public class TestFormPlugin : PluginBase, IHttpPlugin { public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) @@ -348,15 +598,21 @@ public class TestFormPlugin : PluginBase, IHttpPlugin { if (e.Context.Request.UrlEquals("/form")) { + #region Http服务器获取Form参数 var formCollection = await e.Context.Request.GetFormCollectionAsync(); foreach (var item in formCollection) { Console.WriteLine($"{item.Key}={item.Value}"); } + #endregion + + #region Http服务器链式响应 await e.Context.Response .SetStatusWithSuccess() .FromText("Ok") .AnswerAsync(); + #endregion + } } await e.InvokeNext(); @@ -365,11 +621,11 @@ public class TestFormPlugin : PluginBase, IHttpPlugin public class MyCustomDownloadHttpPlug : PluginBase, IHttpPlugin { - private readonly ILog logger; + private readonly ILog m_logger; public MyCustomDownloadHttpPlug(ILog logger) { - this.logger = logger; + this.m_logger = logger; } public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) { @@ -415,15 +671,15 @@ public class MyCustomDownloadHttpPlug : PluginBase, IHttpPlugin break; } - await response.WriteAsync(buffer.Slice(0, readLen)); + await response.WriteAsync(buffer[..readLen]); } } - this.logger.Info("Success"); + this.m_logger.Info("Success"); } catch (Exception ex) { - this.logger.Exception(ex); + this.m_logger.Exception(ex); //await response.SetStatus(403, ex.Message) // .AnswerAsync(); } @@ -431,13 +687,13 @@ public class MyCustomDownloadHttpPlug : PluginBase, IHttpPlugin } } -class MyDelayResponsePlugin : PluginBase, IHttpPlugin +internal class MyDelayResponsePlugin : PluginBase, IHttpPlugin { - private ConcurrentQueue> m_queue = new(); + private readonly ConcurrentQueue> m_queue = new(); public MyDelayResponsePlugin() { - Task.Factory.StartNew(HandleQueue, TaskCreationOptions.LongRunning); + Task.Factory.StartNew(this.HandleQueue, TaskCreationOptions.LongRunning); } private async Task HandleQueue() @@ -448,7 +704,7 @@ class MyDelayResponsePlugin : PluginBase, IHttpPlugin await Task.Delay(3000); //处理队列 - while (m_queue.TryDequeue(out var tcs)) + while (this.m_queue.TryDequeue(out var tcs)) { //返回结果 tcs.SetResult(Guid.NewGuid().ToString()); @@ -463,7 +719,7 @@ class MyDelayResponsePlugin : PluginBase, IHttpPlugin if (request.UrlEquals("/delay")) { var tcs = new TaskCompletionSource(); - m_queue.Enqueue(tcs); + this.m_queue.Enqueue(tcs); var result = await tcs.Task; await response @@ -475,13 +731,13 @@ class MyDelayResponsePlugin : PluginBase, IHttpPlugin } } -class MyDelayResponsePlugin2 : PluginBase, IHttpPlugin +internal class MyDelayResponsePlugin2 : PluginBase, IHttpPlugin { - ConcurrentQueue m_queue = new(); + private readonly ConcurrentQueue m_queue = new(); public MyDelayResponsePlugin2() { - Task.Factory.StartNew(HandleQueue, TaskCreationOptions.LongRunning); + Task.Factory.StartNew(this.HandleQueue, TaskCreationOptions.LongRunning); } private async Task HandleQueue() @@ -492,7 +748,7 @@ class MyDelayResponsePlugin2 : PluginBase, IHttpPlugin await Task.Delay(3000); //处理队列 - while (m_queue.TryDequeue(out var tcs)) + while (this.m_queue.TryDequeue(out var tcs)) { //返回结果 @@ -502,9 +758,9 @@ class MyDelayResponsePlugin2 : PluginBase, IHttpPlugin response.SetStatus(200, "success"); response.IsChunk = true; - for (int i = 0; i < 5; i++) + for (var i = 0; i < 5; i++) { - await response.WriteAsync(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()+"\r\n")); + await response.WriteAsync(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString() + "\r\n")); await Task.Delay(1000); } @@ -522,14 +778,14 @@ class MyDelayResponsePlugin2 : PluginBase, IHttpPlugin if (request.UrlEquals("/delay2")) { var tcs = new MyTaskCompletionSource(client, e.Context); - m_queue.Enqueue(tcs); + this.m_queue.Enqueue(tcs); var result = await tcs.Task; //不做任何处理 } await e.InvokeNext(); } - class MyTaskCompletionSource : TaskCompletionSource + private class MyTaskCompletionSource : TaskCompletionSource { public MyTaskCompletionSource(IHttpSessionClient client, HttpContext context) { @@ -540,4 +796,59 @@ class MyDelayResponsePlugin2 : PluginBase, IHttpPlugin public IHttpSessionClient Client { get; } public HttpContext Context { get; } } -} \ No newline at end of file +} + +#region Http服务器响应有长度大数据 {10,13,18} +internal class MyHttpPlugin22 : PluginBase, IHttpPlugin +{ + public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) + { + var request = e.Context.Request;//http请求体 + var response = e.Context.Response;//http响应体 + if (e.Context.Request.IsGet() && e.Context.Request.UrlEquals("/data1")) + { + //1.先设置需要响应的相关配置 + response.SetStatusWithSuccess(); + + //2.然后设置数据总长度 + response.ContentLength = 1024 * 1024; + + for (var i = 0; i < 1024; i++) + { + //3.将数据持续写入 + await response.WriteAsync(new byte[1024]); + } + } + await e.InvokeNext(); + } +} +#endregion + +#region Http服务器响应无长度大数据 {10,13,18,22} +internal class MyHttpPlugin33 : PluginBase, IHttpPlugin +{ + public async Task OnHttpRequest(IHttpSessionClient client, HttpContextEventArgs e) + { + var request = e.Context.Request;//http请求体 + var response = e.Context.Response;//http响应体 + if (e.Context.Request.IsGet() && e.Context.Request.UrlEquals("/data2")) + { + //1.先设置需要响应的相关配置 + response.SetStatusWithSuccess(); + + //2.设置使用Chunk模式 + response.IsChunk = true; + + for (var i = 0; i < 1024; i++) + { + //3.将数据持续写入 + await response.WriteAsync(new byte[1024]); + } + + //4.在正式数据传输完成后,调用此方法,客户端才知道数据结束了 + await response.CompleteChunkAsync(); + } + await e.InvokeNext(); + } +} +#endregion diff --git a/examples/Http/HttpServiceForCorsConsoleApp/HttpServiceForCorsConsoleApp.csproj b/examples/Http/HttpServiceForCorsConsoleApp/HttpServiceForCorsConsoleApp.csproj index 1099a07d7..eb2eeb8d7 100644 --- a/examples/Http/HttpServiceForCorsConsoleApp/HttpServiceForCorsConsoleApp.csproj +++ b/examples/Http/HttpServiceForCorsConsoleApp/HttpServiceForCorsConsoleApp.csproj @@ -8,7 +8,7 @@ - + - - - - - - \ No newline at end of file diff --git a/examples/Udp/UdpBroadcastConsoleApp/Program.cs b/examples/Udp/UdpBroadcastConsoleApp/Program.cs index b639ea597..9b0c25c62 100644 --- a/examples/Udp/UdpBroadcastConsoleApp/Program.cs +++ b/examples/Udp/UdpBroadcastConsoleApp/Program.cs @@ -12,7 +12,6 @@ using System.Net; using System.Text; -using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.Sockets; @@ -26,14 +25,14 @@ internal class Program var udpService = new UdpSession(); await udpService.SetupAsync(new TouchSocketConfig() .SetBindIPHost(new IPHost(7789)) - .UseBroadcast() + .SetEnableBroadcast(true) .ConfigurePlugins(a => { a.Add(); a.Add(); a.Add(); }) - .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())); + ); await udpService.StartAsync(); //加入组播组 @@ -43,8 +42,8 @@ internal class Program await udpClient.SetupAsync(new TouchSocketConfig() //.UseUdpReceive()//作为客户端时,如果需要接收数据,那么需要绑定端口。要么使用SetBindIPHost指定端口,要么调用UseUdpReceive绑定随机端口。 .SetBindIPHost(new IPHost(7788)) - .UseBroadcast()//该配置在广播时是必须的 - .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())); + .SetEnableBroadcast(true)//该配置在广播时是必须的 + ); await udpClient.StartAsync(); while (true) @@ -64,7 +63,7 @@ internal class Program { public async Task OnUdpReceived(IUdpSessionBase client, UdpReceivedDataEventArgs e) { - var msg = e.ByteBlock.ToString(); + var msg = e.Memory.Span.ToUtf8String(); if (msg == "hello") { Console.WriteLine("已处理Hello"); @@ -81,7 +80,7 @@ internal class Program { public async Task OnUdpReceived(IUdpSessionBase client, UdpReceivedDataEventArgs e) { - var msg = e.ByteBlock.ToString(); + var msg = e.Memory.Span.ToUtf8String(); if (msg == "hi") { Console.WriteLine("已处理Hi"); @@ -98,7 +97,7 @@ internal class Program { public async Task OnUdpReceived(IUdpSessionBase client, UdpReceivedDataEventArgs e) { - var msg = e.ByteBlock.ToString(); + var msg = e.Memory.Span.ToUtf8String(); Console.WriteLine(msg); await Task.CompletedTask; } diff --git a/examples/Udp/UdpBroadcastConsoleApp/UdpBroadcastConsoleApp.csproj b/examples/Udp/UdpBroadcastConsoleApp/UdpBroadcastConsoleApp.csproj index f18b62f22..6608859ea 100644 --- a/examples/Udp/UdpBroadcastConsoleApp/UdpBroadcastConsoleApp.csproj +++ b/examples/Udp/UdpBroadcastConsoleApp/UdpBroadcastConsoleApp.csproj @@ -8,12 +8,12 @@ - - - - - - + + + + + + diff --git a/examples/Udp/UdpDemoApp/Form1.cs b/examples/Udp/UdpDemoApp/Form1.cs index 2c84cf7f9..6b8a718a6 100644 --- a/examples/Udp/UdpDemoApp/Form1.cs +++ b/examples/Udp/UdpDemoApp/Form1.cs @@ -12,7 +12,6 @@ using System; using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using TouchSocket.Core; using TouchSocket.Sockets; @@ -33,14 +32,14 @@ public partial class Form1 : Form { this.m_udpSession.Received = async (remote, e) => { - if (e.ByteBlock.Length > 1024) + if (e.Memory.Length > 1024) { - this.m_udpSession.Logger.Info($"收到:{e.ByteBlock.Length}长度的数据。"); + this.m_udpSession.Logger.Info($"收到:{e.Memory.Length}长度的数据。"); await this.m_udpSession.SendAsync("收到"); } else { - this.m_udpSession.Logger.Info($"收到:{e.ByteBlock.Span.ToString(Encoding.UTF8)}"); + this.m_udpSession.Logger.Info($"收到:{e.Memory.Span.ToString(Encoding.UTF8)}"); } var endPoint = e.EndPoint; }; @@ -48,7 +47,7 @@ public partial class Form1 : Form await this.m_udpSession.SetupAsync(new TouchSocketConfig() .SetBindIPHost(new IPHost(this.textBox2.Text)) .SetRemoteIPHost(new IPHost(this.textBox3.Text)) - .UseBroadcast() + .SetEnableBroadcast(true) .SetUdpDataHandlingAdapter(() => { if (this.checkBox1.Checked) @@ -57,7 +56,7 @@ public partial class Form1 : Form } else { - return new NormalUdpDataHandlingAdapter(); + return default; } }) .ConfigureContainer(a => @@ -105,8 +104,8 @@ public partial class Form1 : Form }); //然后使用SendThenReturn。 - var returnData = await waitClient.SendThenReturnAsync(Encoding.UTF8.GetBytes("RRQM")); - this.ShowMsg($"收到回应消息:{Encoding.UTF8.GetString(returnData)}"); + using var returnData = await waitClient.SendThenResponseAsync(Encoding.UTF8.GetBytes("RRQM")); + this.ShowMsg($"收到回应消息:{Encoding.UTF8.GetString(returnData.Memory.Span)}"); ////同时,如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时,可以使用SendThenResponse. //ResponsedData responsedData = waitClient.SendThenResponse(Encoding.UTF8.GetBytes("RRQM")); diff --git a/examples/Udp/UdpDemoApp/UdpDemoApp.csproj b/examples/Udp/UdpDemoApp/UdpDemoApp.csproj index 2e5f4e936..f2f2eead4 100644 --- a/examples/Udp/UdpDemoApp/UdpDemoApp.csproj +++ b/examples/Udp/UdpDemoApp/UdpDemoApp.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -7,11 +7,11 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/examples/Udp/UdpDemoApp/UdpSessionDocExamples.cs b/examples/Udp/UdpDemoApp/UdpSessionDocExamples.cs new file mode 100644 index 000000000..593b14d0c --- /dev/null +++ b/examples/Udp/UdpDemoApp/UdpSessionDocExamples.cs @@ -0,0 +1,233 @@ +//------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Net; +using System.Text; +using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Sockets; + +namespace UdpDemoApp; + +#region UdpSession作为服务器使用 +internal class UdpSessionServerExample +{ + public async Task ServerExample() + { + var udpService = new UdpSession(); + udpService.Received = (c, e) => + { + Console.WriteLine(e.Memory.ToString()); + return EasyTask.CompletedTask; + }; + await udpService.SetupAsync(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7789))); + await udpService.StartAsync(); + Console.WriteLine("等待接收"); + } +} +#endregion + +#region UdpSession作为客户端使用 +internal class UdpSessionClientExample +{ + public async Task ClientExample() + { + var udpClient = new UdpSession(); + await udpClient.SetupAsync(new TouchSocketConfig() + //.UseUdpReceive()//作为客户端时,如果需要接收数据,那么需要绑定端口。要么使用SetBindIPHost指定端口,要么调用UseUdpReceive绑定随机端口。 + .SetBindIPHost(new IPHost(7788))); + await udpClient.StartAsync(); + } +} +#endregion + +#region UdpSession发送到接收数据的地址 +internal class MyPluginClass : PluginBase, IUdpReceivedPlugin +{ + public async Task OnUdpReceived(IUdpSessionBase client, UdpReceivedDataEventArgs e) + { + if (client is IUdpSession udpSession) + { + await udpSession.SendAsync(e.EndPoint, Encoding.UTF8.GetBytes("RRQM")); + } + await e.InvokeNext(); + } +} +#endregion + +#region UdpSession委托接收 +internal class UdpSessionDelegateReceiveExample +{ + public async Task DelegateReceiveExample() + { + var udpService = new UdpSession(); + udpService.Received = (c, e) => + { + Console.WriteLine(e.Memory.ToString()); + return EasyTask.CompletedTask; + }; + await udpService.StartAsync(7789); + } +} +#endregion + +#region UdpSession插件接收声明插件1 +internal class MyPluginClass1 : PluginBase, IUdpReceivedPlugin +{ + public async Task OnUdpReceived(IUdpSessionBase client, UdpReceivedDataEventArgs e) + { + var msg = e.Memory.ToString(); + if (msg == "hello") + { + Console.WriteLine("已处理Hello"); + } + else + { + //如果判断逻辑发现此处无法处理,即可转到下一个插件 + await e.InvokeNext(); + } + } +} +#endregion + +#region UdpSession插件接收声明插件2 +internal class MyPluginClass2 : PluginBase, IUdpReceivedPlugin +{ + public async Task OnUdpReceived(IUdpSessionBase client, UdpReceivedDataEventArgs e) + { + var msg = e.Memory.ToString(); + if (msg == "hi") + { + Console.WriteLine("已处理Hi"); + } + else + { + //如果判断逻辑发现此处无法处理,即可转到下一个插件 + await e.InvokeNext(); + } + } +} +#endregion + +#region UdpSession插件接收使用插件 +internal class UdpSessionPluginReceiveExample +{ + public async Task PluginReceiveExample() + { + var udpService = new UdpSession(); + await udpService.SetupAsync(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7789)) + .ConfigurePlugins(a => + { + a.Add(); + a.Add(); + })); + await udpService.StartAsync(); + } +} +#endregion + +#region UdpSession创建组播服务器 +internal class UdpSessionMulticastServerExample +{ + public async Task MulticastServerExample() + { + //创建udpService + var udpService = new UdpSession(); + udpService.Received = (remote, e) => + { + Console.WriteLine(e.Memory.ToString()); + return EasyTask.CompletedTask; + }; + await udpService.SetupAsync(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7789)) + .SetEnableBroadcast(true)); + await udpService.StartAsync(); + + //加入组播组 + udpService.JoinMulticastGroup(IPAddress.Parse("224.5.6.7")); + } +} +#endregion + +#region UdpSession发送组播数据 +internal class UdpSessionMulticastSendExample +{ + public async Task MulticastSendExample() + { + var udpClient = new UdpSession(); + await udpClient.SetupAsync(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7788))); + await udpClient.StartAsync(); + + await udpClient.SendAsync(new IPEndPoint(IPAddress.Parse("224.5.6.7"), 7789), Encoding.UTF8.GetBytes("我是组播")); + } +} +#endregion + +#region UdpSession创建广播服务器 +internal class UdpSessionBroadcastServerExample +{ + public async Task BroadcastServerExample() + { + //创建udpService + var udpService = new UdpSession(); + udpService.Received = (remote, e) => + { + Console.WriteLine(e.Memory.ToString()); + return EasyTask.CompletedTask; + }; + await udpService.SetupAsync(new TouchSocketConfig() + .SetBindIPHost(new IPHost(7789)) + .SetEnableBroadcast(true)); + await udpService.StartAsync(); + } +} +#endregion + +#region UdpSession发送广播数据 +internal class UdpSessionBroadcastSendExample +{ + public async Task BroadcastSendExample() + { + var udpClient = new UdpSession(); + await udpClient.SetupAsync(new TouchSocketConfig() + .SetEnableBroadcast(true)//该配置在发送广播时是必须的 + .SetBindIPHost(new IPHost(7788))); + await udpClient.StartAsync(); + + await udpClient.SendAsync(new IPEndPoint(IPAddress.Parse("255.255.255.255"), 7789), Encoding.UTF8.GetBytes("我是广播")); + } +} +#endregion + +#region UdpSession传输大于64K的数据 +internal class UdpSessionBigDataExample +{ + public async Task BigDataExample() + { + var udpSession = new UdpSession(); + udpSession.Received = (endpoint, e) => + { + // 处理接收到的数据 + return EasyTask.CompletedTask; + }; + + await udpSession.SetupAsync(new TouchSocketConfig() + .SetBindIPHost(new IPHost("127.0.0.1:7789")) + .SetUdpDataHandlingAdapter(() => new UdpPackageAdapter()));//加载配置 + await udpSession.StartAsync();//启动 + } +} +#endregion diff --git a/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/Form1.cs b/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/Form1.cs index 2ea2ab453..9e93a5f57 100644 --- a/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/Form1.cs +++ b/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/Form1.cs @@ -11,7 +11,9 @@ //------------------------------------------------------------------------------ using System; +using System.Buffers; using System.Drawing; +using System.IO; using System.Windows.Forms; using TouchSocket.Core; using TouchSocket.Sockets; @@ -19,7 +21,7 @@ using TouchSocket.Sockets; namespace ScreenUdpReceiver; /// -/// 本程序源码由网友“木南白水”提供。 +/// 本程序源码由网友"木南白水"提供。 /// public partial class Form1 : Form { @@ -38,7 +40,30 @@ public partial class Form1 : Form this.udpSession.Received = (c, e) => { - this.pictureBox1.Image = Image.FromStream(e.ByteBlock.AsStream(false)); + + try + { + using var stream = new ReadOnlyMemoryStream(e.Memory); + + // Update UI on the main thread + this.Invoke(() => + { + try + { + this.pictureBox1.Image = Image.FromStream(stream); + } + catch (Exception ex) + { + // Handle image conversion errors silently or log them + Console.WriteLine($"Error converting image: {ex.Message}"); + } + }); + } + catch (Exception ex) + { + } + + return EasyTask.CompletedTask; }; this.udpSession.SetupAsync(new TouchSocketConfig() diff --git a/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/ScreenUdpReceiver.csproj b/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/ScreenUdpReceiver.csproj index 7cd9717f4..81ec51bea 100644 --- a/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/ScreenUdpReceiver.csproj +++ b/examples/Udp/UdpScreenCapture/ScreenUdpReceiver/ScreenUdpReceiver.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -7,7 +7,7 @@ - + \ No newline at end of file diff --git a/examples/Udp/UdpScreenCapture/ScreenUdpSender/Form1.cs b/examples/Udp/UdpScreenCapture/ScreenUdpSender/Form1.cs index f3810f0d5..27f8d2648 100644 --- a/examples/Udp/UdpScreenCapture/ScreenUdpSender/Form1.cs +++ b/examples/Udp/UdpScreenCapture/ScreenUdpSender/Form1.cs @@ -40,8 +40,10 @@ public partial class Form1 : Form { while (true) { - var byteArray = this.ImageToByte(this.getScreen()); - using var bb = new ByteBlock(byteArray); + using var bb = new ByteBlock(1024 * 1024 * 5); + using var img = this.getScreen(); + this.ImageToByte(bb.AsStream(), img); + await this.udpSession.SendAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7790), bb.Memory); await Task.Delay((int)(1000.0 / (int)this.numericUpDown1.Value)); } @@ -76,7 +78,7 @@ public partial class Form1 : Form if (height == -1) height = SystemInformation.VirtualScreen.Height; var tmp = new Bitmap(width, height); //按指定大小创建位图 - var g = Graphics.FromImage(tmp); //从位图创建Graphics对象 + using var g = Graphics.FromImage(tmp); //从位图创建Graphics对象 g.CopyFromScreen(x, y, 0, 0, new Size(width, height)); //绘制 // 绘制鼠标 @@ -90,7 +92,7 @@ public partial class Form1 : Form var cur = new System.Windows.Forms.Cursor(pci.hCursor); cur.Draw(g, new Rectangle(pci.ptScreenPos.x, pci.ptScreenPos.y, cur.Size.Width, cur.Size.Height)); } - catch (Exception ex) { } // 若获取鼠标异常则不显示 + catch (Exception) { } // 若获取鼠标异常则不显示 } //Size halfSize = new Size((int)(tmp.Size.Width * 0.8), (int)(tmp.Size.Height * 0.8)); // 按一半尺寸存储图像 @@ -103,25 +105,16 @@ public partial class Form1 : Form #region 格式转换 - private byte[] ImageToByte(Image Picture) + private void ImageToByte(Stream stream, Image Picture) { - var ms = new MemoryStream(); if (Picture == null) - return new byte[ms.Length]; - Picture.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); - var BPicture = new byte[ms.Length]; - BPicture = ms.GetBuffer(); - return BPicture; + { + return; + } + + Picture.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg); } - private Image ByteToImage(byte[] btImage) - { - if (btImage.Length == 0) - return null; - var ms = new System.IO.MemoryStream(btImage); - var image = System.Drawing.Image.FromStream(ms); - return image; - } #endregion 格式转换 @@ -134,6 +127,7 @@ public partial class Form1 : Form this.udpSession.SetupAsync( new TouchSocketConfig() + .SetUdpConnReset(true) .SetBindIPHost(new IPHost(7789)) .SetUdpDataHandlingAdapter(() => { return new UdpPackageAdapter() { MaxPackageSize = 1024 * 1024, MTU = 1024 * 10 }; })); this.udpSession.StartAsync(); diff --git a/examples/Udp/UdpScreenCapture/ScreenUdpSender/ScreenUdpSender.csproj b/examples/Udp/UdpScreenCapture/ScreenUdpSender/ScreenUdpSender.csproj index 7cd9717f4..81ec51bea 100644 --- a/examples/Udp/UdpScreenCapture/ScreenUdpSender/ScreenUdpSender.csproj +++ b/examples/Udp/UdpScreenCapture/ScreenUdpSender/ScreenUdpSender.csproj @@ -1,4 +1,4 @@ - + WinExe @@ -7,7 +7,7 @@ - + \ No newline at end of file diff --git a/examples/Unity3d/UnityPackage/由于unity包体积较大,以后版本均在qq群(234762506)文件获取.txt b/examples/Unity3d/UnityPackage/由于unity包体积较大,以后版本均在qq群(234762506)文件获取.txt new file mode 100644 index 000000000..7921185eb --- /dev/null +++ b/examples/Unity3d/UnityPackage/由于unity包体积较大,以后版本均在qq群(234762506)文件获取.txt @@ -0,0 +1 @@ +由于unity包体积较大,以后版本均在qq群(234762506)文件获取 \ No newline at end of file diff --git a/examples/Unity3d/UnityServerConsoleApp_2D/Program.cs b/examples/Unity3d/UnityServerConsoleApp_2D/Program.cs index 9a140f87a..8d21d8199 100644 --- a/examples/Unity3d/UnityServerConsoleApp_2D/Program.cs +++ b/examples/Unity3d/UnityServerConsoleApp_2D/Program.cs @@ -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 UnityServerConsoleApp_2D.TouchServer; namespace UnityServerConsoleApp_2D; diff --git a/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/Reverse2DSquareRpcServer.cs b/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/Reverse2DSquareRpcServer.cs index 7c4c8dfc1..70bcd035a 100644 --- a/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/Reverse2DSquareRpcServer.cs +++ b/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/Reverse2DSquareRpcServer.cs @@ -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 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + /* 此代码由Rpc工具直接生成,非必要请不要修改此处代码 */ @@ -20,14 +32,14 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - void UpdatePosition(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, IInvokeOption invokeOption = default); + void UpdatePosition(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, InvokeOption invokeOption = default); /// ///更新位置 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task UpdatePositionAsync(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, IInvokeOption invokeOption = default); + Task UpdatePositionAsync(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, InvokeOption invokeOption = default); /// ///创建新的NPC @@ -35,14 +47,14 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - void NewNPC(System.Int32 id, System.Numerics.Vector3 vector3, IInvokeOption invokeOption = default); + void NewNPC(System.Int32 id, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default); /// ///创建新的NPC /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task NewNPCAsync(System.Int32 id, System.Numerics.Vector3 vector3, IInvokeOption invokeOption = default); + Task NewNPCAsync(System.Int32 id, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default); /// ///玩家离线 @@ -50,14 +62,14 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - void Offline(System.Int32 id, IInvokeOption invokeOption = default); + void Offline(System.Int32 id, InvokeOption invokeOption = default); /// ///玩家离线 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task OfflineAsync(System.Int32 id, IInvokeOption invokeOption = default); + Task OfflineAsync(System.Int32 id, InvokeOption invokeOption = default); /// ///玩家登陆 @@ -65,14 +77,14 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - void PlayerLogin(System.Int32 id, IInvokeOption invokeOption = default); + void PlayerLogin(System.Int32 id, InvokeOption invokeOption = default); /// ///玩家登陆 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task PlayerLoginAsync(System.Int32 id, IInvokeOption invokeOption = default); + Task PlayerLoginAsync(System.Int32 id, InvokeOption invokeOption = default); } public class Reverse2DSquareRpcServer : IReverse2DSquareRpcServer @@ -88,7 +100,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public void UpdatePosition(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, IInvokeOption invokeOption = default) + public void UpdatePosition(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -101,7 +113,7 @@ namespace UnityRpcProxy /// ///更新位置 /// - public Task UpdatePositionAsync(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, IInvokeOption invokeOption = default) + public Task UpdatePositionAsync(System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -118,7 +130,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public void NewNPC(System.Int32 id, System.Numerics.Vector3 vector3, IInvokeOption invokeOption = default) + public void NewNPC(System.Int32 id, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -131,7 +143,7 @@ namespace UnityRpcProxy /// ///创建新的NPC /// - public Task NewNPCAsync(System.Int32 id, System.Numerics.Vector3 vector3, IInvokeOption invokeOption = default) + public Task NewNPCAsync(System.Int32 id, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -148,7 +160,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public void Offline(System.Int32 id, IInvokeOption invokeOption = default) + public void Offline(System.Int32 id, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -161,7 +173,7 @@ namespace UnityRpcProxy /// ///玩家离线 /// - public Task OfflineAsync(System.Int32 id, IInvokeOption invokeOption = default) + public Task OfflineAsync(System.Int32 id, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -178,7 +190,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public void PlayerLogin(System.Int32 id, IInvokeOption invokeOption = default) + public void PlayerLogin(System.Int32 id, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -191,7 +203,7 @@ namespace UnityRpcProxy /// ///玩家登陆 /// - public Task PlayerLoginAsync(System.Int32 id, IInvokeOption invokeOption = default) + public Task PlayerLoginAsync(System.Int32 id, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -211,7 +223,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static void UpdatePosition(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, IInvokeOption invokeOption = default) where TClient : + public static void UpdatePosition(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] @_parameters = new object[] { id, vector3, time }; @@ -221,7 +233,7 @@ namespace UnityRpcProxy /// ///更新位置 /// - public static Task UpdatePositionAsync(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, IInvokeOption invokeOption = default) where TClient : + public static Task UpdatePositionAsync(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, System.Int64 time, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] parameters = new object[] { id, vector3, time }; @@ -235,7 +247,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static void NewNPC(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, IInvokeOption invokeOption = default) where TClient : + public static void NewNPC(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] @_parameters = new object[] { id, vector3 }; @@ -245,7 +257,7 @@ namespace UnityRpcProxy /// ///创建新的NPC /// - public static Task NewNPCAsync(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, IInvokeOption invokeOption = default) where TClient : + public static Task NewNPCAsync(this TClient client, System.Int32 id, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] parameters = new object[] { id, vector3 }; @@ -259,7 +271,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static void Offline(this TClient client, System.Int32 id, IInvokeOption invokeOption = default) where TClient : + public static void Offline(this TClient client, System.Int32 id, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] @_parameters = new object[] { id }; @@ -269,7 +281,7 @@ namespace UnityRpcProxy /// ///玩家离线 /// - public static Task OfflineAsync(this TClient client, System.Int32 id, IInvokeOption invokeOption = default) where TClient : + public static Task OfflineAsync(this TClient client, System.Int32 id, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] parameters = new object[] { id }; @@ -283,7 +295,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static void PlayerLogin(this TClient client, System.Int32 id, IInvokeOption invokeOption = default) where TClient : + public static void PlayerLogin(this TClient client, System.Int32 id, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] @_parameters = new object[] { id }; @@ -293,7 +305,7 @@ namespace UnityRpcProxy /// ///玩家登陆 /// - public static Task PlayerLoginAsync(this TClient client, System.Int32 id, IInvokeOption invokeOption = default) where TClient : + public static Task PlayerLoginAsync(this TClient client, System.Int32 id, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] parameters = new object[] { id }; diff --git a/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/UnityRpcProxy_Json_HttpDmtp_2D.cs b/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/UnityRpcProxy_Json_HttpDmtp_2D.cs index cbc263d15..33e27271e 100644 --- a/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/UnityRpcProxy_Json_HttpDmtp_2D.cs +++ b/examples/Unity3d/UnityServerConsoleApp_2D/RPCStore/UnityRpcProxy_Json_HttpDmtp_2D.cs @@ -1,96 +1,110 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + /* 此代码由Rpc工具直接生成,非必要请不要修改此处代码 */ #pragma warning disable using System; -using TouchSocket.Core; -using TouchSocket.Sockets; -using TouchSocket.Rpc; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Threading.Tasks; +using TouchSocket.Core; +using TouchSocket.Rpc; +using TouchSocket.Sockets; namespace UnityRpcProxy_Json_HttpDmtp_2D { -public interface IUnityRpcStore:TouchSocket.Rpc.IRemoteServer -{ -/// -///单位移动 -/// -/// 调用超时 -/// Rpc调用异常 -/// 其他异常 -void JsonRpc_UnitMovement(System.Numerics.Vector3 vector3,IInvokeOption invokeOption = default); -/// -///单位移动 -/// -/// 调用超时 -/// Rpc调用异常 -/// 其他异常 -Task JsonRpc_UnitMovementAsync(System.Numerics.Vector3 vector3,IInvokeOption invokeOption = default); + public interface IUnityRpcStore : TouchSocket.Rpc.IRemoteServer + { + /// + ///单位移动 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + void JsonRpc_UnitMovement(System.Numerics.Vector3 vector3, InvokeOption invokeOption = default); + /// + ///单位移动 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + Task JsonRpc_UnitMovementAsync(System.Numerics.Vector3 vector3, InvokeOption invokeOption = default); -} -public class UnityRpcStore :IUnityRpcStore -{ -public UnityRpcStore(IRpcClient client) -{ -this.Client=client; -} -public IRpcClient Client{get;private set; } -/// -///单位移动 -/// -/// 调用超时 -/// Rpc调用异常 -/// 其他异常 -public void JsonRpc_UnitMovement(System.Numerics.Vector3 vector3,IInvokeOption invokeOption = default) -{ -if(this.Client==null) -{ -throw new RpcException("IRpcClient为空,请先初始化或者进行赋值"); -} -object[] @_parameters = new object[]{vector3}; -this.Client.Invoke("JsonRpc_UnitMovement",null,invokeOption, @_parameters); + } + public class UnityRpcStore : IUnityRpcStore + { + public UnityRpcStore(IRpcClient client) + { + this.Client = client; + } + public IRpcClient Client { get; private set; } + /// + ///单位移动 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + public void JsonRpc_UnitMovement(System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) + { + if (this.Client == null) + { + throw new RpcException("IRpcClient为空,请先初始化或者进行赋值"); + } + object[] @_parameters = new object[] { vector3 }; + this.Client.Invoke("JsonRpc_UnitMovement", null, invokeOption, @_parameters); -} -/// -///单位移动 -/// -public Task JsonRpc_UnitMovementAsync(System.Numerics.Vector3 vector3,IInvokeOption invokeOption = default) -{ -if(this.Client==null) -{ -throw new RpcException("IRpcClient为空,请先初始化或者进行赋值"); -} -object[] parameters = new object[]{vector3}; -return this.Client.InvokeAsync("JsonRpc_UnitMovement",null,invokeOption, parameters); + } + /// + ///单位移动 + /// + public Task JsonRpc_UnitMovementAsync(System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) + { + if (this.Client == null) + { + throw new RpcException("IRpcClient为空,请先初始化或者进行赋值"); + } + object[] parameters = new object[] { vector3 }; + return this.Client.InvokeAsync("JsonRpc_UnitMovement", null, invokeOption, parameters); -} + } -} -public static class UnityRpcStoreExtensions -{ -/// -///单位移动 -/// -/// 调用超时 -/// Rpc调用异常 -/// 其他异常 -public static void JsonRpc_UnitMovement(this TClient client,System.Numerics.Vector3 vector3,IInvokeOption invokeOption = default) where TClient: -TouchSocket.JsonRpc.IJsonRpcClient{ -object[] @_parameters = new object[]{vector3}; -client.Invoke("JsonRpc_UnitMovement",null,invokeOption, @_parameters); + } + public static class UnityRpcStoreExtensions + { + /// + ///单位移动 + /// + /// 调用超时 + /// Rpc调用异常 + /// 其他异常 + public static void JsonRpc_UnitMovement(this TClient client, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) where TClient : + TouchSocket.JsonRpc.IJsonRpcClient + { + object[] @_parameters = new object[] { vector3 }; + client.Invoke("JsonRpc_UnitMovement", null, invokeOption, @_parameters); -} -/// -///单位移动 -/// -public static Task JsonRpc_UnitMovementAsync(this TClient client,System.Numerics.Vector3 vector3,IInvokeOption invokeOption = default) where TClient: -TouchSocket.JsonRpc.IJsonRpcClient{ -object[] parameters = new object[]{vector3}; -return client.InvokeAsync("JsonRpc_UnitMovement",null,invokeOption, parameters); + } + /// + ///单位移动 + /// + public static Task JsonRpc_UnitMovementAsync(this TClient client, System.Numerics.Vector3 vector3, InvokeOption invokeOption = default) where TClient : + TouchSocket.JsonRpc.IJsonRpcClient + { + object[] parameters = new object[] { vector3 }; + return client.InvokeAsync("JsonRpc_UnitMovement", null, invokeOption, parameters); -} + } -} + } } diff --git a/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/BaseTouchServer.cs b/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/BaseTouchServer.cs index 8d1f8ae7e..6863ab57d 100644 --- a/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/BaseTouchServer.cs +++ b/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/BaseTouchServer.cs @@ -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 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + namespace UnityServerConsoleApp_2D.TouchServer; /// diff --git a/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/Touch_JsonWebSocket_2D.cs b/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/Touch_JsonWebSocket_2D.cs index 060e39647..10f09c684 100644 --- a/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/Touch_JsonWebSocket_2D.cs +++ b/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/Touch_JsonWebSocket_2D.cs @@ -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.Numerics; using TouchSocket.Core; using TouchSocket.Dmtp; @@ -36,12 +48,20 @@ public class Touch_JsonWebSocket_2D : BaseTouchServer }) .ConfigurePlugins(a => { - a.UseWebSocket() - .SetWSUrl("/ws"); + //添加WebSocket功能 + a.UseWebSocket(options => + { + options.SetUrl("/ws");//设置url直接可以连接。 + options.SetAutoPong(true);//当收到ping报文时自动回应pong + }); //启用json rpc插件 - a.UseWebSocketJsonRpc() - .SetAllowJsonRpc((websocket, context) => true);//让所有请求WebSocket都加载JsonRpc插件 + a.UseWebSocketJsonRpc(options => + { + options.SetAllowJsonRpc((websocket, context) => true);//让所有请求WebSocket都加载JsonRpc插件 + }); + + a.Add(); @@ -58,7 +78,7 @@ public class Touch_JsonWebSocket_2D : BaseTouchServer /// /// 状态日志打印插件 /// -internal class Touch_JsonWebSocket_Log_Plguin : PluginBase, IWebSocketHandshakedPlugin, IWebSocketClosedPlugin +internal class Touch_JsonWebSocket_Log_Plguin : PluginBase, IWebSocketConnectedPlugin, IWebSocketClosedPlugin { private readonly ILog m_log; public Touch_JsonWebSocket_Log_Plguin(ILog Log) @@ -87,7 +107,7 @@ internal class Touch_JsonWebSocket_Log_Plguin : PluginBase, IWebSocketHandshaked await e.InvokeNext(); } - public async Task OnWebSocketHandshaked(IWebSocket webSocket, HttpContextEventArgs e) + public async Task OnWebSocketConnected(IWebSocket webSocket, HttpContextEventArgs e) { if (webSocket.Client is JsonHttpSessionClient client) diff --git a/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/UnityRpcStore.cs b/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/UnityRpcStore.cs index 77b1a67d4..9b19982e0 100644 --- a/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/UnityRpcStore.cs +++ b/examples/Unity3d/UnityServerConsoleApp_2D/TouchServer/UnityRpcStore.cs @@ -1,6 +1,17 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.ComponentModel; using System.Numerics; -using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.JsonRpc; using TouchSocket.Rpc; @@ -43,12 +54,12 @@ internal class UnityRpcStore : SingletonRpcServer //通知除开玩家的其他所有客户端 if (jsonsession != clientItem) { - await clientItem.GetJsonRpcActionClient().UpdatePositionAsync(jsonsession.ID, jsonsession.Postion, ToTimestamp(DateTime.Now)); + await clientItem.GetJsonRpcActionClient().UpdatePositionAsync(jsonsession.ID, jsonsession.Postion, ToTimestamp(DateTime.Now)); } } - m_logger.Info($"玩家{jsonsession.ID}移动到{vector3}"); + this.m_logger.Info($"玩家{jsonsession.ID}移动到{vector3}"); } } diff --git a/examples/Unity3d/UnityServerConsoleApp_2D/UnityServerConsoleApp_2D.csproj b/examples/Unity3d/UnityServerConsoleApp_2D/UnityServerConsoleApp_2D.csproj index 75aa9b331..ac08ba95a 100644 --- a/examples/Unity3d/UnityServerConsoleApp_2D/UnityServerConsoleApp_2D.csproj +++ b/examples/Unity3d/UnityServerConsoleApp_2D/UnityServerConsoleApp_2D.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,8 +7,8 @@ enable - - + + diff --git a/examples/Unity3d/UnityServerConsoleApp_All/Program.cs b/examples/Unity3d/UnityServerConsoleApp_All/Program.cs index bc9857225..80926126e 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/Program.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/Program.cs @@ -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 UnityServerConsoleApp_All.TouchServer; namespace UnityServerConsoleApp_All; diff --git a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_HttpDmtp.cs b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_HttpDmtp.cs index aa41683eb..bf6798a1b 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_HttpDmtp.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_HttpDmtp.cs @@ -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 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + /* 此代码由Rpc工具直接生成,非必要请不要修改此处代码 */ @@ -20,14 +32,14 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - System.Int32 RandomNumber(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default); + System.Int32 RandomNumber(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default); /// ///无注释信息 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task RandomNumberAsync(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default); + Task RandomNumberAsync(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default); } public class Touch_HttpDmtp_Client_UnityRpcStore : ITouch_HttpDmtp_Client_UnityRpcStore @@ -43,7 +55,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public System.Int32 RandomNumber(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) + public System.Int32 RandomNumber(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -57,7 +69,7 @@ namespace UnityRpcProxy /// ///无注释信息 /// - public async Task RandomNumberAsync(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) + public async Task RandomNumberAsync(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -77,7 +89,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static System.Int32 RandomNumber(this TClient client, System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) where TClient : + public static System.Int32 RandomNumber(this TClient client, System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) where TClient : TouchSocket.Dmtp.Rpc.IDmtpRpcActor { object[] @_parameters = new object[] { a, b }; @@ -88,7 +100,7 @@ namespace UnityRpcProxy /// ///无注释信息 /// - public static async Task RandomNumberAsync(this TClient client, System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) where TClient : + public static async Task RandomNumberAsync(this TClient client, System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) where TClient : TouchSocket.Dmtp.Rpc.IDmtpRpcActor { object[] parameters = new object[] { a, b }; diff --git a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_JsonRPCDmtp.cs b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_JsonRPCDmtp.cs index 5b121b1b8..c4b126f4f 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_JsonRPCDmtp.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Client_JsonRPCDmtp.cs @@ -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 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + /* 此代码由Rpc工具直接生成,非必要请不要修改此处代码 */ @@ -20,14 +32,14 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - System.Int32 Add(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default); + System.Int32 Add(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default); /// ///无注释信息 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 - Task AddAsync(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default); + Task AddAsync(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default); } public class ReverseJsonRpcServer : IReverseJsonRpcServer @@ -43,7 +55,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public System.Int32 Add(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) + public System.Int32 Add(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -57,7 +69,7 @@ namespace UnityRpcProxy /// ///无注释信息 /// - public async Task AddAsync(System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) + public async Task AddAsync(System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) { if (this.Client == null) { @@ -77,7 +89,7 @@ namespace UnityRpcProxy /// 调用超时 /// Rpc调用异常 /// 其他异常 - public static System.Int32 Add(this TClient client, System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) where TClient : + public static System.Int32 Add(this TClient client, System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] @_parameters = new object[] { a, b }; @@ -88,7 +100,7 @@ namespace UnityRpcProxy /// ///无注释信息 /// - public static async Task AddAsync(this TClient client, System.Int32 a, System.Int32 b, IInvokeOption invokeOption = default) where TClient : + public static async Task AddAsync(this TClient client, System.Int32 a, System.Int32 b, InvokeOption invokeOption = default) where TClient : TouchSocket.JsonRpc.IJsonRpcClient { object[] parameters = new object[] { a, b }; diff --git a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_HttpDmtp.cs b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_HttpDmtp.cs index 509434e37..b2c655624 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_HttpDmtp.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_HttpDmtp.cs @@ -20,14 +20,15 @@ public interface IUnityRpcStore:TouchSocket.Rpc.IRemoteServer /// 调用超时 /// Rpc调用异常 /// 其他异常 -LoginModelResult DmtpRpc_Login(LoginModel model,IInvokeOption invokeOption = default); +[AsyncToSyncWarning] +LoginModelResult DmtpRpc_Login(LoginModel model,InvokeOption invokeOption = default); /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 -Task DmtpRpc_LoginAsync(LoginModel model,IInvokeOption invokeOption = default); +Task DmtpRpc_LoginAsync(LoginModel model,InvokeOption invokeOption = default); /// ///性能测试 @@ -35,14 +36,15 @@ Task DmtpRpc_LoginAsync(LoginModel model,IInvokeOption invokeO /// 调用超时 /// Rpc调用异常 /// 其他异常 -System.Int32 DmtpRpc_Performance(System.Int32 i,IInvokeOption invokeOption = default); +[AsyncToSyncWarning] +System.Int32 DmtpRpc_Performance(System.Int32 i,InvokeOption invokeOption = default); /// ///性能测试 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 -Task DmtpRpc_PerformanceAsync(System.Int32 i,IInvokeOption invokeOption = default); +Task DmtpRpc_PerformanceAsync(System.Int32 i,InvokeOption invokeOption = default); } public class UnityRpcStore :IUnityRpcStore @@ -58,7 +60,8 @@ public IRpcClient Client{get;private set; } /// 调用超时 /// Rpc调用异常 /// 其他异常 -public LoginModelResult DmtpRpc_Login(LoginModel model,IInvokeOption invokeOption = default) +[AsyncToSyncWarning] +public LoginModelResult DmtpRpc_Login(LoginModel model,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -72,7 +75,7 @@ return returnData; /// ///登录 /// -public async Task DmtpRpc_LoginAsync(LoginModel model,IInvokeOption invokeOption = default) +public async Task DmtpRpc_LoginAsync(LoginModel model,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -89,7 +92,8 @@ return (LoginModelResult) await this.Client.InvokeAsync("DmtpRpc_Login",typeof(L /// 调用超时 /// Rpc调用异常 /// 其他异常 -public System.Int32 DmtpRpc_Performance(System.Int32 i,IInvokeOption invokeOption = default) +[AsyncToSyncWarning] +public System.Int32 DmtpRpc_Performance(System.Int32 i,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -103,7 +107,7 @@ return returnData; /// ///性能测试 /// -public async Task DmtpRpc_PerformanceAsync(System.Int32 i,IInvokeOption invokeOption = default) +public async Task DmtpRpc_PerformanceAsync(System.Int32 i,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -123,7 +127,8 @@ public static class UnityRpcStoreExtensions /// 调用超时 /// Rpc调用异常 /// 其他异常 -public static LoginModelResult DmtpRpc_Login(this TClient client,LoginModel model,IInvokeOption invokeOption = default) where TClient: +[AsyncToSyncWarning] +public static LoginModelResult DmtpRpc_Login(this TClient client,LoginModel model,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] @_parameters = new object[]{model}; LoginModelResult returnData=(LoginModelResult)client.Invoke("DmtpRpc_Login",typeof(LoginModelResult),invokeOption, @_parameters); @@ -133,7 +138,7 @@ return returnData; /// ///登录 /// -public static async Task DmtpRpc_LoginAsync(this TClient client,LoginModel model,IInvokeOption invokeOption = default) where TClient: +public static async Task DmtpRpc_LoginAsync(this TClient client,LoginModel model,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] parameters = new object[]{model}; return (LoginModelResult) await client.InvokeAsync("DmtpRpc_Login",typeof(LoginModelResult),invokeOption, parameters); @@ -146,7 +151,8 @@ return (LoginModelResult) await client.InvokeAsync("DmtpRpc_Login",typeof(LoginM /// 调用超时 /// Rpc调用异常 /// 其他异常 -public static System.Int32 DmtpRpc_Performance(this TClient client,System.Int32 i,IInvokeOption invokeOption = default) where TClient: +[AsyncToSyncWarning] +public static System.Int32 DmtpRpc_Performance(this TClient client,System.Int32 i,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] @_parameters = new object[]{i}; System.Int32 returnData=(System.Int32)client.Invoke("DmtpRpc_Performance",typeof(System.Int32),invokeOption, @_parameters); @@ -156,7 +162,7 @@ return returnData; /// ///性能测试 /// -public static async Task DmtpRpc_PerformanceAsync(this TClient client,System.Int32 i,IInvokeOption invokeOption = default) where TClient: +public static async Task DmtpRpc_PerformanceAsync(this TClient client,System.Int32 i,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] parameters = new object[]{i}; return (System.Int32) await client.InvokeAsync("DmtpRpc_Performance",typeof(System.Int32),invokeOption, parameters); @@ -164,6 +170,12 @@ return (System.Int32) await client.InvokeAsync("DmtpRpc_Performance",typeof(Syst } } +public class LoginModelResult +{ +public TouchSocket.Core.ResultCode ResultCode { get; set; } +public System.String Message { get; set; } +} + public class LoginModel { public System.String Token { get; set; } @@ -171,10 +183,4 @@ public System.String Account { get; set; } public System.String Password { get; set; } } -public class LoginModelResult -{ -public TouchSocket.Core.ResultCode ResultCode { get; set; } -public System.String Message { get; set; } -} - } diff --git a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Json_HttpDmtp.cs b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Json_HttpDmtp.cs index d1d961d35..9ba24d372 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Json_HttpDmtp.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_Json_HttpDmtp.cs @@ -20,14 +20,15 @@ public interface IUnityRpcStore:TouchSocket.Rpc.IRemoteServer /// 调用超时 /// Rpc调用异常 /// 其他异常 -LoginModelResult JsonRpc_Login(LoginModel model,IInvokeOption invokeOption = default); +[AsyncToSyncWarning] +LoginModelResult JsonRpc_Login(LoginModel model,InvokeOption invokeOption = default); /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 -Task JsonRpc_LoginAsync(LoginModel model,IInvokeOption invokeOption = default); +Task JsonRpc_LoginAsync(LoginModel model,InvokeOption invokeOption = default); /// ///性能测试 @@ -35,14 +36,15 @@ Task JsonRpc_LoginAsync(LoginModel model,IInvokeOption invokeO /// 调用超时 /// Rpc调用异常 /// 其他异常 -System.Int32 JsonRpc_Performance(System.Int32 i,IInvokeOption invokeOption = default); +[AsyncToSyncWarning] +System.Int32 JsonRpc_Performance(System.Int32 i,InvokeOption invokeOption = default); /// ///性能测试 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 -Task JsonRpc_PerformanceAsync(System.Int32 i,IInvokeOption invokeOption = default); +Task JsonRpc_PerformanceAsync(System.Int32 i,InvokeOption invokeOption = default); } public class UnityRpcStore :IUnityRpcStore @@ -58,7 +60,8 @@ public IRpcClient Client{get;private set; } /// 调用超时 /// Rpc调用异常 /// 其他异常 -public LoginModelResult JsonRpc_Login(LoginModel model,IInvokeOption invokeOption = default) +[AsyncToSyncWarning] +public LoginModelResult JsonRpc_Login(LoginModel model,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -72,7 +75,7 @@ return returnData; /// ///登录 /// -public async Task JsonRpc_LoginAsync(LoginModel model,IInvokeOption invokeOption = default) +public async Task JsonRpc_LoginAsync(LoginModel model,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -89,7 +92,8 @@ return (LoginModelResult) await this.Client.InvokeAsync("JsonRpc_Login",typeof(L /// 调用超时 /// Rpc调用异常 /// 其他异常 -public System.Int32 JsonRpc_Performance(System.Int32 i,IInvokeOption invokeOption = default) +[AsyncToSyncWarning] +public System.Int32 JsonRpc_Performance(System.Int32 i,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -103,7 +107,7 @@ return returnData; /// ///性能测试 /// -public async Task JsonRpc_PerformanceAsync(System.Int32 i,IInvokeOption invokeOption = default) +public async Task JsonRpc_PerformanceAsync(System.Int32 i,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -123,7 +127,8 @@ public static class UnityRpcStoreExtensions /// 调用超时 /// Rpc调用异常 /// 其他异常 -public static LoginModelResult JsonRpc_Login(this TClient client,LoginModel model,IInvokeOption invokeOption = default) where TClient: +[AsyncToSyncWarning] +public static LoginModelResult JsonRpc_Login(this TClient client,LoginModel model,InvokeOption invokeOption = default) where TClient: TouchSocket.JsonRpc.IJsonRpcClient{ object[] @_parameters = new object[]{model}; LoginModelResult returnData=(LoginModelResult)client.Invoke("JsonRpc_Login",typeof(LoginModelResult),invokeOption, @_parameters); @@ -133,7 +138,7 @@ return returnData; /// ///登录 /// -public static async Task JsonRpc_LoginAsync(this TClient client,LoginModel model,IInvokeOption invokeOption = default) where TClient: +public static async Task JsonRpc_LoginAsync(this TClient client,LoginModel model,InvokeOption invokeOption = default) where TClient: TouchSocket.JsonRpc.IJsonRpcClient{ object[] parameters = new object[]{model}; return (LoginModelResult) await client.InvokeAsync("JsonRpc_Login",typeof(LoginModelResult),invokeOption, parameters); @@ -146,7 +151,8 @@ return (LoginModelResult) await client.InvokeAsync("JsonRpc_Login",typeof(LoginM /// 调用超时 /// Rpc调用异常 /// 其他异常 -public static System.Int32 JsonRpc_Performance(this TClient client,System.Int32 i,IInvokeOption invokeOption = default) where TClient: +[AsyncToSyncWarning] +public static System.Int32 JsonRpc_Performance(this TClient client,System.Int32 i,InvokeOption invokeOption = default) where TClient: TouchSocket.JsonRpc.IJsonRpcClient{ object[] @_parameters = new object[]{i}; System.Int32 returnData=(System.Int32)client.Invoke("JsonRpc_Performance",typeof(System.Int32),invokeOption, @_parameters); @@ -156,7 +162,7 @@ return returnData; /// ///性能测试 /// -public static async Task JsonRpc_PerformanceAsync(this TClient client,System.Int32 i,IInvokeOption invokeOption = default) where TClient: +public static async Task JsonRpc_PerformanceAsync(this TClient client,System.Int32 i,InvokeOption invokeOption = default) where TClient: TouchSocket.JsonRpc.IJsonRpcClient{ object[] parameters = new object[]{i}; return (System.Int32) await client.InvokeAsync("JsonRpc_Performance",typeof(System.Int32),invokeOption, parameters); @@ -164,6 +170,12 @@ return (System.Int32) await client.InvokeAsync("JsonRpc_Performance",typeof(Syst } } +public class LoginModelResult +{ +public TouchSocket.Core.ResultCode ResultCode { get; set; } +public System.String Message { get; set; } +} + public class LoginModel { public System.String Token { get; set; } @@ -171,10 +183,4 @@ public System.String Account { get; set; } public System.String Password { get; set; } } -public class LoginModelResult -{ -public TouchSocket.Core.ResultCode ResultCode { get; set; } -public System.String Message { get; set; } -} - } diff --git a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_TcpDmtp.cs b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_TcpDmtp.cs index 7ae8fce8e..25e1855c4 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_TcpDmtp.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/RPCStore/UnityRpcProxy_TcpDmtp.cs @@ -20,14 +20,15 @@ public interface IUnityRpcStore:TouchSocket.Rpc.IRemoteServer /// 调用超时 /// Rpc调用异常 /// 其他异常 -LoginModelResult DmtpRpc_Login(LoginModel model,IInvokeOption invokeOption = default); +[AsyncToSyncWarning] +LoginModelResult DmtpRpc_Login(LoginModel model,InvokeOption invokeOption = default); /// ///登录 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 -Task DmtpRpc_LoginAsync(LoginModel model,IInvokeOption invokeOption = default); +Task DmtpRpc_LoginAsync(LoginModel model,InvokeOption invokeOption = default); /// ///性能测试 @@ -35,14 +36,15 @@ Task DmtpRpc_LoginAsync(LoginModel model,IInvokeOption invokeO /// 调用超时 /// Rpc调用异常 /// 其他异常 -System.Int32 DmtpRpc_Performance(System.Int32 i,IInvokeOption invokeOption = default); +[AsyncToSyncWarning] +System.Int32 DmtpRpc_Performance(System.Int32 i,InvokeOption invokeOption = default); /// ///性能测试 /// /// 调用超时 /// Rpc调用异常 /// 其他异常 -Task DmtpRpc_PerformanceAsync(System.Int32 i,IInvokeOption invokeOption = default); +Task DmtpRpc_PerformanceAsync(System.Int32 i,InvokeOption invokeOption = default); } public class UnityRpcStore :IUnityRpcStore @@ -58,7 +60,8 @@ public IRpcClient Client{get;private set; } /// 调用超时 /// Rpc调用异常 /// 其他异常 -public LoginModelResult DmtpRpc_Login(LoginModel model,IInvokeOption invokeOption = default) +[AsyncToSyncWarning] +public LoginModelResult DmtpRpc_Login(LoginModel model,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -72,7 +75,7 @@ return returnData; /// ///登录 /// -public async Task DmtpRpc_LoginAsync(LoginModel model,IInvokeOption invokeOption = default) +public async Task DmtpRpc_LoginAsync(LoginModel model,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -89,7 +92,8 @@ return (LoginModelResult) await this.Client.InvokeAsync("DmtpRpc_Login",typeof(L /// 调用超时 /// Rpc调用异常 /// 其他异常 -public System.Int32 DmtpRpc_Performance(System.Int32 i,IInvokeOption invokeOption = default) +[AsyncToSyncWarning] +public System.Int32 DmtpRpc_Performance(System.Int32 i,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -103,7 +107,7 @@ return returnData; /// ///性能测试 /// -public async Task DmtpRpc_PerformanceAsync(System.Int32 i,IInvokeOption invokeOption = default) +public async Task DmtpRpc_PerformanceAsync(System.Int32 i,InvokeOption invokeOption = default) { if(this.Client==null) { @@ -123,7 +127,8 @@ public static class UnityRpcStoreExtensions /// 调用超时 /// Rpc调用异常 /// 其他异常 -public static LoginModelResult DmtpRpc_Login(this TClient client,LoginModel model,IInvokeOption invokeOption = default) where TClient: +[AsyncToSyncWarning] +public static LoginModelResult DmtpRpc_Login(this TClient client,LoginModel model,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] @_parameters = new object[]{model}; LoginModelResult returnData=(LoginModelResult)client.Invoke("DmtpRpc_Login",typeof(LoginModelResult),invokeOption, @_parameters); @@ -133,7 +138,7 @@ return returnData; /// ///登录 /// -public static async Task DmtpRpc_LoginAsync(this TClient client,LoginModel model,IInvokeOption invokeOption = default) where TClient: +public static async Task DmtpRpc_LoginAsync(this TClient client,LoginModel model,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] parameters = new object[]{model}; return (LoginModelResult) await client.InvokeAsync("DmtpRpc_Login",typeof(LoginModelResult),invokeOption, parameters); @@ -146,7 +151,8 @@ return (LoginModelResult) await client.InvokeAsync("DmtpRpc_Login",typeof(LoginM /// 调用超时 /// Rpc调用异常 /// 其他异常 -public static System.Int32 DmtpRpc_Performance(this TClient client,System.Int32 i,IInvokeOption invokeOption = default) where TClient: +[AsyncToSyncWarning] +public static System.Int32 DmtpRpc_Performance(this TClient client,System.Int32 i,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] @_parameters = new object[]{i}; System.Int32 returnData=(System.Int32)client.Invoke("DmtpRpc_Performance",typeof(System.Int32),invokeOption, @_parameters); @@ -156,7 +162,7 @@ return returnData; /// ///性能测试 /// -public static async Task DmtpRpc_PerformanceAsync(this TClient client,System.Int32 i,IInvokeOption invokeOption = default) where TClient: +public static async Task DmtpRpc_PerformanceAsync(this TClient client,System.Int32 i,InvokeOption invokeOption = default) where TClient: TouchSocket.Dmtp.Rpc.IDmtpRpcActor{ object[] parameters = new object[]{i}; return (System.Int32) await client.InvokeAsync("DmtpRpc_Performance",typeof(System.Int32),invokeOption, parameters); @@ -164,6 +170,12 @@ return (System.Int32) await client.InvokeAsync("DmtpRpc_Performance",typeof(Syst } } +public class LoginModelResult +{ +public TouchSocket.Core.ResultCode ResultCode { get; set; } +public System.String Message { get; set; } +} + public class LoginModel { public System.String Token { get; set; } @@ -171,10 +183,4 @@ public System.String Account { get; set; } public System.String Password { get; set; } } -public class LoginModelResult -{ -public TouchSocket.Core.ResultCode ResultCode { get; set; } -public System.String Message { get; set; } -} - } diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/BaseTouchServer.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/BaseTouchServer.cs index db33fe1b7..66f88a1f0 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/BaseTouchServer.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/BaseTouchServer.cs @@ -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 +// 感谢您的下载和使用 +// ------------------------------------------------------------------------------ + namespace UnityServerConsoleApp_All.TouchServer; /// diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_HttpDmtp.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_HttpDmtp.cs index f786a175c..a434b6647 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_HttpDmtp.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_HttpDmtp.cs @@ -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; using TouchSocket.Dmtp; using TouchSocket.Dmtp.Rpc; @@ -40,9 +52,9 @@ public class Touch_HttpDmtp : BaseTouchServer a.Add(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp"//设置验证token + options.VerifyToken = "Dmtp";//设置验证token }); await this.dmtpService.SetupAsync(config); @@ -55,7 +67,7 @@ public class Touch_HttpDmtp : BaseTouchServer /// /// 状态日志打印插件 /// - internal class Touch_Dmtp_Log_Plguin : PluginBase, IDmtpHandshakedPlugin, IDmtpClosedPlugin, IDmtpCreatedChannelPlugin + internal class Touch_Dmtp_Log_Plguin : PluginBase, IDmtpConnectedPlugin, IDmtpClosedPlugin, IDmtpCreatedChannelPlugin { public async Task OnDmtpClosed(IDmtpActorObject client, ClosedEventArgs e) { @@ -76,26 +88,22 @@ public class Touch_HttpDmtp : BaseTouchServer using (channel) { client.DmtpActor.Logger.Info("通道开始接收"); - //此判断主要是探测是否有Hold操作 - while (channel.CanMoveNext) + long count = 0; + while (channel.CanRead) { - long count = 0; - foreach (var byteBlock in channel) - { - //这里处理数据 - count += byteBlock.Length; - client.DmtpActor.Logger.Info($"通道已接收:{count}字节"); - } - - client.DmtpActor.Logger.Info($"通道接收结束,状态={channel.Status},短语={channel.LastOperationMes},共接收{count / (1048576.0):0.00}Mb字节"); + using var cts = new CancellationTokenSource(10 * 1000); + var memory = await channel.ReadAsync(cts.Token); + //这里处理数据 + count += memory.Length; } + client.DmtpActor.Logger.Info($"通道接收结束,状态={channel.Status},短语={channel.LastOperationMes},共接收{count / (1048576.0):0.00}Mb字节"); } } await e.InvokeNext(); } - public async Task OnDmtpHandshaked(IDmtpActorObject client, DmtpVerifyEventArgs e) + public async Task OnDmtpConnected(IDmtpActorObject client, DmtpVerifyEventArgs e) { if (client is HttpDmtpSessionClient clientSession) { @@ -150,7 +158,7 @@ public class Touch_HttpDmtp : BaseTouchServer this.Logger.Info("客户端计算数据不对"); } } - catch (Exception e) + catch (Exception) { this.StopReverseRPC(); } diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_JsonWebSocket.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_JsonWebSocket.cs index 00ea240da..1ac2e1d24 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_JsonWebSocket.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_JsonWebSocket.cs @@ -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; using TouchSocket.Http; using TouchSocket.Http.WebSockets; @@ -35,12 +47,18 @@ public class Touch_JsonWebSocket : BaseTouchServer }) .ConfigurePlugins(a => { - a.UseWebSocket() - .SetWSUrl("/ws"); + //添加WebSocket功能 + a.UseWebSocket(options => + { + options.SetUrl("/ws");//设置url直接可以连接。 + options.SetAutoPong(true);//当收到ping报文时自动回应pong + }); //启用json rpc插件 - a.UseWebSocketJsonRpc() - .SetAllowJsonRpc((websocket, context) => true);//让所有请求WebSocket都加载JsonRpc插件 + a.UseWebSocketJsonRpc(options => + { + options.SetAllowJsonRpc((websocket, context) => true);//让所有请求WebSocket都加载JsonRpc插件 + }); a.Add(); @@ -57,7 +75,7 @@ public class Touch_JsonWebSocket : BaseTouchServer /// /// 状态日志打印插件 /// -internal class Touch_JsonWebSocket_Log_Plguin : PluginBase, IWebSocketHandshakedPlugin, IWebSocketClosedPlugin +internal class Touch_JsonWebSocket_Log_Plguin : PluginBase, IWebSocketConnectedPlugin, IWebSocketClosedPlugin //,IWebSocketReceivedPlugin { @@ -67,7 +85,7 @@ internal class Touch_JsonWebSocket_Log_Plguin : PluginBase, IWebSocketHandshaked await e.InvokeNext(); } - public async Task OnWebSocketHandshaked(IWebSocket webSocket, HttpContextEventArgs e) + public async Task OnWebSocketConnected(IWebSocket webSocket, HttpContextEventArgs e) { webSocket.Client.Logger.Info($"TCP_WebSocket:客户端{webSocket.Client.IP}已连接"); await e.InvokeNext(); diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TCP.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TCP.cs index 659beab97..f46a14a00 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TCP.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TCP.cs @@ -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,11 +60,11 @@ internal class Touch_TCP_Log_Plguin : PluginBase, ITcpConnectedPlugin, ITcpClose public async Task OnTcpReceived(ITcpSession client, ReceivedDataEventArgs e) { - client.Logger.Info($"TCP:接收到信息:{e.ByteBlock.Span.ToString(Encoding.UTF8)}"); + client.Logger.Info($"TCP:接收到信息:{e.Memory.Span.ToString(Encoding.UTF8)}"); if (client is ITcpSessionClient sessionClient) { - await sessionClient.SendAsync($"TCP:服务器已收到你发送的消息:{e.ByteBlock.ToString()}"); + await sessionClient.SendAsync($"TCP:服务器已收到你发送的消息:{e.Memory.Span.ToUtf8String()}"); } await e.InvokeNext(); } diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TcpDmtp.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TcpDmtp.cs index 5bc9aa8d8..afa702f7e 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TcpDmtp.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_TcpDmtp.cs @@ -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; using TouchSocket.Dmtp; using TouchSocket.Dmtp.Rpc; @@ -40,9 +52,9 @@ public class Touch_TcpDmtp : BaseTouchServer a.Add(); }) - .SetDmtpOption(new DmtpOption() + .SetDmtpOption(options => { - VerifyToken = "Dmtp"//设置验证token + options.VerifyToken = "Dmtp";//设置验证token }); await this.dmtpService.SetupAsync(config); @@ -55,7 +67,7 @@ public class Touch_TcpDmtp : BaseTouchServer /// /// 状态日志打印插件 /// - internal class Touch_Dmtp_Log_Plguin : PluginBase, IDmtpHandshakedPlugin, IDmtpClosedPlugin, IDmtpCreatedChannelPlugin + internal class Touch_Dmtp_Log_Plguin : PluginBase, IDmtpConnectedPlugin, IDmtpClosedPlugin, IDmtpCreatedChannelPlugin { public async Task OnDmtpClosed(IDmtpActorObject client, ClosedEventArgs e) { @@ -76,26 +88,23 @@ public class Touch_TcpDmtp : BaseTouchServer using (channel) { client.DmtpActor.Logger.Info("通道开始接收"); - //此判断主要是探测是否有Hold操作 - while (channel.CanMoveNext) + long count = 0; + while (channel.CanRead) { - long count = 0; - foreach (var byteBlock in channel) - { - //这里处理数据 - count += byteBlock.Length; - client.DmtpActor.Logger.Info($"通道已接收:{count}字节"); - } - - client.DmtpActor.Logger.Info($"通道接收结束,状态={channel.Status},短语={channel.LastOperationMes},共接收{count / (1048576.0):0.00}Mb字节"); + using var cts = new CancellationTokenSource(10 * 1000); + var memory = await channel.ReadAsync(cts.Token); + //这里处理数据 + count += memory.Length; } + + client.DmtpActor.Logger.Info($"通道接收结束,状态={channel.Status},短语={channel.LastOperationMes},共接收{count / (1048576.0):0.00}Mb字节"); } } await e.InvokeNext(); } - public async Task OnDmtpHandshaked(IDmtpActorObject client, DmtpVerifyEventArgs e) + public async Task OnDmtpConnected(IDmtpActorObject client, DmtpVerifyEventArgs e) { if (client is TcpDmtpSessionClient clientSession) { @@ -150,7 +159,7 @@ public class Touch_TcpDmtp : BaseTouchServer this.Logger.Info("客户端计算数据不对"); } } - catch (Exception e) + catch (Exception) { this.StopReverseRPC(); } diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_UDP.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_UDP.cs index 1cb36c728..7acfbf9de 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_UDP.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_UDP.cs @@ -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; @@ -15,8 +27,8 @@ public class Touch_UDP : BaseTouchServer { await this.udpService.SetupAsync(new TouchSocketConfig() .SetBindIPHost(new IPHost(port)) - .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter())//常规udp - //.SetUdpDataHandlingAdapter(() => new UdpPackageAdapter())//Udp包模式,支持超过64k数据。 + //常规udp + //.SetUdpDataHandlingAdapter(() => new UdpPackageAdapter())//Udp包模式,支持超过64k数据。 .ConfigurePlugins(a => { a.Add();//此处可以添加插件 @@ -36,10 +48,10 @@ public class Touch_UDP : BaseTouchServer { public async Task OnUdpReceived(IUdpSessionBase client, UdpReceivedDataEventArgs e) { - client.Logger.Info($"UDP:收到:{e.ByteBlock.Span.ToString(Encoding.UTF8)}"); + client.Logger.Info($"UDP:收到:{e.Memory.Span.ToString(Encoding.UTF8)}"); if (client is UdpSession session) { - await session.SendAsync(e.EndPoint, "UDP:" + e.EndPoint.ToString() + "收到了你的消息:" + e.ByteBlock.Span.ToString(Encoding.UTF8)); + await session.SendAsync(e.EndPoint, "UDP:" + e.EndPoint.ToString() + "收到了你的消息:" + e.Memory.Span.ToString(Encoding.UTF8)); } await e.InvokeNext(); } diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_WebSocket.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_WebSocket.cs index c21c0af0d..e33e54bdc 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_WebSocket.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/Touch_WebSocket.cs @@ -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; using TouchSocket.Dmtp; using TouchSocket.Http; @@ -23,8 +35,12 @@ public class Touch_WebSocket : BaseTouchServer }) .ConfigurePlugins(a => { - a.UseWebSocket() - .SetWSUrl("/ws"); + //添加WebSocket功能 + a.UseWebSocket(options => + { + options.SetUrl("/ws");//设置url直接可以连接。 + options.SetAutoPong(true);//当收到ping报文时自动回应pong + }); a.Add(); @@ -40,7 +56,7 @@ public class Touch_WebSocket : BaseTouchServer /// /// 状态日志打印插件 /// -internal class Touch_WebSocket_Log_Plguin : PluginBase, IWebSocketHandshakedPlugin, IWebSocketReceivedPlugin, IWebSocketClosedPlugin +internal class Touch_WebSocket_Log_Plguin : PluginBase, IWebSocketConnectedPlugin, IWebSocketReceivedPlugin, IWebSocketClosedPlugin { public async Task OnWebSocketClosed(IWebSocket webSocket, ClosedEventArgs e) @@ -49,7 +65,7 @@ internal class Touch_WebSocket_Log_Plguin : PluginBase, IWebSocketHandshakedPlug await e.InvokeNext(); } - public async Task OnWebSocketHandshaked(IWebSocket webSocket, HttpContextEventArgs e) + public async Task OnWebSocketConnected(IWebSocket webSocket, HttpContextEventArgs e) { webSocket.Client.Logger.Info($"TCP_WebSocket:客户端{webSocket.Client.IP}已连接"); await e.InvokeNext(); @@ -62,7 +78,7 @@ internal class Touch_WebSocket_Log_Plguin : PluginBase, IWebSocketHandshakedPlug switch (e.DataFrame.Opcode) { case WSDataType.Cont: - m_logger.Info($"TCP_WebSocket:收到中间数据,长度为:{e.DataFrame.PayloadLength}"); + m_logger.Info($"TCP_WebSocket:收到中间数据,长度为:{e.DataFrame.PayloadData.Length}"); return; @@ -78,11 +94,11 @@ internal class Touch_WebSocket_Log_Plguin : PluginBase, IWebSocketHandshakedPlug case WSDataType.Binary: if (e.DataFrame.FIN) { - m_logger.Info($"TCP_WebSocket:收到二进制数据,长度为:{e.DataFrame.PayloadLength}"); + m_logger.Info($"TCP_WebSocket:收到二进制数据,长度为:{e.DataFrame.PayloadData.Length}"); } else { - m_logger.Info($"TCP_WebSocket:收到未结束的二进制数据,长度为:{e.DataFrame.PayloadLength}"); + m_logger.Info($"TCP_WebSocket:收到未结束的二进制数据,长度为:{e.DataFrame.PayloadData.Length}"); } return; diff --git a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/UnityRpcStore.cs b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/UnityRpcStore.cs index d4d039849..3cef80a08 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/UnityRpcStore.cs +++ b/examples/Unity3d/UnityServerConsoleApp_All/TouchServer/UnityRpcStore.cs @@ -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.ComponentModel; using TouchSocket.Core; using TouchSocket.Dmtp.Rpc; diff --git a/examples/Unity3d/UnityServerConsoleApp_All/UnityServerConsoleApp_All.csproj b/examples/Unity3d/UnityServerConsoleApp_All/UnityServerConsoleApp_All.csproj index 75aa9b331..ac08ba95a 100644 --- a/examples/Unity3d/UnityServerConsoleApp_All/UnityServerConsoleApp_All.csproj +++ b/examples/Unity3d/UnityServerConsoleApp_All/UnityServerConsoleApp_All.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,8 +7,8 @@ enable - - + + diff --git a/examples/UpdateProjectReferences.ps1 b/examples/UpdateProjectReferences.ps1 new file mode 100644 index 000000000..75cb0d59d --- /dev/null +++ b/examples/UpdateProjectReferences.ps1 @@ -0,0 +1,23 @@ +# PowerShell script to update all project files to use centralized package management +# This script removes Version attributes from PackageReference elements + +$projectFiles = Get-ChildItem -Path "." -Recurse -Filter "*.csproj" + +foreach ($project in $projectFiles) { + Write-Host "Processing: $($project.FullName)" + + $content = Get-Content $project.FullName -Raw + + # Remove Version attributes from PackageReference elements + $updatedContent = $content -replace '()', '$1$3' + + # Only update the file if changes were made + if ($content -ne $updatedContent) { + Set-Content -Path $project.FullName -Value $updatedContent -NoNewline + Write-Host "Updated: $($project.Name)" -ForegroundColor Green + } else { + Write-Host "No changes needed: $($project.Name)" -ForegroundColor Yellow + } +} + +Write-Host "All project files have been processed!" -ForegroundColor Cyan \ No newline at end of file diff --git a/examples/Tcp/TcpWaitingClientWinFormsApp/Form1.Designer.cs b/examples/WaitingClient/TcpWaitingClientWinFormsApp/Form1.Designer.cs similarity index 100% rename from examples/Tcp/TcpWaitingClientWinFormsApp/Form1.Designer.cs rename to examples/WaitingClient/TcpWaitingClientWinFormsApp/Form1.Designer.cs diff --git a/examples/Tcp/TcpWaitingClientWinFormsApp/Form1.cs b/examples/WaitingClient/TcpWaitingClientWinFormsApp/Form1.cs similarity index 83% rename from examples/Tcp/TcpWaitingClientWinFormsApp/Form1.cs rename to examples/WaitingClient/TcpWaitingClientWinFormsApp/Form1.cs index 532509320..deaaa0219 100644 --- a/examples/Tcp/TcpWaitingClientWinFormsApp/Form1.cs +++ b/examples/WaitingClient/TcpWaitingClientWinFormsApp/Form1.cs @@ -11,7 +11,6 @@ //------------------------------------------------------------------------------ using System.Text; -using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.Sockets; @@ -19,19 +18,18 @@ namespace TcpWaitingClientWinFormsApp; public partial class Form1 : Form { + private CancellationTokenSource cts; + + private TcpClient m_tcpClient; + + private TcpService m_tcpService; + public Form1() { this.InitializeComponent(); this.Load += this.Form1_Load; } - private TcpService m_tcpService; - private async void Form1_Load(object? sender, EventArgs e) - { - this.m_tcpService = await CreateService(); - - this.UpdateServiceButtonUI(); - } private static async Task CreateService() { var service = new TcpService(); @@ -53,48 +51,9 @@ public partial class Form1 : Form return service; } - private TcpClient m_tcpClient; - - private async Task IsConnected() + private async void button1_Click(object sender, EventArgs e) { - try - { - if (this.m_tcpClient?.Online == true) - { - return; - } - this.m_tcpClient.SafeDispose(); - this.m_tcpClient = new TcpClient(); - - this.m_tcpClient.Received = async (client, e) => - { - //此处不能await,否则也会导致死锁 - _ = Task.Run(async () => - { - var waitingClient = client.CreateWaitingClient(new WaitingOptions()); - - var bytes = await waitingClient.SendThenReturnAsync("hello"); - }); - - await Task.CompletedTask; - }; - - await this.m_tcpClient.SetupAsync(new TouchSocketConfig() - .ConfigurePlugins(a => - { - a.Add(typeof(ITcpReceivedPlugin), (ReceivedDataEventArgs e) => - { - Console.WriteLine($"PluginReceivedData:{e.ByteBlock.Span.ToString(Encoding.UTF8)}"); - }); - }) - .SetRemoteIPHost(this.textBox1.Text)); - - await this.m_tcpClient.ConnectAsync(); - } - catch (Exception ex) - { - MessageBox.Show(ex.Message); - } + await this.m_tcpClient?.CloseAsync(); } private async void button2_Click(object sender, EventArgs e) @@ -105,11 +64,8 @@ public partial class Form1 : Form var waitingClient = this.m_tcpClient.CreateWaitingClient(new WaitingOptions()); this.cts = new CancellationTokenSource(5000); - var bytes = await waitingClient.SendThenReturnAsync(this.textBox2.Text.ToUtf8Bytes(), this.cts.Token); - if (bytes != null) - { - MessageBox.Show($"message:{Encoding.UTF8.GetString(bytes)}"); - } + using var responsedData = await waitingClient.SendThenResponseAsync(this.textBox2.Text.ToUtf8Bytes(), this.cts.Token); + MessageBox.Show($"message:{Encoding.UTF8.GetString(responsedData.Memory.Span)}"); } catch (Exception ex) { @@ -126,12 +82,12 @@ public partial class Form1 : Form { FilterFuncAsync = async (response) => { - var byteBlock = response.ByteBlock; + var memory = response.Memory; var requestInfo = response.RequestInfo; - if (byteBlock != null) + if (!memory.IsEmpty) { - var str = byteBlock.Span.ToString(Encoding.UTF8); + var str = memory.Span.ToString(Encoding.UTF8); if (str.Contains(this.textBox4.Text)) { return true; @@ -142,7 +98,7 @@ public partial class Form1 : Form //如果需要在插件中继续处理,在此处触发插件 - await this.m_tcpClient.PluginManager.RaiseAsync(typeof(ITcpReceivedPlugin), this.m_tcpClient, new ReceivedDataEventArgs(byteBlock, requestInfo)).ConfigureAwait(false); + await this.m_tcpClient.PluginManager.RaiseAsync(typeof(ITcpReceivedPlugin), this.m_tcpClient, new ReceivedDataEventArgs(memory, requestInfo)).ConfigureAwait(false); } } return false; @@ -150,12 +106,9 @@ public partial class Form1 : Form }); this.cts = new CancellationTokenSource(500000); - var bytes = await waitingClient.SendThenReturnAsync(this.textBox3.Text.ToUtf8Bytes(), this.cts.Token); + using var responsedData = await waitingClient.SendThenResponseAsync(this.textBox3.Text.ToUtf8Bytes(), this.cts.Token); - if (bytes != null) - { - MessageBox.Show($"message:{Encoding.UTF8.GetString(bytes)}"); - } + MessageBox.Show($"message:{Encoding.UTF8.GetString(responsedData.Memory.Span)}"); } catch (Exception ex) { @@ -163,17 +116,6 @@ public partial class Form1 : Form } } - private async void button1_Click(object sender, EventArgs e) - { - await this.m_tcpClient?.CloseAsync(); - } - - private CancellationTokenSource cts; - private void button5_Click(object sender, EventArgs e) - { - this.cts?.Cancel(); - } - private void button4_Click(object sender, EventArgs e) { this.m_tcpService?.Dispose(); @@ -181,6 +123,60 @@ public partial class Form1 : Form this.UpdateServiceButtonUI(); } + private void button5_Click(object sender, EventArgs e) + { + this.cts?.Cancel(); + } + + private async void Form1_Load(object? sender, EventArgs e) + { + this.m_tcpService = await CreateService(); + + this.UpdateServiceButtonUI(); + } + + private async Task IsConnected() + { + try + { + if (this.m_tcpClient?.Online == true) + { + return; + } + await this.m_tcpClient.CloseAsync(); + this.m_tcpClient = new TcpClient(); + + this.m_tcpClient.Received = async (client, e) => + { + //此处不能await,否则也会导致死锁 + _ = Task.Run(async () => + { + var waitingClient = client.CreateWaitingClient(new WaitingOptions()); + + using var bytes = await waitingClient.SendThenResponseAsync("hello"); + }); + + await Task.CompletedTask; + }; + + await this.m_tcpClient.SetupAsync(new TouchSocketConfig() + .ConfigurePlugins(a => + { + a.Add(typeof(ITcpReceivedPlugin), (ReceivedDataEventArgs e) => + { + Console.WriteLine($"PluginReceivedData:{e.Memory.Span.ToString(Encoding.UTF8)}"); + }); + }) + .SetRemoteIPHost(this.textBox1.Text)); + + await this.m_tcpClient.ConnectAsync(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + private void UpdateServiceButtonUI() { if (this.m_tcpService == null) @@ -205,11 +201,11 @@ internal class MyPlugin1 : PluginBase, ITcpReceivedPlugin public async Task OnTcpReceived(ITcpSession client, ReceivedDataEventArgs e) { - this.m_logger.Info($"Plugin:{e.ByteBlock.ToString()}"); + this.m_logger.Info($"Plugin:{e.Memory.Span.ToUtf8String()}"); if (client is ITcpSessionClient sessionClient) { - await sessionClient.SendAsync(e.ByteBlock.Memory); + await sessionClient.SendAsync(e.Memory); } } } \ No newline at end of file diff --git a/examples/Tcp/TcpWaitingClientWinFormsApp/Form1.resx b/examples/WaitingClient/TcpWaitingClientWinFormsApp/Form1.resx similarity index 100% rename from examples/Tcp/TcpWaitingClientWinFormsApp/Form1.resx rename to examples/WaitingClient/TcpWaitingClientWinFormsApp/Form1.resx diff --git a/examples/Tcp/TcpWaitingClientWinFormsApp/Program.cs b/examples/WaitingClient/TcpWaitingClientWinFormsApp/Program.cs similarity index 100% rename from examples/Tcp/TcpWaitingClientWinFormsApp/Program.cs rename to examples/WaitingClient/TcpWaitingClientWinFormsApp/Program.cs diff --git a/examples/WaitingClient/TcpWaitingClientWinFormsApp/TcpWaitingClientWinFormsApp.csproj b/examples/WaitingClient/TcpWaitingClientWinFormsApp/TcpWaitingClientWinFormsApp.csproj new file mode 100644 index 000000000..092f6a341 --- /dev/null +++ b/examples/WaitingClient/TcpWaitingClientWinFormsApp/TcpWaitingClientWinFormsApp.csproj @@ -0,0 +1,15 @@ + + + + Exe + net9.0-windows + enable + true + enable + + + + + + + \ No newline at end of file diff --git a/examples/WaitingClient/WaitingClientConsoleApp/Program.cs b/examples/WaitingClient/WaitingClientConsoleApp/Program.cs new file mode 100644 index 000000000..4c2ae9d62 --- /dev/null +++ b/examples/WaitingClient/WaitingClientConsoleApp/Program.cs @@ -0,0 +1,172 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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; + +namespace WaitingClientConsoleApp; + +internal class Program +{ + private static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + } + + + + private static async Task TcpService_WaitingClient() + { + #region Tcp服务器WaitingClient示例 + var service = new TcpService(); + await service.StartAsync(7789);//启动服务器 + + //在服务器中,找到指定Id的会话客户端 + if (service.TryGetClient("targetId", out var tcpSessionClient)) + { + //调用CreateWaitingClient获取到IWaitingClient的对象。 + var waitClient = tcpSessionClient.CreateWaitingClient(new WaitingOptions() + { + FilterFunc = response => //设置用于筛选的fun委托,当返回为true时,才会响应返回 + { + return true; + } + }); + + //发送数据,并等待响应 + using (var responsedData = await waitClient.SendThenResponseAsync(Encoding.UTF8.GetBytes("RRQM"))) + { + var memory = responsedData.Memory; + Console.WriteLine(memory.Span.ToString(Encoding.UTF8)); + + var requestInfo = responsedData.RequestInfo;//如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时 + } + } + #endregion + } + private static async Task TcpClient_WaitingClient() + { + #region Tcp客户端WaitingClient示例 + var client = new TcpClient(); + await client.ConnectAsync("tcp://127.0.0.1:7789"); + + //调用CreateWaitingClient获取到IWaitingClient的对象。 + + #region WaitingClient设置筛选函数 + var waitingClient = client.CreateWaitingClient(new WaitingOptions() + { + FilterFunc = response => //设置用于筛选的fun委托,当返回为true时,才会响应返回 + { + var requestInfo = response.RequestInfo; + var memory = response.Memory; + + //这里可以根据服务端返回的信息,判断是否响应 + return true; + } + }); + #endregion + + + + //发送数据,并等待响应 + using (var responsedData = await waitingClient.SendThenResponseAsync(Encoding.UTF8.GetBytes("RRQM"))) + { + var memory = responsedData.Memory; + Console.WriteLine(memory.Span.ToString(Encoding.UTF8)); + + var requestInfo = responsedData.RequestInfo;//如果适配器收到数据后,返回的并不是字节,而是IRequestInfo对象时 + } + #endregion + + #region WaitingClient默认超时示例 + using var responsed = await waitingClient.SendThenResponseAsync("hello");//默认5秒超时 + #endregion + + #region WaitingClient指定超时取消示例 + var cts = new CancellationTokenSource(); + + _ = Task.Run(async () => + { + await Task.Delay(5000); + cts.Cancel();//5秒后取消等待,不再等待服务端的消息。这里模拟的是客户端主动取消等待 + }); + using var responsed2 = await waitingClient.SendThenResponseAsync("hello", cts.Token); + #endregion + + } + + private static async Task WaitingClient_FilterFuncRetrigger() + { + var m_tcpClient = new TcpClient(); + await m_tcpClient.ConnectAsync("tcp://127.0.0.1:7789"); + + #region WaitingClient筛选函数重新触发插件 + var waitingClient = m_tcpClient.CreateWaitingClient(new WaitingOptions() + { + FilterFuncAsync = async (response) => + { + var byteBlock = response.Memory; + var requestInfo = response.RequestInfo; + + if (true)//如果满足某个条件,则响应WaitingClient + { + return true; + } + else + { + //否则 + //数据不符合要求,waitingClient继续等待 + //如果需要在插件中继续处理,在此处触发插件 + + await m_tcpClient.PluginManager.RaiseAsync(typeof(ITcpReceivedPlugin), m_tcpClient, new ReceivedDataEventArgs(byteBlock, requestInfo)); + + return false; + } + } + }); + #endregion + } + + private static void WaitingClient_WrongUsageInReceived() + { + #region WaitingClient错误使用时机示例 + var tcpClient = new TcpClient(); + + tcpClient.Received = async (client, e) => + { + var waitingClient = client.CreateWaitingClient(new WaitingOptions()); + + //这里将导致死锁 + await waitingClient.SendThenResponseAsync("hello"); + }; + #endregion + } + + private static void WaitingClient_CorrectUsageInReceived() + { + var m_tcpClient = new TcpClient(); + + #region WaitingClient正确使用时机示例 + m_tcpClient.Received = async (client, e) => + { + //此处不能await,否则也会导致死锁 + _ = Task.Run(async () => + { + var waitingClient = client.CreateWaitingClient(new WaitingOptions()); + + await waitingClient.SendThenResponseAsync("hello"); + }); + }; + #endregion + } +} diff --git a/examples/WaitingClient/WaitingClientConsoleApp/WaitingClientConsoleApp.csproj b/examples/WaitingClient/WaitingClientConsoleApp/WaitingClientConsoleApp.csproj new file mode 100644 index 000000000..e08d18664 --- /dev/null +++ b/examples/WaitingClient/WaitingClientConsoleApp/WaitingClientConsoleApp.csproj @@ -0,0 +1,13 @@ + + + + Exe + net9.0 + enable + enable + + + + + + diff --git a/examples/WebApi/AotWebApiConsoleApp/AotWebApiConsoleApp.csproj b/examples/WebApi/AotWebApiConsoleApp/AotWebApiConsoleApp.csproj index 6b9763acd..85f27cf1a 100644 --- a/examples/WebApi/AotWebApiConsoleApp/AotWebApiConsoleApp.csproj +++ b/examples/WebApi/AotWebApiConsoleApp/AotWebApiConsoleApp.csproj @@ -1,4 +1,4 @@ - + net9.0 @@ -10,10 +10,10 @@ - - - - + + + + diff --git a/examples/WebApi/AotWebApiConsoleApp/Program.cs b/examples/WebApi/AotWebApiConsoleApp/Program.cs index fa3923f55..1e5f94fd6 100644 --- a/examples/WebApi/AotWebApiConsoleApp/Program.cs +++ b/examples/WebApi/AotWebApiConsoleApp/Program.cs @@ -1,10 +1,21 @@ +// ------------------------------------------------------------------------------ +// 此代码版权(除特别声明或在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.Json.Serialization; using TouchSocket.Core; using TouchSocket.Http; using TouchSocket.Rpc; using TouchSocket.Sockets; using TouchSocket.WebApi; -using TouchSocket.WebApi.Swagger; namespace WebApiConsoleApp { @@ -14,7 +25,7 @@ namespace WebApiConsoleApp { var builder = Host.CreateApplicationBuilder(args); - builder.Services.ConfigureContainer(a => + builder.Services.ConfigureContainer(a => { a.AddRpcStore(store => { @@ -31,13 +42,15 @@ namespace WebApiConsoleApp { a.UseTcpSessionCheckClear(); - a.UseWebApi() - .ConfigureConverter(converter => + a.UseWebApi(options => { - converter.Clear(); - converter.AddSystemTextJsonSerializerFormatter(options => + options.ConfigureConverter(converter => { - options.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); + converter.Clear(); + converter.AddSystemTextJsonSerializerFormatter(options => + { + options.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default); + }); }); }); @@ -95,7 +108,7 @@ namespace WebApiConsoleApp [WebApi(Method = HttpMethodType.Post)] public MySum TestPost(MyClass myClass) { - m_logger.Info("TestPost"); + this.m_logger.Info("TestPost"); return new MySum() { A = myClass.A, B = myClass.B, Sum = myClass.A + myClass.B }; } diff --git a/examples/WebApi/DispatchProxyWebApiConsoleApp/DispatchProxyWebApiConsoleApp.csproj b/examples/WebApi/DispatchProxyWebApiConsoleApp/DispatchProxyWebApiConsoleApp.csproj index cf26d6c94..69accf85a 100644 --- a/examples/WebApi/DispatchProxyWebApiConsoleApp/DispatchProxyWebApiConsoleApp.csproj +++ b/examples/WebApi/DispatchProxyWebApiConsoleApp/DispatchProxyWebApiConsoleApp.csproj @@ -8,6 +8,6 @@ - + diff --git a/examples/WebApi/DispatchProxyWebApiConsoleApp/Program.cs b/examples/WebApi/DispatchProxyWebApiConsoleApp/Program.cs index 4caaf6c1f..cee80fca3 100644 --- a/examples/WebApi/DispatchProxyWebApiConsoleApp/Program.cs +++ b/examples/WebApi/DispatchProxyWebApiConsoleApp/Program.cs @@ -18,6 +18,7 @@ namespace DispatchProxyWebApiConsoleApp; internal class Program { + #region WebApi客户端DispatchProxy代理调用 /// /// 使用DispatchProxy生成调用代理 /// @@ -37,8 +38,10 @@ internal class Program Console.WriteLine(sum); } } + #endregion } +#region WebApi客户端DispatchProxy代理类实现 /// /// 新建一个类,继承WebApiDispatchProxy,亦或者RpcDispatchProxy基类。 /// 然后实现抽象方法,主要是能获取到调用的IRpcClient派生接口。 @@ -59,7 +62,7 @@ internal class MyWebApiDispatchProxy : WebApiDispatchProxy .SetRemoteIPHost("127.0.0.1:7789") .ConfigurePlugins(a => { - a.UseTcpReconnection(); + a.UseReconnection(); })); client.ConnectAsync(); Console.WriteLine("连接成功"); @@ -71,11 +74,14 @@ internal class MyWebApiDispatchProxy : WebApiDispatchProxy return this.m_client; } } +#endregion +#region WebApi客户端DispatchProxy代理接口定义 internal interface IApiServer { [Router("ApiServer/[action]ab")] [Router("ApiServer/[action]")] [WebApi(Method = HttpMethodType.Get)] int Sum(int a, int b); -} \ No newline at end of file +} +#endregion \ No newline at end of file diff --git a/examples/WebApi/WebApiClientApp/Program.cs b/examples/WebApi/WebApiClientApp/Program.cs index 67e060cb7..d17fe3502 100644 --- a/examples/WebApi/WebApiClientApp/Program.cs +++ b/examples/WebApi/WebApiClientApp/Program.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using TouchSocket.Core; using TouchSocket.Http; @@ -29,12 +30,12 @@ internal class Program await TestHttpClient(); //此处预设一个30秒超时的请求设定。 - var invokeOption_30s = new InvokeOption() + var invokeOption_30s = new InvokeOption(30 * 1000) { - FeedbackType = FeedbackType.WaitInvoke, - Timeout = 30 * 1000 + FeedbackType = FeedbackType.WaitInvoke }; + #region WebApi客户端GET调用 { var client = await CreateWebApiClient(); @@ -42,50 +43,166 @@ internal class Program request.Method = HttpMethodType.Get; request.Querys = new KeyValuePair[] { new KeyValuePair("a", "10"), new KeyValuePair("b", "20") }; - var sum1 =await client.InvokeTAsync("/ApiServer/Sum", invokeOption_30s, request); + var sum1 = await client.InvokeTAsync("/ApiServer/Sum", invokeOption_30s, request); Console.WriteLine($"Get调用成功,结果:{sum1}"); + } + #endregion + #region WebApi客户端POST调用 + { + var client = await CreateWebApiClient(); var requestForPost = new WebApiRequest(); requestForPost.Method = HttpMethodType.Post; requestForPost.Body = new MyClass() { A = 10, B = 20 }; - var sum2 =await client.InvokeTAsync("/ApiServer/TestPost", invokeOption_30s, requestForPost); + var sum2 = await client.InvokeTAsync("/ApiServer/TestPost", invokeOption_30s, requestForPost); Console.WriteLine($"Post调用成功,结果:{sum2}"); + } + #endregion - var sum3 = client.TestPost(new MyClass() { A = 10, B = 20 }, invokeOption_30s); + #region WebApi客户端使用代理调用 + { + var client = await CreateWebApiClient(); + + var sum3 = await client.TestPostAsync(new MyClass() { A = 10, B = 20 }, invokeOption_30s); Console.WriteLine($"代理调用成功,结果:{sum3}"); } + #endregion + #region WebApi客户端字符串模板调用 { var client = await CreateWebApiClientSlim(); - var sum1 =await client.InvokeTAsync("GET:/ApiServer/Sum?a={0}&b={1}", invokeOption_30s, 10, 20); + var sum1 = await client.InvokeTAsync("GET:/ApiServer/Sum?a={0}&b={1}", invokeOption_30s, 10, 20); Console.WriteLine($"Get调用成功,结果:{sum1}"); - var sum2 =await client.InvokeTAsync("POST:/ApiServer/TestPost", invokeOption_30s, new MyClass() { A = 10, B = 20 }); + var sum2 = await client.InvokeTAsync("POST:/ApiServer/TestPost", invokeOption_30s, new MyClass() { A = 10, B = 20 }); Console.WriteLine($"Post调用成功,结果:{sum2}"); - var sum3 = client.TestPost(new MyClass() { A = 10, B = 20 }, invokeOption_30s); + var sum3 = client.TestPostAsync(new MyClass() { A = 10, B = 20 }, invokeOption_30s); Console.WriteLine($"代理调用成功,结果:{sum3}"); } + #endregion Console.ReadKey(); } + #region WebApi客户端使用原生HttpClient + private static async Task UseNativeHttpClient() + { + using var httpClient = new HttpClient(); + var result = await httpClient.GetStringAsync("http://localhost:7789/apiserver/sum?a=10&b=20"); + Console.WriteLine(result); // 输出: 30 + } + #endregion + + #region WebApi客户端代码生成使用代理 + private static async Task UseGeneratedProxy() + { + var client = new WebApiClient(); + await client.SetupAsync(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789")); + await client.ConnectAsync(); + + // 直接使用生成的扩展方法 + var sum = await client.SumAsync(10, 20); + Console.WriteLine($"结果: {sum}"); + } + #endregion + + #region WebApi客户端使用插件 + private static async Task UsePluginExample() + { + var client = new WebApiClient(); + await client.SetupAsync(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789") + .ConfigurePlugins(a => + { + a.Add(); + })); + } + #endregion + + #region WebApi客户端异常处理 + private static async Task ExceptionHandlingExample() + { + try + { + var client = new WebApiClient(); + await client.SetupAsync(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789")); + await client.ConnectAsync(); + + var request = new WebApiRequest(); + request.Method = HttpMethodType.Get; + + var result = await client.InvokeTAsync("/apiserver/sum?a=10&b=20", null, request); + Console.WriteLine($"结果: {result}"); + } + catch (TimeoutException) + { + Console.WriteLine("请求超时"); + } + catch (Exception ex) + { + Console.WriteLine($"请求失败: {ex.Message}"); + } + } + #endregion + + #region WebApi客户端设置超时 + private static async Task SetTimeoutExample() + { + var client = new WebApiClient(); + await client.SetupAsync(new TouchSocketConfig() + .SetRemoteIPHost("127.0.0.1:7789")); + await client.ConnectAsync(); + + // 为单次调用设置超时 + var invokeOption = new InvokeOption(30 * 1000) + { + FeedbackType = FeedbackType.WaitInvoke + }; + + var request = new WebApiRequest(); + request.Method = HttpMethodType.Get; + var result = await client.InvokeTAsync("/apiserver/sum", invokeOption, request); + } + #endregion + + #region WebApi客户端使用CancellationToken + private static async Task UseCancellationTokenExample() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + + try + { + var httpClient = new HttpClient(); + var result = await httpClient.GetStringAsync("/apiserver/sum?a=10&b=20", cts.Token); + } + catch (OperationCanceledException) + { + Console.WriteLine("操作已取消"); + } + } + #endregion + private static async Task TestHttpClient() { - var client = new HttpClient(); + using var client = new HttpClient(); await client.ConnectAsync("127.0.0.1:7789"); Console.WriteLine("连接成功"); - var responseString = await client.GetStringAsync("/ApiServer/Sum?a=10&b=20"); + using var cts = new CancellationTokenSource(1000 * 10); + var responseString = await client.GetStringAsync("/ApiServer/Sum?a=10&b=20", cts.Token); return client; } + #region WebApi客户端创建WebApiClient private static async Task CreateWebApiClient() { - var client = new WebApiClient(); + using var client = new WebApiClient(); await client.SetupAsync(new TouchSocketConfig() .SetRemoteIPHost("127.0.0.1:7789") .ConfigurePlugins(a => @@ -96,10 +213,12 @@ internal class Program Console.WriteLine("连接成功"); return client; } + #endregion + #region WebApi客户端创建WebApiClientSlim private static async Task