文件归档

This commit is contained in:
若汝棋茗
2022-08-31 21:16:02 +08:00
parent 1010891652
commit 44320e7223
814 changed files with 0 additions and 145067 deletions

View File

@@ -1,41 +0,0 @@
> 💢 特别说明:如果 Issue 没有严格按照模板编写且未提供测试源码下载或 Git 测试仓库地址,则视为无效 `Issue`。
### 组件名及版本号
例如:
- [x] TCP-v8.2.2
- [ ] UDP-v8.2.2
- [ ] Http-v8.2.2
- [ ] WebSocket-v8.2.2
- [ ] TcpTouchRpc-v8.2.2
- [ ] UdpTouchRpc-v8.2.2
- [ ] HttpTouchRpc-v8.2.2
- [ ] WSTouchRpc-v8.2.2
---
### 描述你的问题
发生了什么?尽可能的描述每一步操作。
---
### 异常堆栈信息
异常堆栈是什么?
---
### 测试项目代码
> **⚠⚠ 必须提供完整可运行且包含错误的 `Git` 仓库 DEMODEMO 提供最简单的错误逻辑代码,否则不予处理。⚠⚠**
您的代码下载地址?
---
### 期待结果
期待的结果是?
---

341
.gitignore vendored
View File

@@ -1,341 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true
**/wwwroot/lib/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb

201
LICENSE
View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,218 +0,0 @@
<p></p>
<p></p>
<p align="center">
<img src="logo.png" width = "100" height = "100" alt="图片名称" align=center />
</p>
<div align="center">
[![NuGet(TouchSocket)](https://buildstats.info/nuget/TouchSocket)](https://www.nuget.org/packages/TouchSocket/)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![star](https://gitee.com/dotnetchina/TouchSocket/badge/star.svg?theme=gvp)](https://gitee.com/dotnetchina/TouchSocket/stargazers)
[![fork](https://gitee.com/dotnetchina/TouchSocket/badge/fork.svg?theme=gvp)](https://gitee.com/dotnetchina/TouchSocket/members)
<a href="https://jq.qq.com/?_wv=1027&k=gN7UL4fw">
<img src="https://img.shields.io/badge/QQ群-234762506-red" alt="QQ">
</a>
</div>
<div align="center">
雄关漫道真如铁,而今迈步从头越。从头越,苍山如海,残阳如血。
</div>
中文 | [English](README.en.md)
## 🎀描述
**_以下Nuget包均已在此仓使用Apache License 2.0开源协议开源。_**
| 名称|地址 |描述|
|---|---|---|
|[![NuGet version (TouchSocket)](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket)](https://www.nuget.org/packages/TouchSocket)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket)| TouchSocket这是一个轻量级的、支持插件的综合网络通信库。<br>基础通信功能包含Tcp、Udp、Ssl、Rpc、Http等。其中http<br>服务器支持WebSocket、静态网页、XmlRpc、WebApi、JsonRpc<br>等扩展插件。和自定义协议的TouchRpc支持Ssl加密、异步调用、<br>权限管理、错误状态返回、服务回调、分布式调用等。在空载函数<br>执行时10万次调用仅3.8秒在不返回状态时仅0.9秒。|
| [![NuGet version (TouchSocket.AspNetCore)](https://img.shields.io/nuget/v/TouchSocket.AspNetCore.svg?label=TouchSocket.AspNetCore)](https://www.nuget.org/packages/TouchSocket.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket) | TouchSocket.AspNetCore是适用于AspNetCore的专属版本。|
## 🎫企业版描述
**_以下Nuget包并未开源其源代码需要付费购买。_**
| 名称|地址 |描述|
|---|---|---|
|[![NuGet version (TouchSocketPro)](https://img.shields.io/nuget/v/TouchSocketPro.svg?label=TouchSocketPro)](https://www.nuget.org/packages/TouchSocketPro)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket)| TouchSocketPro是TouchSocket的增强企业版。其中<br>未开源的企业版功能,这需要密钥才能使用,可以先试<br>用。所以两者在**基础功能**没有区别,只是在扩展功能上<br>有一定差异性。具体差异请看[企业版相关](https://www.yuque.com/rrqm/touchsocket/80696720a95e415d94c87fa03642513d)|
| [![NuGet version (TouchSocket.AspNetCore)](https://img.shields.io/nuget/v/TouchSocket.AspNetCore.svg?label=TouchSocket.AspNetCore)](https://www.nuget.org/packages/TouchSocket.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket) | TouchSocket.AspNetCore是适用于AspNetCore的专属版本。|
## 🖥支持环境
- .NET Framework4.5及以上。
- .NET Core3.1及以上。
- .NET Standard2.0及以上。
## 🥪支持框架
- WPF
- Winform
- Blazor
- Xamarin
- Mono
- Unity在IL2cpp编译时需要导入源码或添加link.xml亦或者直接安装RRQMSocketFrameworkMono则直接加载dll即可
- 其他即所有C#系
### unity内link.xml设置(放置在Assets文件夹内)
[unity官方文档 托管代码剥离](https://docs.unity3d.com/cn/current/Manual/ManagedCodeStripping.html#LinkXML)
```
<linker>
<assembly fullname="RRQMCore" />
<assembly fullname="RRQMSocket" />
</linker>
```
## 🌴RRQMSocket特点速览
#### 传统IOCP和RRQMSocket
RRQMSocket的IOCP和传统也不一样就以微软官方示例为例使用MemoryBuffer开辟一块内存均分然后给每个会话分配一个区接收等收到数据后再**复制**源数据然后把复制的数据进行处理。而RRQMSocket是每次接收之前从内存池拿一个可用内存块然后**直接用于接收**,等收到数据以后,直接就把这个内存块抛出处理,这样就避免了**复制操作**,虽然只是细小的设计,但是在传输**1000w**次**64kb**的数据时,性能相差了**10倍**。
#### 数据处理适配器
相信大家都使用过其他的Socket产品那么RRQMSocket在设计时也是借鉴了其他产品的优秀设计理念数据处理适配器就是其中之一但和其他产品的设计不同的是RRQMSocket的适配器功能更加强大它不仅可以提前解析数据包还可以解析数据对象。例如可以使用固定包头对数据进行预处理从而解决**数据分包**、**粘包**的问题。也可以直接解析**HTTP**数据协议、WebSocket数据协议等。
#### 兼容性与适配
RRQMSocket提供多种框架模型能够完全兼容基于TCP、UDP协议的所有协议。例如TcpService与TcpClient其基础功能和Socket一模一样只是增强了框架的**坚固性**和**并发性**,将**连接**和**接收数据**通过事件的形式抛出,让使用者能够更加友好的使用。
## 🔗联系作者
- [CSDN博客主页](https://blog.csdn.net/qq_40374647)
- [哔哩哔哩视频](https://space.bilibili.com/94253567)
- [源代码仓库主页](https://gitee.com/RRQM_Home)
- 交流QQ群234762506
## 🌟说明文档
- [ 文档首页 ](https://www.yuque.com/rrqm/touchsocket/index)
## ✨简单示例
**_以下仅以最简方式创建示例更多详情请查看[说明文档](https://www.yuque.com/rrqm/touchsocket/index)。_**
**【TcpService】**
```
TcpService service = new TcpService();
service.Connecting += (client, e) => { };//有客户端正在连接
service.Connected += (client, e) => { };//有客户端连接
service.Disconnected += (client, e) => { };//有客户端断开连接
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = byteBlock.ToString();
Console.WriteLine($"已从{client.ID}接收到信息:{mes}");
client.Send(mes);//将收到的信息直接返回给发送方
//client.Send("id",mes);//将收到的信息返回给特定ID的客户端
var clients = service.GetClients();
foreach (var targetClient in clients)//将收到的信息返回给在线的所有客户端。
{
if (targetClient.ID != client.ID)
{
targetClient.Send(mes);
}
}
};
service.Setup(new RRQMConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(10000)
.SetThreadCount(100))
.Start();//启动
```
**【TcpClient】**
```
TcpClient tcpClient = new TcpClient();
tcpClient.Connected += (client, e) => { };//成功连接到服务器
tcpClient.Disconnected += (client, e) => { };//从服务器断开连接,当连接不成功时不会触发。
tcpClient.Received += (client, byteBlock, requestInfo) =>
{
//从服务器收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"接收到信息:{mes}");
};
//声明配置
RRQMConfig config = new RRQMConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin()
.SetBufferLength(1024 * 10);
//载入配置
tcpClient.Setup(config);
tcpClient.Connect();
tcpClient.Send("RRQM");
```
**【TcpClient 断线重连】**
```
tcpClient.UseReconnection(tryCount:5,printLog:true);
```
**【FixedHeaderPackageAdapter包模式】**
该适配器主要解决TCP粘分包问题数据格式采用简单而高效的“包头+数据体”的模式,其中包头支持:
- Byte模式1+n一次性最大接收255字节的数据。
- Ushort模式2+n一次最大接收65535字节。
- Int模式4+n一次最大接收2G数据。
以上数据头均采用RRQMBitConverter的默认端模式小端模式使用者可以根据需求切换默认端模式。
```
RRQMBitConverter.DefaultEndianType = EndianType.Little;
```
**【CustomFixedHeaderDataHandlingAdapter】**
用户自定义固定包头适配器主要帮助用户解决具有固定包头的数据帧信息。例如下列数据格式仅需要实现几个接口就能完成解析详细操作请参照API。
|1|1|1|**********|
**【CustomUnfixedHeaderDataHandlingAdapter】**
用户自定义不固定包头适配器主要帮助用户解决具有包头不固定的数据帧信息。例如最典型的HTTP数据包其数据头和数据体由“\r\n”隔开而数据头又因为请求者的请求信息的不同头部数据也不固定而数据体的长度也是由数据头的ContentLength的值显式指定的所以可以考虑使用CustomUnfixedHeaderDataHandlingAdapter解析也是仅通过简单的开发就能实现。
**【Ssl加密】**
在[RRQMBox](https://gitee.com/RRQM_Home/RRQMBox/tree/master/Ssl%E8%AF%81%E4%B9%A6%E7%9B%B8%E5%85%B3)中放置了一个自制Ssl证书密码为“RRQMSocket”以供测试。使用配置非常方便。
在服务器中只需设置配置SslOption属性和接收模式。
**服务器配置**
```
config.SetServerSslOption(new ServiceSslOption() { Certificate = new X509Certificate2("RRQMSocket.pfx", "RRQMSocket"), SslProtocols = SslProtocols.Tls12 });
```
**客户端配置**
```
config.SetClientSslOption(new ClientSslOption()
{
ClientCertificates = new X509CertificateCollection() { new X509Certificate2("RRQMSocket.pfx", "RRQMSocket") },
SslProtocols = SslProtocols.Tls12,
TargetHost = "127.0.0.1",
CertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; }
});
```
## 🧲应用场景模拟
[场景入口](https://www.yuque.com/rrqm/touchsocket/wrwx9k)
***
## 致谢
谢谢大家对RRQM的支持如果还有其他问题请加群QQ234762506讨论。
## 支持作者
[支持入口](https://www.yuque.com/rrqm/touchsocket/a5199820843b324f025633fdeee44394)

221
README.md
View File

@@ -1,221 +0,0 @@
<p></p>
<p></p>
<p align="center">
<img src="logo.png" width = "100" height = "100" alt="图片名称" align=center />
</p>
<div align="center">
[![NuGet(TouchSocket)](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket)](https://www.nuget.org/packages/TouchSocket/)
[![NuGet(TouchSocket)](https://img.shields.io/nuget/dt/TouchSocket.svg)](https://www.nuget.org/packages/TouchSocket/)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![star](https://gitee.com/dotnetchina/TouchSocket/badge/star.svg?theme=gvp)](https://gitee.com/dotnetchina/TouchSocket/stargazers)
[![fork](https://gitee.com/dotnetchina/TouchSocket/badge/fork.svg?theme=gvp)](https://gitee.com/dotnetchina/TouchSocket/members)
<a href="https://jq.qq.com/?_wv=1027&k=gN7UL4fw">
<img src="https://img.shields.io/badge/QQ群-234762506-red" alt="QQ">
</a>
[![NuGet(TouchSocket)](https://img.shields.io/github/stars/RRQM/TouchSocket?logo=github)](https://github.com/RRQM/TouchSocket)
</div>
<div align="center">
雄关漫道真如铁,而今迈步从头越。从头越,苍山如海,残阳如血。
</div>
中文 | [English](README.en.md)
## 🎀描述
【开源版】
| 名称|地址 |描述|
|---|---|---|
|[![NuGet version (TouchSocket)](https://img.shields.io/nuget/v/TouchSocket.svg?label=TouchSocket)](https://www.nuget.org/packages/TouchSocket)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket)| TouchSocket这是一个轻量级的、支持插件的综合网络通信库。<br>基础通信功能包含Tcp、Udp、Ssl、Rpc、Http等。其中http<br>服务器支持WebSocket、静态网页、XmlRpc、WebApi、JsonRpc<br>等扩展插件。和自定义协议的TouchRpc支持Ssl加密、异步调用、<br>权限管理、错误状态返回、服务回调、分布式调用等。在空载函数<br>执行时10万次调用仅3.8秒在不返回状态时仅0.9秒。|
| [![NuGet version (TouchSocket.AspNetCore)](https://img.shields.io/nuget/v/TouchSocket.AspNetCore.svg?label=TouchSocket.AspNetCore)](https://www.nuget.org/packages/TouchSocket.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket) | TouchSocket.AspNetCore是适用于AspNetCore的专属版本。|
【企业版】
| 名称|地址 |描述|
|---|---|---|
|[![NuGet version (TouchSocketPro)](https://img.shields.io/nuget/v/TouchSocketPro.svg?label=TouchSocketPro)](https://www.nuget.org/packages/TouchSocketPro)|[Gitee](https://gitee.com/dotnetchina/TouchSocketPro)<br>[Github](https://github.com/RRQM/TouchSocketPro)| TouchSocketPro是TouchSocket的企业版这在原有基础之上<br>还有一些企业版功能,详情请看[企业版相关](https://www.yuque.com/rrqm/touchsocket/80696720a95e415d94c87fa03642513d)|
| [![NuGet version (TouchSocketPro.AspNetCore)](https://img.shields.io/nuget/v/TouchSocketPro.AspNetCore.svg?label=TouchSocketPro.AspNetCore)](https://www.nuget.org/packages/TouchSocketPro.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocketPro)<br>[Github](https://github.com/RRQM/TouchSocketPro) | TouchSocketPro.AspNetCore是适用于AspNetCore的专属版本。|
## 🖥支持环境
- .NET Framework4.5及以上。
- .NET Core3.1及以上。
- .NET Standard2.0及以上。
## 🥪支持框架
- Console
- WPF
- Winform
- Blazor Server
- Xamarin
- MAUI
- Avalonia
- Mono
- Unity 3D
- 其他即所有C#系
## 🌴TouchSocket特点速览
#### 传统IOCP和TouchSocket的IOCP模式
TouchSocket的IOCP和传统也不一样就以微软官方示例为例他是使用MemoryBuffer开辟一块内存均分然后给每个会话分配一个区接收等收到数据后再**复制**接收的数据然后把复制的数据进行处理。而TouchSocket是每次接收之前从内存池拿一个可用内存块然后**直接用于接收**,等收到数据以后,直接就把这个内存块抛出处理,这样就避免了**复制操作**,虽然只是细小的设计,但是在传输**10w**次**64kb**的数据时,性能相差了**10倍**。
#### 数据处理适配器
相信大家都使用过其他的Socket产品那么TouchSocket在设计时也是借鉴了其他产品的优秀设计理念数据处理适配器就是其中之一但和其他产品的设计不同的是TouchSocket的适配器功能更加强大易用且灵活。它不仅可以提前解析数据包还可以解析数据对象可以随时替换然后立即生效。例如可以使用固定包头对数据进行预处理从而解决**数据分包**、**粘包**的问题。也可以直接解析**HTTP**数据协议、WebSocket数据协议等。
#### 兼容性与适配
TouchSocket提供多种框架模型能够完全兼容基于TCP、UDP协议的所有协议。例如TcpService与TcpClient其基础功能和Socket一模一样只是增强了框架的**坚固性**和**并发性**,将**连接**和**接收数据**通过事件的形式抛出,让使用者能够更加友好的使用。
## 🔗联系作者
- [CSDN博客主页](https://blog.csdn.net/qq_40374647)
- [哔哩哔哩视频](https://space.bilibili.com/94253567)
- [源代码仓库主页](https://gitee.com/RRQM_Home)
- 交流QQ群234762506
## 🌟说明文档
- [ 文档首页 ](https://www.yuque.com/rrqm/touchsocket/index)
## ✨简单示例
**_以下仅以最简方式创建示例更多详情请查看[说明文档](https://www.yuque.com/rrqm/touchsocket/index)。_**
**【TcpService】**
```
TcpService service = new TcpService();
service.Connecting += (client, e) => { };//有客户端正在连接
service.Connected += (client, e) => { };//有客户端连接
service.Disconnected += (client, e) => { };//有客户端断开连接
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = byteBlock.ToString();
Console.WriteLine($"已从{client.ID}接收到信息:{mes}");
client.Send(mes);//将收到的信息直接返回给发送方
//client.Send("id",mes);//将收到的信息返回给特定ID的客户端
var clients = service.GetClients();
foreach (var targetClient in clients)//将收到的信息返回给在线的所有客户端。
{
if (targetClient.ID != client.ID)
{
targetClient.Send(mes);
}
}
};
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(10000)
.SetThreadCount(100))
.Start();//启动
```
**【TcpClient】**
```
TcpClient tcpClient = new TcpClient();
tcpClient.Connected += (client, e) => { };//成功连接到服务器
tcpClient.Disconnected += (client, e) => { };//从服务器断开连接,当连接不成功时不会触发。
tcpClient.Received += (client, byteBlock, requestInfo) =>
{
//从服务器收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"接收到信息:{mes}");
};
//声明配置
TouchSocketConfig config = new TouchSocketConfig();
config.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin()
.SetBufferLength(1024 * 10);
//载入配置
tcpClient.Setup(config);
tcpClient.Connect();
tcpClient.Send("RRQM");
```
**【TcpClient 断线重连】**
在Config的插件配置中首先得启用插件然后使用重连插件即可。
```
.UsePlugin()
.ConfigurePlugins(a=>
{
a.UseReconnection(5, true, 1000);
});
```
**【FixedHeaderPackageAdapter包模式】**
该适配器主要解决TCP粘分包问题数据格式采用简单而高效的“包头+数据体”的模式,其中包头支持:
- Byte模式1+n一次性最大接收255字节的数据。
- Ushort模式2+n一次最大接收65535字节。
- Int模式4+n一次最大接收2G数据。
以上数据头均采用TouchSocketBitConverter的默认端模式小端模式使用者可以根据需求切换默认端模式。
```
TouchSocketBitConverter.DefaultEndianType = EndianType.Little;
```
**【CustomFixedHeaderDataHandlingAdapter】**
用户自定义固定包头适配器主要帮助用户解决具有固定包头的数据帧信息。例如下列数据格式仅需要实现几个接口就能完成解析详细操作请参照API。
|1|1|1|**********|
**【CustomUnfixedHeaderDataHandlingAdapter】**
用户自定义不固定包头适配器主要帮助用户解决具有包头不固定的数据帧信息。例如最典型的HTTP数据包其数据头和数据体由“\r\n”隔开而数据头又因为请求者的请求信息的不同头部数据也不固定而数据体的长度也是由数据头的ContentLength的值显式指定的所以可以考虑使用CustomUnfixedHeaderDataHandlingAdapter解析也是仅通过简单的开发就能实现。
**【Http服务器】**
```
var service = new HttpService();
service.AddPlugin<MyHttpPlug>();
service.AddPlugin<HttpStaticPagePlugin>().
AddFolder("../../../../../api");//添加静态页面
service.AddPlugin<WebSocketServerPlugin>().//添加WebSocket功能
SetWSUrl("/ws");
service.AddPlugin<MyWebSocketPlugin>();//添加WS事务触发。
service.AddPlugin<MyWSCommandLinePlugin>();//添加WS命令行事务。
var config = new RRQMConfig();
config.UsePlugin()
.SetReceiveType(ReceiveType.Auto)
.SetListenIPHosts(new IPHost[] { new IPHost(7789) });
service.Setup(config).Start();
Console.WriteLine("Http服务器已启动");
Console.WriteLine("浏览器访问http://127.0.0.1:7789/index.html");
Console.WriteLine("WS访问ws://127.0.0.1:7789");
```
## 🧲应用场景模拟
[场景入口](https://www.yuque.com/rrqm/touchsocket/wrwx9k)
***
## 致谢
谢谢大家对TouchSocket的支持如果还有其他问题请提交Issue或者加群QQ234762506讨论。
## 支持作者
[支持入口](https://www.yuque.com/rrqm/touchsocket/a5199820843b324f025633fdeee44394)

View File

@@ -1,36 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.32428.217
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{5F888345-EC9C-4AC3-B4D5-D9510A32C9DC}"
ProjectSection(SolutionItems) = preProject
doc\源码编译相关问题.txt = doc\源码编译相关问题.txt
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchSocket", "src\TouchSocket\TouchSocket.csproj", "{37BF3CB2-9003-465D-A936-7373301FDA5C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchSocket.AspNetCore", "src\TouchSocket.AspNetCore\TouchSocket.AspNetCore.csproj", "{6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{37BF3CB2-9003-465D-A936-7373301FDA5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{37BF3CB2-9003-465D-A936-7373301FDA5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37BF3CB2-9003-465D-A936-7373301FDA5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37BF3CB2-9003-465D-A936-7373301FDA5C}.Release|Any CPU.Build.0 = Release|Any CPU
{6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E00016F-41A4-40BC-AF9C-DA3B0FA4F81A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DB787235-A13A-4A3D-B5A8-5DFEB6511EEE}
EndGlobalSection
EndGlobal

View File

@@ -1,329 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.32428.217
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tcp简单示例", "Tcp简单示例", "{FB46E926-0EEC-488C-B950-A16D2E7F694B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Udp简单示例", "Udp简单示例", "{F4D798A3-8D65-4750-9552-B02BCE081508}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Adapter简单示例", "Adapter简单示例", "{F8C07F29-7233-4FD3-A3DC-45963071E20A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugin简单示例", "Plugin简单示例", "{397AE2E0-1FB6-4B71-A888-328FF7FA05B4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Consul简单示例", "Consul简单示例", "{B405B0AE-6ECD-4586-B3D6-9D875073DFAF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NATService简单示例", "NATService简单示例", "{825D21FC-245C-4B6B-B237-E4ADEB2C98DC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ssl证书相关", "Ssl证书相关", "{4D592C10-4AF8-435E-9DB2-A718AB9BF9C4}"
ProjectSection(SolutionItems) = preProject
examples\Ssl证书相关\证书生成.zip = examples\Ssl证书相关\证书生成.zip
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdapterConsoleApp", "examples\Adapter简单示例\AdapterConsoleApp\AdapterConsoleApp.csproj", "{65823091-FE7C-4B96-96AB-1D4D09B45DA2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TouchRpc集群", "TouchRpc集群", "{DC9E894F-E65F-443E-9F4E-6FEDB46F06DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinFormsApp", "examples\Consul集群示例\TouchRpc Consul集群\WinFormsApp\WinFormsApp.csproj", "{558B024C-981D-4288-99D2-5B6C0C30C427}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceConsoleApp", "examples\Consul集群示例\TouchRpc Consul集群\ServiceConsoleApp\ServiceConsoleApp.csproj", "{FF655439-DFFE-4BE4-AB76-BC84EE188C7F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tcp集群", "Tcp集群", "{82B05679-3A56-4E9A-BFA3-B68D29821B8A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsulConsoleApp", "examples\Consul集群示例\ConsulConsoleApp\ConsulConsoleApp.csproj", "{A9C4DF80-0A9F-4979-AB4B-201A5B573A61}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NATServiceConsoleApp", "examples\NAT简单示例\NATServiceConsoleApp\NATServiceConsoleApp.csproj", "{FF839E56-FD43-4CEF-9775-B440D6BA4099}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PluginConsoleApp", "examples\Plugin简单示例\PluginConsoleApp\PluginConsoleApp.csproj", "{A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceApp", "examples\Tcp简单示例\ServiceApp\ServiceApp.csproj", "{6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientApp", "examples\Tcp简单示例\ClientApp\ClientApp.csproj", "{0B7591F5-37C8-4570-ACEF-782CE3F12957}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UdpDemoApp", "examples\Udp简单示例\UdpDemoApp\UdpDemoApp.csproj", "{31026659-0E64-4344-A8E2-A3C5477E4A94}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JsonRpc简单示例", "JsonRpc简单示例", "{969A695E-BEB5-45B8-93D8-B31640FA495D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonRpcConsoleApp", "examples\JsonRpc简单示例\JsonRpcConsoleApp\JsonRpcConsoleApp.csproj", "{F9E0154E-2DFC-480F-9B3A-B30548C41DFD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Http简单示例", "Http简单示例", "{EFB33E23-9E98-4B85-99E4-865705D5ACD2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServiceConsoleApp", "examples\Http简单示例\ConsoleApp\ServiceConsoleApp.csproj", "{AF8A5195-E56B-41E6-85A2-83E501E69500}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApi简单示例", "WebApi简单示例", "{5836A018-B0F3-4D6F-8C45-FC1E9C85D51A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApiServerApp", "examples\WebApi简单示例\WebApiServer\WebApiServerApp.csproj", "{725CF25C-F3F0-4833-A501-8FD8F3596837}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApiClientApp", "examples\WebApi简单示例\WebApiClientApp\WebApiClientApp.csproj", "{BF73D290-6C07-4EC6-8546-447F15B543C7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XmlRpc简单示例", "XmlRpc简单示例", "{94F46729-90A8-415A-92E0-2D996D3210B4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XmlRpcServerApp", "examples\XmlRpc简单示例\XmlRpcServerApp\XmlRpcServerApp.csproj", "{54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XmlRpcClientApp", "examples\XmlRpc简单示例\XmlRpcClientApp\XmlRpcClientApp.csproj", "{F933280F-F5C2-4145-B857-A70B921D940A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus简单示例", "EventBus简单示例", "{5E9585EE-934F-41B4-9ECA-FB0C55A155EF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusServer", "examples\EventBus简单示例\EventBusServer\EventBusServer.csproj", "{A6358094-56E0-4DF3-BA95-319D676C0A04}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusClient", "examples\EventBus简单示例\EventBusClient\EventBusClient.csproj", "{30A64984-243D-4745-807E-B084BA51B968}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FileTransfer简单示例", "FileTransfer简单示例", "{24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TouchRpc简单示例", "TouchRpc简单示例", "{54A8216A-AA96-4293-9285-D2173E1D2E69}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchRpcServerApp", "examples\TouchRpc简单示例\TouchRpcServerApp\TouchRpcServerApp.csproj", "{613B3E85-59DE-4314-9A3A-EEE7C03E207F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchRpcClientApp", "examples\TouchRpc简单示例\TouchRpcClientApp\TouchRpcClientApp.csproj", "{D367F50D-0B27-4B46-9872-695DC6B021BF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "基于AspNetCore的WebSocket协议", "基于AspNetCore的WebSocket协议", "{5C17B127-95DD-480C-BDCC-7FDF5E645B0C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TouchRpcWebApplication", "examples\TouchRpc简单示例\基于AspNetCore的WebSocket协议\TouchRpcWebApplication\TouchRpcWebApplication.csproj", "{35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WSTouchRpcClientConsoleApp", "examples\TouchRpc简单示例\基于AspNetCore的WebSocket协议\WSTouchRpcClientConsoleApp\WSTouchRpcClientConsoleApp.csproj", "{5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProtocolServerConsoleApp", "examples\TouchRpc简单示例\ProtocolServerConsoleApp\ProtocolServerConsoleApp.csproj", "{571F2732-7E54-42A8-BEC6-B97B0A651059}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "控制台", "控制台", "{DB89FCB6-E4F9-4BD4-93F3-4E857741D749}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "examples\Tcp简单示例\ConsoleApp\ConsoleApp.csproj", "{71D8B6B2-09F3-4060-B073-A3F5D944C304}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSocket简单示例", "WebSocket简单示例", "{84D1227F-3419-4BCD-9331-8B61B2C19784}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSocketConsoleApp", "examples\WebSocket简单示例\WebSocketConsoleApp\WebSocketConsoleApp.csproj", "{5F9D5028-12C8-4819-9B8E-ACE017B63132}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WSFormClientApp", "examples\WebSocket简单示例\WSFormClientApp\WSFormClientApp.csproj", "{1B247610-9FAD-4434-BA15-B1DB1F71B7C5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileServiceGUI", "examples\FileTransfer简单示例\FileServiceGUI\FileServiceGUI.csproj", "{2017B959-1B58-453A-B65D-2F737E6B96DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileClientGUI", "examples\FileTransfer简单示例\FileClientGUI\FileClientGUI.csproj", "{8BFDA2E0-E7B6-4592-86B8-53426A8C0848}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BlogsDemos", "BlogsDemos", "{EB38E883-88AF-4E4C-9DCD-FAEBD8A20968}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HeartbeatConsoleApp", "examples\BlogsDemos\HeartbeatConsoleApp\HeartbeatConsoleApp.csproj", "{06B4A342-2E42-4F66-A0FE-CD6110DDF980}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LimitNumberOfConnectionsConsoleApp", "examples\BlogsDemos\LimitNumberOfConnectionsConsoleApp\LimitNumberOfConnectionsConsoleApp.csproj", "{8452EA31-F7BB-4897-8881-F3EE3F82049A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThrottlingConsoleApp", "examples\BlogsDemos\ThrottlingConsoleApp\ThrottlingConsoleApp.csproj", "{DD7848E5-3489-454E-BF37-49B6FE4C7F01}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrafficCounterConsoleApp", "examples\BlogsDemos\TrafficCounterConsoleApp\TrafficCounterConsoleApp.csproj", "{82A783ED-11AD-407D-990B-A6AE9D557290}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UDP屏幕捕捉器", "UDP屏幕捕捉器", "{8B9374B5-42D7-48C9-84C7-A560167F0D47}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenUdpSender", "examples\Udp简单示例\UDP屏幕捕捉器\ScreenUdpSender\ScreenUdpSender.csproj", "{791D316B-41D7-4B19-A25B-A58EBEA4E04A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenUdpReceiver", "examples\Udp简单示例\UDP屏幕捕捉器\ScreenUdpReceiver\ScreenUdpReceiver.csproj", "{EDAA9CD3-1474-4588-9E3B-E970CED20F0F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "反向Rpc示例", "反向Rpc示例", "{5777979E-5737-46EF-9B0E-9C18FA7004B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseRpcConsoleApp", "examples\TouchRpc简单示例\反向Rpc示例\ReverseRpcConsoleApp\ReverseRpcConsoleApp.csproj", "{D5738DF3-C8E8-4E21-98B2-0557F0392167}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "控制台", "控制台", "{FB0FA0CF-1657-48F7-B852-FBA818F1AE8A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileServiceConsoleApp", "examples\FileTransfer简单示例\FileClientApp\FileServiceConsoleApp\FileServiceConsoleApp.csproj", "{8C6EA0F4-78F6-4E5F-B633-848355B06331}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileClientConsoleApp", "examples\FileTransfer简单示例\FileClientConsoleApp\FileClientConsoleApp.csproj", "{EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65823091-FE7C-4B96-96AB-1D4D09B45DA2}.Release|Any CPU.Build.0 = Release|Any CPU
{558B024C-981D-4288-99D2-5B6C0C30C427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{558B024C-981D-4288-99D2-5B6C0C30C427}.Debug|Any CPU.Build.0 = Debug|Any CPU
{558B024C-981D-4288-99D2-5B6C0C30C427}.Release|Any CPU.ActiveCfg = Release|Any CPU
{558B024C-981D-4288-99D2-5B6C0C30C427}.Release|Any CPU.Build.0 = Release|Any CPU
{FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF655439-DFFE-4BE4-AB76-BC84EE188C7F}.Release|Any CPU.Build.0 = Release|Any CPU
{A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9C4DF80-0A9F-4979-AB4B-201A5B573A61}.Release|Any CPU.Build.0 = Release|Any CPU
{FF839E56-FD43-4CEF-9775-B440D6BA4099}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF839E56-FD43-4CEF-9775-B440D6BA4099}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF839E56-FD43-4CEF-9775-B440D6BA4099}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF839E56-FD43-4CEF-9775-B440D6BA4099}.Release|Any CPU.Build.0 = Release|Any CPU
{A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B}.Release|Any CPU.Build.0 = Release|Any CPU
{6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6BEF15C2-29A2-4E57-8879-1B4AD0B4935E}.Release|Any CPU.Build.0 = Release|Any CPU
{0B7591F5-37C8-4570-ACEF-782CE3F12957}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B7591F5-37C8-4570-ACEF-782CE3F12957}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B7591F5-37C8-4570-ACEF-782CE3F12957}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B7591F5-37C8-4570-ACEF-782CE3F12957}.Release|Any CPU.Build.0 = Release|Any CPU
{31026659-0E64-4344-A8E2-A3C5477E4A94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31026659-0E64-4344-A8E2-A3C5477E4A94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31026659-0E64-4344-A8E2-A3C5477E4A94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31026659-0E64-4344-A8E2-A3C5477E4A94}.Release|Any CPU.Build.0 = Release|Any CPU
{F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9E0154E-2DFC-480F-9B3A-B30548C41DFD}.Release|Any CPU.Build.0 = Release|Any CPU
{AF8A5195-E56B-41E6-85A2-83E501E69500}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF8A5195-E56B-41E6-85A2-83E501E69500}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF8A5195-E56B-41E6-85A2-83E501E69500}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF8A5195-E56B-41E6-85A2-83E501E69500}.Release|Any CPU.Build.0 = Release|Any CPU
{725CF25C-F3F0-4833-A501-8FD8F3596837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{725CF25C-F3F0-4833-A501-8FD8F3596837}.Debug|Any CPU.Build.0 = Debug|Any CPU
{725CF25C-F3F0-4833-A501-8FD8F3596837}.Release|Any CPU.ActiveCfg = Release|Any CPU
{725CF25C-F3F0-4833-A501-8FD8F3596837}.Release|Any CPU.Build.0 = Release|Any CPU
{BF73D290-6C07-4EC6-8546-447F15B543C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BF73D290-6C07-4EC6-8546-447F15B543C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BF73D290-6C07-4EC6-8546-447F15B543C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BF73D290-6C07-4EC6-8546-447F15B543C7}.Release|Any CPU.Build.0 = Release|Any CPU
{54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5}.Release|Any CPU.Build.0 = Release|Any CPU
{F933280F-F5C2-4145-B857-A70B921D940A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F933280F-F5C2-4145-B857-A70B921D940A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F933280F-F5C2-4145-B857-A70B921D940A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F933280F-F5C2-4145-B857-A70B921D940A}.Release|Any CPU.Build.0 = Release|Any CPU
{A6358094-56E0-4DF3-BA95-319D676C0A04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A6358094-56E0-4DF3-BA95-319D676C0A04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6358094-56E0-4DF3-BA95-319D676C0A04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6358094-56E0-4DF3-BA95-319D676C0A04}.Release|Any CPU.Build.0 = Release|Any CPU
{30A64984-243D-4745-807E-B084BA51B968}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30A64984-243D-4745-807E-B084BA51B968}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30A64984-243D-4745-807E-B084BA51B968}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30A64984-243D-4745-807E-B084BA51B968}.Release|Any CPU.Build.0 = Release|Any CPU
{613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{613B3E85-59DE-4314-9A3A-EEE7C03E207F}.Release|Any CPU.Build.0 = Release|Any CPU
{D367F50D-0B27-4B46-9872-695DC6B021BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D367F50D-0B27-4B46-9872-695DC6B021BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D367F50D-0B27-4B46-9872-695DC6B021BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D367F50D-0B27-4B46-9872-695DC6B021BF}.Release|Any CPU.Build.0 = Release|Any CPU
{35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35C3CCAE-2C39-4756-82CD-1E2AFE1FB527}.Release|Any CPU.Build.0 = Release|Any CPU
{5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FF19798-AD4B-4B45-BD0C-DE5271BEF63A}.Release|Any CPU.Build.0 = Release|Any CPU
{571F2732-7E54-42A8-BEC6-B97B0A651059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{571F2732-7E54-42A8-BEC6-B97B0A651059}.Debug|Any CPU.Build.0 = Debug|Any CPU
{571F2732-7E54-42A8-BEC6-B97B0A651059}.Release|Any CPU.ActiveCfg = Release|Any CPU
{571F2732-7E54-42A8-BEC6-B97B0A651059}.Release|Any CPU.Build.0 = Release|Any CPU
{71D8B6B2-09F3-4060-B073-A3F5D944C304}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71D8B6B2-09F3-4060-B073-A3F5D944C304}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71D8B6B2-09F3-4060-B073-A3F5D944C304}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71D8B6B2-09F3-4060-B073-A3F5D944C304}.Release|Any CPU.Build.0 = Release|Any CPU
{5F9D5028-12C8-4819-9B8E-ACE017B63132}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F9D5028-12C8-4819-9B8E-ACE017B63132}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F9D5028-12C8-4819-9B8E-ACE017B63132}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F9D5028-12C8-4819-9B8E-ACE017B63132}.Release|Any CPU.Build.0 = Release|Any CPU
{1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B247610-9FAD-4434-BA15-B1DB1F71B7C5}.Release|Any CPU.Build.0 = Release|Any CPU
{2017B959-1B58-453A-B65D-2F737E6B96DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2017B959-1B58-453A-B65D-2F737E6B96DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2017B959-1B58-453A-B65D-2F737E6B96DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2017B959-1B58-453A-B65D-2F737E6B96DC}.Release|Any CPU.Build.0 = Release|Any CPU
{8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8BFDA2E0-E7B6-4592-86B8-53426A8C0848}.Release|Any CPU.Build.0 = Release|Any CPU
{06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06B4A342-2E42-4F66-A0FE-CD6110DDF980}.Release|Any CPU.Build.0 = Release|Any CPU
{8452EA31-F7BB-4897-8881-F3EE3F82049A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8452EA31-F7BB-4897-8881-F3EE3F82049A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8452EA31-F7BB-4897-8881-F3EE3F82049A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8452EA31-F7BB-4897-8881-F3EE3F82049A}.Release|Any CPU.Build.0 = Release|Any CPU
{DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD7848E5-3489-454E-BF37-49B6FE4C7F01}.Release|Any CPU.Build.0 = Release|Any CPU
{82A783ED-11AD-407D-990B-A6AE9D557290}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{82A783ED-11AD-407D-990B-A6AE9D557290}.Debug|Any CPU.Build.0 = Debug|Any CPU
{82A783ED-11AD-407D-990B-A6AE9D557290}.Release|Any CPU.ActiveCfg = Release|Any CPU
{82A783ED-11AD-407D-990B-A6AE9D557290}.Release|Any CPU.Build.0 = Release|Any CPU
{791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{791D316B-41D7-4B19-A25B-A58EBEA4E04A}.Release|Any CPU.Build.0 = Release|Any CPU
{EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDAA9CD3-1474-4588-9E3B-E970CED20F0F}.Release|Any CPU.Build.0 = Release|Any CPU
{D5738DF3-C8E8-4E21-98B2-0557F0392167}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5738DF3-C8E8-4E21-98B2-0557F0392167}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5738DF3-C8E8-4E21-98B2-0557F0392167}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5738DF3-C8E8-4E21-98B2-0557F0392167}.Release|Any CPU.Build.0 = Release|Any CPU
{8C6EA0F4-78F6-4E5F-B633-848355B06331}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C6EA0F4-78F6-4E5F-B633-848355B06331}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C6EA0F4-78F6-4E5F-B633-848355B06331}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C6EA0F4-78F6-4E5F-B633-848355B06331}.Release|Any CPU.Build.0 = Release|Any CPU
{EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{65823091-FE7C-4B96-96AB-1D4D09B45DA2} = {F8C07F29-7233-4FD3-A3DC-45963071E20A}
{DC9E894F-E65F-443E-9F4E-6FEDB46F06DC} = {B405B0AE-6ECD-4586-B3D6-9D875073DFAF}
{558B024C-981D-4288-99D2-5B6C0C30C427} = {DC9E894F-E65F-443E-9F4E-6FEDB46F06DC}
{FF655439-DFFE-4BE4-AB76-BC84EE188C7F} = {DC9E894F-E65F-443E-9F4E-6FEDB46F06DC}
{82B05679-3A56-4E9A-BFA3-B68D29821B8A} = {B405B0AE-6ECD-4586-B3D6-9D875073DFAF}
{A9C4DF80-0A9F-4979-AB4B-201A5B573A61} = {82B05679-3A56-4E9A-BFA3-B68D29821B8A}
{FF839E56-FD43-4CEF-9775-B440D6BA4099} = {825D21FC-245C-4B6B-B237-E4ADEB2C98DC}
{A3FAE253-EF1C-4B77-BBCA-A2E85F22E48B} = {397AE2E0-1FB6-4B71-A888-328FF7FA05B4}
{6BEF15C2-29A2-4E57-8879-1B4AD0B4935E} = {FB46E926-0EEC-488C-B950-A16D2E7F694B}
{0B7591F5-37C8-4570-ACEF-782CE3F12957} = {FB46E926-0EEC-488C-B950-A16D2E7F694B}
{31026659-0E64-4344-A8E2-A3C5477E4A94} = {F4D798A3-8D65-4750-9552-B02BCE081508}
{F9E0154E-2DFC-480F-9B3A-B30548C41DFD} = {969A695E-BEB5-45B8-93D8-B31640FA495D}
{AF8A5195-E56B-41E6-85A2-83E501E69500} = {EFB33E23-9E98-4B85-99E4-865705D5ACD2}
{725CF25C-F3F0-4833-A501-8FD8F3596837} = {5836A018-B0F3-4D6F-8C45-FC1E9C85D51A}
{BF73D290-6C07-4EC6-8546-447F15B543C7} = {5836A018-B0F3-4D6F-8C45-FC1E9C85D51A}
{54AA84C4-3986-4E0C-9F3B-2D17C00C8CD5} = {94F46729-90A8-415A-92E0-2D996D3210B4}
{F933280F-F5C2-4145-B857-A70B921D940A} = {94F46729-90A8-415A-92E0-2D996D3210B4}
{A6358094-56E0-4DF3-BA95-319D676C0A04} = {5E9585EE-934F-41B4-9ECA-FB0C55A155EF}
{30A64984-243D-4745-807E-B084BA51B968} = {5E9585EE-934F-41B4-9ECA-FB0C55A155EF}
{613B3E85-59DE-4314-9A3A-EEE7C03E207F} = {54A8216A-AA96-4293-9285-D2173E1D2E69}
{D367F50D-0B27-4B46-9872-695DC6B021BF} = {54A8216A-AA96-4293-9285-D2173E1D2E69}
{5C17B127-95DD-480C-BDCC-7FDF5E645B0C} = {54A8216A-AA96-4293-9285-D2173E1D2E69}
{35C3CCAE-2C39-4756-82CD-1E2AFE1FB527} = {5C17B127-95DD-480C-BDCC-7FDF5E645B0C}
{5FF19798-AD4B-4B45-BD0C-DE5271BEF63A} = {5C17B127-95DD-480C-BDCC-7FDF5E645B0C}
{571F2732-7E54-42A8-BEC6-B97B0A651059} = {54A8216A-AA96-4293-9285-D2173E1D2E69}
{DB89FCB6-E4F9-4BD4-93F3-4E857741D749} = {FB46E926-0EEC-488C-B950-A16D2E7F694B}
{71D8B6B2-09F3-4060-B073-A3F5D944C304} = {DB89FCB6-E4F9-4BD4-93F3-4E857741D749}
{5F9D5028-12C8-4819-9B8E-ACE017B63132} = {84D1227F-3419-4BCD-9331-8B61B2C19784}
{1B247610-9FAD-4434-BA15-B1DB1F71B7C5} = {84D1227F-3419-4BCD-9331-8B61B2C19784}
{2017B959-1B58-453A-B65D-2F737E6B96DC} = {24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4}
{8BFDA2E0-E7B6-4592-86B8-53426A8C0848} = {24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4}
{06B4A342-2E42-4F66-A0FE-CD6110DDF980} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968}
{8452EA31-F7BB-4897-8881-F3EE3F82049A} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968}
{DD7848E5-3489-454E-BF37-49B6FE4C7F01} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968}
{82A783ED-11AD-407D-990B-A6AE9D557290} = {EB38E883-88AF-4E4C-9DCD-FAEBD8A20968}
{8B9374B5-42D7-48C9-84C7-A560167F0D47} = {F4D798A3-8D65-4750-9552-B02BCE081508}
{791D316B-41D7-4B19-A25B-A58EBEA4E04A} = {8B9374B5-42D7-48C9-84C7-A560167F0D47}
{EDAA9CD3-1474-4588-9E3B-E970CED20F0F} = {8B9374B5-42D7-48C9-84C7-A560167F0D47}
{5777979E-5737-46EF-9B0E-9C18FA7004B6} = {54A8216A-AA96-4293-9285-D2173E1D2E69}
{D5738DF3-C8E8-4E21-98B2-0557F0392167} = {5777979E-5737-46EF-9B0E-9C18FA7004B6}
{FB0FA0CF-1657-48F7-B852-FBA818F1AE8A} = {24212B0A-8DAA-4AC3-BB5D-F3AC485EABA4}
{8C6EA0F4-78F6-4E5F-B633-848355B06331} = {FB0FA0CF-1657-48F7-B852-FBA818F1AE8A}
{EDEB1260-9D17-439C-A5E3-A31E1B1FE1F4} = {FB0FA0CF-1657-48F7-B852-FBA818F1AE8A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DB787235-A13A-4A3D-B5A8-5DFEB6511EEE}
EndGlobalSection
EndGlobal

View File

@@ -1 +0,0 @@
https://www.yuque.com/rrqm/touchsocket/mf3zif <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>

View File

@@ -1,16 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
<ItemGroup>
<None Update="SGCC测试数据.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -1,50 +0,0 @@
using System;
using TouchSocket.Sockets;
namespace AdapterConsoleApp
{
/// <summary>
/// 模板解析“大数据固定包头”数据适配器
/// </summary>
internal class MyBigFixedHeaderCustomDataHandlingAdapter : CustomBigFixedHeaderDataHandlingAdapter<MyBigFixedHeaderRequestInfo>
{
public override int HeaderLength => throw new NotImplementedException();
public override bool CanSendRequestInfo => false;
protected override MyBigFixedHeaderRequestInfo GetInstance()
{
return new MyBigFixedHeaderRequestInfo();
}
protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
{
throw new NotImplementedException();
}
}
/// <summary>
/// 下列吗,没有实现逻辑,仅解释思路。
/// </summary>
internal class MyBigFixedHeaderRequestInfo : IBigFixedHeaderRequestInfo
{
public long BodyLength => throw new NotImplementedException();
public void OnAppendBody(byte[] buffer, int offset, int length)
{
//在这里会一直追加数据体,用户自行实现数据的保存。
}
public bool OnFinished()
{
//触发该方法时说明数据体接收完毕返回true时会触发Receive相关事件否则不会。
return true;
}
public bool OnParsingHeader(byte[] header)
{
//解析头部
return true;
}
}
}

View File

@@ -1,53 +0,0 @@
using System.Text;
using TouchSocket.Sockets;
namespace AdapterConsoleApp
{
internal class MyCustomBetweenAndDataHandlingAdapter : CustomBetweenAndDataHandlingAdapter<MyBetweenAndRequestInfo>
{
public MyCustomBetweenAndDataHandlingAdapter()
{
this.MinSize = 5;//表示实际数据体不会小于5例如“**12##12##”数据解析后会解析成“12##12”
}
public override byte[] StartCode => Encoding.UTF8.GetBytes("**");//可以为0长度字节意味着没有起始标识。
public override byte[] EndCode => Encoding.UTF8.GetBytes("##");//必须为有效值。
public override bool CanSendRequestInfo => false;
protected override MyBetweenAndRequestInfo GetInstance()
{
return new MyBetweenAndRequestInfo();
}
protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
{
throw new System.NotImplementedException();
}
}
/// <summary>
/// 以**12##12##Min=5为例。
/// </summary>
internal class MyBetweenAndRequestInfo : IBetweenAndRequestInfo
{
public byte[] Body { get; private set; }
public void OnParsingBody(byte[] body)
{
this.Body = body;
//这里的Body应该为12##12
}
public bool OnParsingEndCode(byte[] endCode)
{
return true;//该返回值决定是否执行Receive
}
public bool OnParsingStartCode(byte[] startCode)
{
return true;
}
}
}

View File

@@ -1,89 +0,0 @@
using TouchSocket.Core.ByteManager;
using TouchSocket.Sockets;
namespace AdapterConsoleApp
{
/// <summary>
/// 用户自定义适配器
/// </summary>
internal class MyCustomDataHandlingAdapter : CustomDataHandlingAdapter<MyRequestInfo>
{
public override bool CanSendRequestInfo => false;
/// <summary>
/// 筛选解析数据。实例化的TRequest会一直保存直至解析成功或手动清除。
/// <para>当不满足解析条件时,请返回<see cref="FilterResult.Cache"/>,此时会保存<see cref="ByteBlock.CanReadLen"/>的数据</para>
/// <para>当数据部分异常时,请移动<see cref="ByteBlock.Pos"/>到指定位置,然后返回<see cref="FilterResult.GoOn"/></para>
/// <para>当完全满足解析条件时,请返回<see cref="FilterResult.Success"/>最后将<see cref="ByteBlock.Pos"/>移至指定位置。</para>
/// </summary>
/// <param name="byteBlock">字节块</param>
/// <param name="beCached">是否为上次遗留对象当该参数为True时request也将是上次实例化的对象。</param>
/// <param name="request">对象。</param>
/// <returns></returns>
protected override FilterResult Filter(ByteBlock byteBlock, bool beCached, ref MyRequestInfo request, ref int tempCapacity)
{
//以下解析思路为一次性解析,不考虑缓存的临时对象。
if (byteBlock.CanReadLen < 3)
{
return FilterResult.Cache;//当头部都无法解析时,直接缓存
}
int pos = byteBlock.Pos;//记录初始游标位置,防止本次无法解析时,回退游标。
MyRequestInfo myRequestInfo = new MyRequestInfo();
byteBlock.Read(out byte[] header, 3);//填充header
//因为第一个字节表示所有长度而DataType、OrderType已经包含在了header里面。
//所有只需呀再读取header[0]-2个长度即可。
byte bodyLength = (byte)(header[0] - 2);
if (bodyLength > byteBlock.CanReadLen)
{
//body数据不足。
byteBlock.Pos = pos;//回退游标
return FilterResult.Cache;
}
else
{
byteBlock.Read(out byte[] body, bodyLength);//填充body
myRequestInfo.Header = header;
myRequestInfo.DataType = header[1];
myRequestInfo.OrderType = header[2];
myRequestInfo.Body = body;
request = myRequestInfo;//赋值ref
return FilterResult.Success;//返回成功
}
}
protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
{
throw new System.NotImplementedException();
}
}
internal class MyRequestInfo : IRequestInfo
{
/// <summary>
/// 自定义属性,Body
/// </summary>
public byte[] Body { get; internal set; }
/// <summary>
/// 自定义属性,Header
/// </summary>
public byte[] Header { get; internal set; }
/// <summary>
/// 自定义属性,DataType
/// </summary>
public byte DataType { get; internal set; }
/// <summary>
/// 自定义属性,OrderType
/// </summary>
public byte OrderType { get; internal set; }
}
}

View File

@@ -1,98 +0,0 @@
using TouchSocket.Sockets;
namespace AdapterConsoleApp
{
/// <summary>
/// 模板解析“固定包头”数据适配器
/// </summary>
public class MyFixedHeaderCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyFixedHeaderRequestInfo>
{
public MyFixedHeaderCustomDataHandlingAdapter()
{
this.MaxPackageSize = 1024;
}
/// <summary>
/// 接口实现,指示固定包头长度
/// </summary>
public override int HeaderLength => 3;
public override bool CanSendRequestInfo => false;
/// <summary>
/// 获取新实例
/// </summary>
/// <returns></returns>
protected override MyFixedHeaderRequestInfo GetInstance()
{
return new MyFixedHeaderRequestInfo();
}
protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
{
throw new System.NotImplementedException();
}
}
public class MyFixedHeaderRequestInfo : IFixedHeaderRequestInfo
{
private int bodyLength;
/// <summary>
/// 接口实现,标识数据长度
/// </summary>
public int BodyLength
{
get { return bodyLength; }
}
private byte dataType;
/// <summary>
/// 自定义属性,标识数据类型
/// </summary>
public byte DataType
{
get { return dataType; }
}
private byte orderType;
/// <summary>
/// 自定义属性,标识指令类型
/// </summary>
public byte OrderType
{
get { return orderType; }
}
private byte[] body;
/// <summary>
/// 自定义属性,标识实际数据
/// </summary>
public byte[] Body
{
get { return body; }
}
public bool OnParsingBody(byte[] body)
{
if (body.Length == this.bodyLength)
{
this.body = body;
return true;
}
return false;
}
public bool OnParsingHeader(byte[] header)
{
//在该示例中第一个字节表示后续的所有数据长度但是header设置的是3所以后续还应当接收length-2个长度。
this.bodyLength = header[0] - 2;
this.dataType = header[1];
this.orderType = header[2];
return true;
}
}
}

View File

@@ -1,103 +0,0 @@
using System;
using System.IO;
using System.Text;
using TouchSocket.Core.ByteManager;
using TouchSocket.Core.Config;
using TouchSocket.Core.Extensions;
using TouchSocket.Core.IO;
using TouchSocket.Sockets;
namespace AdapterConsoleApp
{
internal class Program
{
/// <summary>
/// Tcp内置适配器介绍请看说明文档<see href="https://www.yuque.com/eo2w71/rrqm/dd2d6d011491561c2c0d6f9b904aad98"/>
/// </summary>
/// <param name="args"></param>
private static void Main(string[] args)
{
// 1.黏、分包问题使用内置适配器即可解决。
//● 正常数据处理适配器(NormalDataHandlingAdapter)
//● 固定包头数据处理适配器(FixedHeaderPackageAdapter)
//● 固定长度数据处理适配器(FixedSizePackageAdapter)
//● 终止因子分割数据处理适配器(TerminatorPackageAdapter)
ConsoleAction consoleAction = new ConsoleAction();
consoleAction.OnException += ConsoleAction_OnException;
consoleAction.Add("0", "启动服务器测试适配器", StartTcpService);
consoleAction.Add("1", "原始适配器实现demo", TestRawDataHandlingAdapter);
consoleAction.Add("2", "SGCC适配器实现demo", TestSGCCCustomDataHandlingAdapter);
consoleAction.ShowAll();
while (true)
{
if (!consoleAction.Run(Console.ReadLine()))
{
Console.WriteLine("指令不正确。");
}
}
}
private static void StartTcpService()
{
TcpService service = new TcpService();
service.Connected += (client, e) => { };//有客户端连接
service.Disconnected += (client, e) => { };//有客户端断开连接
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
if (requestInfo is MyBetweenAndRequestInfo info)
{
Console.WriteLine(Encoding.UTF8.GetString(info.Body));
}
};
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(10000)
.SetDataHandlingAdapter(()=> { return new MyCustomBetweenAndDataHandlingAdapter(); })
.SetThreadCount(10))
.Start();//启动
}
private static void ConsoleAction_OnException(Exception obj)
{
Console.WriteLine(obj.Message);
}
private static void TestRawDataHandlingAdapter()
{
for (int i = 0; i < 10; i++)
{
DataAdapterTester tester = DataAdapterTester.CreateTester(new RawDataHandlingAdapter(), new Random().Next(1, 1024));//用BufferLength模拟粘包分包
using ByteBlock block = new ByteBlock();
block.Write((byte)1);//写入数据类型 这里并未写入数据长度,因为这个适配器在发送前会再封装一次。
block.Write((byte)1);//写入数据指令
byte[] buffer = new byte[100];
new Random().NextBytes(buffer);
block.Write(buffer);//写入数据
byte[] data = block.ToArray();
// 输出测试时间,用于衡量适配性能.
// 测试100次限时2秒完成
Console.WriteLine(tester.Run(data, 100, 100, 1000 * 2).ToString());
}
}
private static void TestSGCCCustomDataHandlingAdapter()
{
string[] lines = File.ReadAllLines("SGCC测试数据.txt");
foreach (var item in lines)
{
DataAdapterTester tester = DataAdapterTester.CreateTester(new SGCCCustomDataHandlingAdapter(), new Random().Next(1, 1024));//用BufferLength模拟粘包分包
using ByteBlock block = new ByteBlock();
byte[] data = item.ByHexStringToBytes(" ");
// 输出测试时间,用于衡量适配性能.
// 测试100次限时2秒完成
Console.WriteLine(tester.Run(data, 100, 100, 1000 * 2).ToString());
}
}
}
}

View File

@@ -1,161 +0,0 @@
using System;
using System.Collections.Generic;
using TouchSocket.Core.ByteManager;
using TouchSocket.Sockets;
namespace AdapterConsoleApp
{
/// <summary>
/// 从原始适配器实现<see href=""="https://www.yuque.com/eo2w71/rrqm/77bcd9c825e08ab9bd0ba5908bc3e515#sGiqF"/>
/// </summary>
internal class RawDataHandlingAdapter : DataHandlingAdapter
{
/// <summary>
/// 包剩余长度
/// </summary>
private byte m_surPlusLength;
/// <summary>
/// 临时包,此包仅当前实例储存
/// </summary>
private ByteBlock m_tempByteBlock;
/// <summary>
/// 是否支持拼接发送为false的话可以不实现<see cref="PreviewSend(IList{TransferByte}, bool)"/>
/// </summary>
public override bool CanSplicingSend => false;
public override bool CanSendRequestInfo => false;
/// <summary>
/// 设计原则:接收时,尽量不抛出异常。
/// </summary>
/// <param name="byteBlock"></param>
protected override void PreviewReceived(ByteBlock byteBlock)
{
byte[] buffer = byteBlock.Buffer;
int r = byteBlock.Len;
if (this.m_tempByteBlock == null)//如果没有临时包,则直接分包。
{
SplitPackage(buffer, 0, r);
}
else
{
if (m_surPlusLength == r)//接收长度正好等于剩余长度,组合完数据以后直接处理数据。
{
this.m_tempByteBlock.Write(buffer, 0, m_surPlusLength);
PreviewHandle(this.m_tempByteBlock);
this.m_tempByteBlock = null;
m_surPlusLength = 0;
}
else if (m_surPlusLength < r)//接收长度大于剩余长度,先组合包,然后处理包,然后将剩下的分包。
{
this.m_tempByteBlock.Write(buffer, 0, m_surPlusLength);
PreviewHandle(this.m_tempByteBlock);
this.m_tempByteBlock = null;
SplitPackage(buffer, m_surPlusLength, r);
}
else//接收长度小于剩余长度,无法处理包,所以必须先组合包,然后等下次接收。
{
this.m_tempByteBlock.Write(buffer, 0, r);
m_surPlusLength -= (byte)r;
}
}
}
/// <summary>
/// 设计原则:发送时的异常,应当直接抛出,让发送者直接捕获
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
/// <param name="isAsync"></param>
protected override void PreviewSend(byte[] buffer, int offset, int length, bool isAsync)
{
int dataLen = length - offset;//先获取需要发送的实际数据长度
if (dataLen > byte.MaxValue)//超长判断
{
throw new OverlengthException("发送数据太长。");
}
ByteBlock byteBlock = BytePool.GetByteBlock(64 * 1024);//从内存池申请内存块因为此处数据绝不超过255所以避免内存池碎片化每次申请64K
//ByteBlock byteBlock = BytePool.GetByteBlock(dataLen+1);//实际写法。
try
{
byteBlock.Write((byte)dataLen);//先写长度
byteBlock.Write(buffer, offset, length);//再写数据
if (isAsync)//判断异步
{
byte[] data = byteBlock.ToArray();//使用异步时不能将byteBlock.Buffer进行发送应当ToArray成新的Byte[]。
this.GoSend(data, 0, data.Length, isAsync);//调用GoSend实际发送
}
else
{
this.GoSend(byteBlock.Buffer, 0, byteBlock.Len, isAsync);
}
}
finally
{
byteBlock.Dispose();//释放内存块
}
}
protected override void PreviewSend(IList<ArraySegment<byte>> transferBytes, bool isAsync)
{
//暂时不实现。
}
protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
{
throw new System.NotImplementedException();
}
protected override void Reset()
{
}
/// <summary>
/// 处理数据
/// </summary>
/// <param name="byteBlock"></param>
private void PreviewHandle(ByteBlock byteBlock)
{
try
{
this.GoReceived(byteBlock, null);
}
finally
{
byteBlock.Dispose();//在框架里面将内存块释放
}
}
/// <summary>
/// 分解包
/// </summary>
/// <param name="dataBuffer"></param>
/// <param name="index"></param>
/// <param name="r"></param>
private void SplitPackage(byte[] dataBuffer, int index, int r)
{
while (index < r)
{
byte length = dataBuffer[index];
int recedSurPlusLength = r - index - 1;
if (recedSurPlusLength >= length)
{
ByteBlock byteBlock = BytePool.GetByteBlock(length);
byteBlock.Write(dataBuffer, index + 1, length);
PreviewHandle(byteBlock);
m_surPlusLength = 0;
}
else//半包
{
this.m_tempByteBlock = BytePool.GetByteBlock(length);
m_surPlusLength = (byte)(length - recedSurPlusLength);
this.m_tempByteBlock.Write(dataBuffer, index + 1, recedSurPlusLength);
}
index += length + 1;
}
}
}
}

View File

@@ -1 +0,0 @@
A5 5A 26 00 31 31 4D 32 30 30 30 30 30 30 30 30 30 30 30 30 30 09 C1 4A 27 EA 92 F4 33 33 1F 41 8F C2 03 42 00 00 20 41 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 93 73 96

View File

@@ -1,145 +0,0 @@
using TouchSocket.Core;
using TouchSocket.Core.ByteManager;
using TouchSocket.Sockets;
namespace AdapterConsoleApp
{
/// <summary>
/// 国网输电i1标准版
/// </summary>
internal class SGCCCustomDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<SGCCRequestInfo>
{
public override int HeaderLength => 30;
public override bool CanSendRequestInfo => false;
protected override SGCCRequestInfo GetInstance()
{
return new SGCCRequestInfo();
}
protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
{
throw new System.NotImplementedException();
}
}
public class SGCCRequestInfo : IFixedHeaderRequestInfo
{
private byte[] m_sync;
private int m_bodyLength;
private byte[] m_cMDID;
private byte[] m_sample;
private byte[] m_cRC16;
public int BodyLength { get => m_bodyLength; }
/// <summary>
/// 报文头:5AA5
/// </summary>
public byte[] Sync { get => m_sync; set => m_sync = value; }
/// <summary>
/// 报文长度
/// </summary>
public ushort PacketLength { get => (ushort)(this.m_bodyLength - 3); }
/// <summary>
/// 状态监测装置ID(17位编码)
/// </summary>
public byte[] CMDID { get => m_cMDID; set => m_cMDID = value; }
/// <summary>
/// 帧类型—参考附表C8-1相关含义
/// </summary>
public byte FrameType { get; set; }
/// <summary>
/// 报文类型—参考附表C8-2相关含义
/// </summary>
public byte PacketType { get; set; }
/// <summary>
/// 帧序列号(无符号整数)
/// </summary>
public byte FrameNo { get; set; }
/// <summary>
/// 通道号—表示采集装置上的摄像机编号。如:一个装连接⒉部摄像机则分别标号为1、2
/// </summary>
public byte ChannelNo { get; set; }
/// <summary>
/// 预置位号—即云台摄像所设置的预置位号,不带云台摄像机预置位号为255
/// </summary>
public byte PresettingNo { get; set; }
/// <summary>
/// 总包数(无符号整数,取值范围:大于等于0)
/// </summary>
public ushort PacketNo { get; set; }
/// <summary>
/// 子包包号(无符号整数,取值范围:大于等于0>
/// </summary>
public ushort SubpacketNo { get; set; }
/// <summary>
/// 数据区
/// </summary>
public byte[] Sample { get => m_sample; set => m_sample = value; }
/// <summary>
/// 校验位
/// </summary>
public byte[] CRC16 { get => m_cRC16; }
/// <summary>
/// 报文尾:0x96
/// </summary>
public byte End { get; set; }
public bool OnParsingHeader(byte[] header)
{
if (header.Length == 30)
{
using (ByteBlock byteBlock = new ByteBlock(header))
{
byteBlock.Pos = 0;
byteBlock.Read(out m_sync, 2);
byte[] lenBuffer;
byteBlock.Read(out lenBuffer, 2);
this.m_bodyLength = TouchSocketBitConverter.LittleEndian.ToUInt16(lenBuffer, 0) + 3 - 6;//先把crc校验和end都获取。
byteBlock.Read(out m_cMDID, 17);
this.FrameType = (byte)byteBlock.ReadByte();
this.PacketType = (byte)byteBlock.ReadByte();
this.FrameNo = (byte)byteBlock.ReadByte();
this.ChannelNo = (byte)byteBlock.ReadByte();
this.PresettingNo = (byte)byteBlock.ReadByte();
this.PacketNo = byteBlock.ReadUInt16();
this.SubpacketNo = byteBlock.ReadUInt16();
return true;
}
}
return false;
}
public bool OnParsingBody(byte[] body)
{
if (body.Length == this.BodyLength && body[^1] == 150)
{
using (ByteBlock byteBlock = new ByteBlock(body))
{
byteBlock.Read(out this.m_sample, this.m_bodyLength - 3);
byteBlock.Read(out this.m_cRC16, 2);
this.End = (byte)byteBlock.ReadByte();
}
return true;
}
return false;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

View File

@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,251 +0,0 @@
using System;
using System.Text;
using System.Threading;
using TouchSocket.Core;
using TouchSocket.Core.ByteManager;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.IO;
using TouchSocket.Core.Log;
using TouchSocket.Core.Plugins;
using TouchSocket.Sockets;
using TouchSocket.Sockets.Plugins;
namespace HeartbeatConsoleApp
{
internal class Program
{
private static TcpService service = new TcpService();
private static TcpClient tcpClient = new TcpClient();
/// <summary>
/// 示例心跳。
/// 博客地址<see href="https://blog.csdn.net/qq_40374647/article/details/125598921"/>
/// </summary>
/// <param name="args"></param>
private static void Main(string[] args)
{
ConsoleAction consoleAction = new ConsoleAction();
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(10000)
.UsePlugin()
.SetThreadCount(10))
.Start();//启动
service.AddPlugin<HeartbeatAndReceivePlugin>();
service.Logger.Info("服务器成功启动");
tcpClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.UsePlugin()
.SetBufferLength(1024 * 10));
tcpClient.AddPlugin<HeartbeatAndReceivePlugin>();
tcpClient.Connect();
tcpClient.Logger.Info("客户端成功连接");
consoleAction.OnException += ConsoleAction_OnException;
consoleAction.Add("1", "发送心跳", () =>
{
tcpClient.Ping();
});
consoleAction.Add("2", "发送数据", () =>
{
tcpClient.Send(new MyRequestInfo()
{
DataType = DataType.Data,
Data = Encoding.UTF8.GetBytes(Console.ReadLine())
}
.PackageAsBytes());
});
consoleAction.ShowAll();
while (true)
{
consoleAction.Run(Console.ReadLine());
}
}
private static void ConsoleAction_OnException(Exception obj)
{
Console.WriteLine(obj);
}
}
#region
internal class MyFixedHeaderDataHandlingAdapter : CustomFixedHeaderDataHandlingAdapter<MyRequestInfo>
{
public override int HeaderLength => 3;
public override bool CanSendRequestInfo => false;
protected override MyRequestInfo GetInstance()
{
return new MyRequestInfo();
}
protected override void PreviewSend(IRequestInfo requestInfo, bool isAsync)
{
throw new NotImplementedException();
}
}
internal class MyRequestInfo : IFixedHeaderRequestInfo
{
public DataType DataType { get; set; }
public byte[] Data { get; set; }
public int BodyLength { get; private set; }
public bool OnParsingBody(byte[] body)
{
if (body.Length == this.BodyLength)
{
this.Data = body;
return true;
}
return false;
}
public bool OnParsingHeader(byte[] header)
{
if (header.Length == 3)
{
this.BodyLength = TouchSocketBitConverter.Default.ToUInt16(header, 0) - 1;
this.DataType = (DataType)header[2];
return true;
}
return false;
}
public void Package(ByteBlock byteBlock)
{
byteBlock.Write((ushort)((this.Data == null ? 0 : this.Data.Length) + 1));
byteBlock.Write((byte)this.DataType);
byteBlock.Write(Data);
}
public byte[] PackageAsBytes()
{
using ByteBlock byteBlock = new ByteBlock();
this.Package(byteBlock);
return byteBlock.ToArray();
}
public override string ToString()
{
return $"数据类型={this.DataType},数据={(this.Data == null ? "null" : Encoding.UTF8.GetString(this.Data))}";
}
}
internal enum DataType : byte
{
Ping,
Pong,
Data
}
#endregion
/// <summary>
/// 一个心跳计数器扩展。
/// </summary>
internal static class DependencyExtensions
{
public static readonly DependencyProperty HeartbeatTimerProperty =
DependencyProperty.Register("HeartbeatTimer", typeof(Timer), typeof(DependencyExtensions), null);
public static bool Ping<TClient>(this TClient client) where TClient : ITcpClientBase
{
try
{
client.Send(new MyRequestInfo() { DataType = DataType.Ping }.PackageAsBytes());
return true;
}
catch (Exception ex)
{
client.Logger.Exception(ex);
}
return false;
}
public static bool Pong<TClient>(this TClient client) where TClient : ITcpClientBase
{
try
{
client.Send(new MyRequestInfo() { DataType = DataType.Pong }.PackageAsBytes());
return true;
}
catch (Exception ex)
{
client.Logger.Exception(ex);
}
return false;
}
}
internal class HeartbeatAndReceivePlugin : TcpPluginBase
{
private readonly int m_timeTick;
[DependencyInject(1000 * 5)]
public HeartbeatAndReceivePlugin(int timeTick)
{
this.m_timeTick = timeTick;
}
protected override void OnConnecting(ITcpClientBase client, ClientOperationEventArgs e)
{
client.SetDataHandlingAdapter(new MyFixedHeaderDataHandlingAdapter());//设置适配器。
base.OnConnecting(client, e);
}
protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e)
{
if (client is ISocketClient)
{
return;//此处可判断,如果为服务器,则不用使用心跳。
}
if (client.GetValue<Timer>(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)
{
timer.Dispose();
}
client.SetValue(DependencyExtensions.HeartbeatTimerProperty, new Timer((o) =>
{
client.Ping();
}, null, 0, m_timeTick));
base.OnConnected(client, e);
}
protected override void OnDisconnected(ITcpClientBase client, ClientDisconnectedEventArgs e)
{
base.OnDisconnected(client, e);
if (client.GetValue<Timer>(DependencyExtensions.HeartbeatTimerProperty) is Timer timer)
{
timer.Dispose();
client.SetValue(DependencyExtensions.HeartbeatTimerProperty, null);
}
}
protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e)
{
if (e.RequestInfo is MyRequestInfo myRequest)
{
client.Logger.Info(myRequest.ToString());
if (myRequest.DataType == DataType.Ping)
{
client.Pong();
}
}
base.OnReceivedData(client, e);
}
}
}

View File

@@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,111 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Text;
using System.Threading;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Core.Plugins;
using TouchSocket.Sockets;
using TouchSocket.Sockets.Plugins;
namespace LimitNumberOfConnectionsConsoleApp
{
internal class Program
{
/// <summary>
/// 限制同一个IP的连接数量
/// 博客地址<see href="https://blog.csdn.net/qq_40374647/article/details/125390655"/>
/// </summary>
/// <param name="args"></param>
private static void Main(string[] args)
{
TcpService service = new TcpService();
service.Connecting += (client, e) => { };//有客户端正在连接
service.Connected += (client, e) => { };//有客户端连接
service.Disconnected += (client, e) => { };//有客户端断开连接
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"已从{client.ID}接收到信息:{mes}");
client.Send(mes);//将收到的信息直接返回给发送方
};
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(10000)
.SetThreadCount(100)
.UsePlugin())
.Start();//启动
service.AddPlugin<LimitNumberOfConnectionsPlugin>();
Console.ReadKey();
}
}
internal class LimitNumberOfConnectionsPlugin : TcpPluginBase
{
[DependencyInject(2)]
public LimitNumberOfConnectionsPlugin(int max, ILog logger)
{
this.Max = max;
this.Logger = logger;
logger.Info($"限制连接插件生效同一IP限制{max}个连接");
}
private readonly ConcurrentDictionary<string, Count> m_ipToCount = new ConcurrentDictionary<string, Count>();
public int Max { get; }
protected override void OnConnecting(ITcpClientBase client, ClientOperationEventArgs e)
{
Count count = m_ipToCount.GetOrAdd(client.IP, (s) => { return new Count(); });
if (count.Increment() > this.Max)
{
count.Decrement();
e.IsPermitOperation = false;//表示不许连接
e.Handled = true;//并且已经处理该消息。
this.Logger.Warning($"IP={client.IP}的客户端,连接数达到设置阈值。已拒绝连接。");
return;
}
base.OnConnecting(client, e);
}
protected override void OnDisconnected(ITcpClientBase client, ClientDisconnectedEventArgs e)
{
if (m_ipToCount.TryGetValue(client.IP, out Count count))
{
if (count.Decrement() == 0)
{
m_ipToCount.TryRemove(client.IP, out _);
}
}
base.OnDisconnected(client, e);
}
}
internal class Count
{
private int num;
public int Num
{
get { return num; }
}
public int Increment()
{
return Interlocked.Increment(ref num);
}
public int Decrement()
{
return Interlocked.Decrement(ref num);
}
}
}

View File

@@ -1,88 +0,0 @@
using System;
using System.Text;
using TouchSocket.Core;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Plugins;
using TouchSocket.Sockets;
using TouchSocket.Sockets.Plugins;
namespace ThrottlingConsoleApp
{
internal class Program
{
/// <summary>
/// 限制单个客户端的访问流量
/// 博客连接<see href="https://blog.csdn.net/qq_40374647/article/details/125496769"/>
/// </summary>
/// <param name="args"></param>
private static void Main(string[] args)
{
TcpService service = new TcpService();
service.Connecting += (client, e) => { };//有客户端正在连接
service.Connected += (client, e) => { };//有客户端连接
service.Disconnected += (client, e) => { };//有客户端断开连接
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"已从{client.ID}接收到信息:{mes}");
client.Send(mes);//将收到的信息直接返回给发送方
};
service.Setup(new TouchSocketConfig()//载入配置
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(10000)
.SetThreadCount(100))
.Start();//启动
service.AddPlugin<MyThrottlingPlugin>();
Console.ReadLine();
}
}
/// <summary>
/// 一个流量计数器扩展。
/// </summary>
internal static class DependencyExtensions
{
public static readonly DependencyProperty FlowGateProperty =
DependencyProperty.Register("FlowGate", typeof(FlowGate), typeof(DependencyExtensions), null);
public static void InitFlowGate(this IDependencyObject dependencyObject, int max)
{
dependencyObject.SetValue(FlowGateProperty, new FlowGate() { Maximum = max });
}
public static FlowGate GetFlowGate(this IDependencyObject dependencyObject)
{
return dependencyObject.GetValue<FlowGate>(FlowGateProperty);
}
}
public class MyThrottlingPlugin : TcpPluginBase
{
private readonly int m_max;
[DependencyInject(10)]
public MyThrottlingPlugin(int max)
{
this.m_max = max;
this.Order = int.MaxValue;//提升优先级
}
protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e)
{
client.InitFlowGate(this.m_max);//初始化流量计数器。
base.OnConnected(client, e);
}
protected override void OnReceivedData(ITcpClientBase client, ReceivedDataEventArgs e)
{
client.GetFlowGate().AddCheckWait(e.ByteBlock.Len);//此处假设接收的是ByteBlock数据。如果是自定义适配器按需增量即可。
base.OnReceivedData(client, e);
}
}
}

View File

@@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,154 +0,0 @@
using System;
using System.Collections;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using TouchSocket.Core;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Core.Plugins;
using TouchSocket.Sockets;
using TouchSocket.Sockets.Plugins;
namespace TrafficCounterConsoleApp
{
class Program
{
static void Main(string[] args)
{
TcpService service = new TcpService();
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
Console.WriteLine($"已从{client.ID}接收到信息:{mes}");
client.Send(mes);//将收到的信息直接返回给发送方
};
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(1000)
.SetThreadCount(10)
.UsePlugin()
.ConfigurePlugins(a =>
{
a.Add<TrafficCounterPlugin>(new object[] { false });//此处可以添加插件
})
.ConfigureContainer(a =>
{
a.SetSingletonLogger<ConsoleLogger>();//添加一个日志注入
}))
.Start();//启动
Timer timer = new Timer((s) =>
{
var clients = service.GetClients();
foreach (var item in clients)
{
item.Logger.Info($"发送流量:{item.GetSendTrafficCounter()}");
item.Logger.Info($"接收流量:{item.GetReceivedTrafficCounter()}");
}
}, null, 0, 1000);
Console.ReadKey();
}
}
public class TrafficCounterPlugin : TcpPluginBase
{
public bool AutoRefresh { get; }
[DependencyInject(true)]
public TrafficCounterPlugin(bool autoRefresh)
{
this.AutoRefresh = autoRefresh;
}
protected override void OnConnected(ITcpClientBase client, TouchSocketEventArgs e)
{
client.SetValue(TrafficCounterEx.AutoRefreshProperty, this.AutoRefresh);
if (this.AutoRefresh)
{
client.SetValue(TrafficCounterEx.AutoRefreshTimerProperty, new Timer((s) =>
{
var countSend = client.GetValue<int>(TrafficCounterEx.SendTempTrafficCounterProperty);
client.SetValue(TrafficCounterEx.SendTempTrafficCounterProperty, 0);
client.SetValue(TrafficCounterEx.SendTrafficCounterProperty, countSend);
var countRev = client.GetValue<int>(TrafficCounterEx.ReceivedTempTrafficCounterProperty);
client.SetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty, 0);
client.SetValue(TrafficCounterEx.ReceivedTrafficCounterProperty, countRev);
}, null, 0, 1000));
}
base.OnConnected(client, e);
}
protected override void OnSending(ITcpClientBase client, SendingEventArgs e)
{
client.SetValue(TrafficCounterEx.SendTempTrafficCounterProperty,
e.Length + client.GetValue<int>(TrafficCounterEx.SendTempTrafficCounterProperty));
base.OnSending(client, e);
}
protected override void OnReceivingData(ITcpClientBase client, ByteBlockEventArgs e)
{
client.SetValue(TrafficCounterEx.ReceivedTempTrafficCounterProperty,
e.ByteBlock.Len + +client.GetValue<int>(TrafficCounterEx.ReceivedTempTrafficCounterProperty));
base.OnReceivingData(client, e);
}
}
public static class TrafficCounterEx
{
public static readonly DependencyProperty SendTrafficCounterProperty =
DependencyProperty.Register("SendTrafficCounter", typeof(int), typeof(TrafficCounterEx), 0);
public static readonly DependencyProperty SendTempTrafficCounterProperty =
DependencyProperty.Register("SendTempTrafficCounter", typeof(int), typeof(TrafficCounterEx), 0);
public static readonly DependencyProperty ReceivedTrafficCounterProperty =
DependencyProperty.Register("ReceivedTrafficCounter", typeof(int), typeof(TrafficCounterEx), 0);
public static readonly DependencyProperty ReceivedTempTrafficCounterProperty =
DependencyProperty.Register("ReceivedTempTrafficCounter", typeof(int), typeof(TrafficCounterEx), 0);
public static readonly DependencyProperty AutoRefreshProperty =
DependencyProperty.Register("AutoRefresh", typeof(bool), typeof(TrafficCounterEx), true);
public static readonly DependencyProperty AutoRefreshTimerProperty =
DependencyProperty.Register("AutoRefreshTimer", typeof(Timer), typeof(TrafficCounterEx), null);
public static int GetSendTrafficCounter(this DependencyObject dependencyObject)
{
if (dependencyObject.GetValue<bool>(AutoRefreshProperty))
{
return dependencyObject.GetValue<int>(SendTrafficCounterProperty);
}
else
{
var count = dependencyObject.GetValue<int>(SendTempTrafficCounterProperty);
dependencyObject.SetValue(SendTempTrafficCounterProperty, 0);
dependencyObject.SetValue(SendTrafficCounterProperty, count);
return count;
}
}
public static int GetReceivedTrafficCounter(this DependencyObject dependencyObject)
{
if (dependencyObject.GetValue<bool>(AutoRefreshProperty))
{
return dependencyObject.GetValue<int>(ReceivedTrafficCounterProperty);
}
else
{
var count = dependencyObject.GetValue<int>(ReceivedTempTrafficCounterProperty);
dependencyObject.SetValue(ReceivedTempTrafficCounterProperty, 0);
dependencyObject.SetValue(ReceivedTrafficCounterProperty, count);
return count;
}
}
}
}

View File

@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Consul" Version="1.6.10.7" />
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,72 +0,0 @@
using Consul;
using System;
using System.Text;
using TouchSocket.Core.Config;
using TouchSocket.Core.Log;
using TouchSocket.Sockets;
namespace ConsulConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
TcpService service = new TcpService();
service.Connecting += (client, e) =>
{
service.Logger.Info("Connecting");
};//有客户端正在连接
service.Connected += (client, e) => { service.Logger.Info("Connected"); };//有客户端连接
service.Disconnected += (client, e) => { service.Logger.Info("Disconnected"); };//有客户端断开连接
service.Received += (client, byteBlock, requestInfo) =>
{
//从客户端收到信息
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
client.Logger.Info($"已从{client.ID}接收到信息:{mes}");
//client.Send(mes);//将收到的信息直接返回给发送方
};
service.Setup(new TouchSocketConfig()//载入配置
.SetListenIPHosts(new IPHost[] { new IPHost("127.0.0.1:7789"), new IPHost(7790) })//同时监听两个地址
.SetMaxCount(10000)
.SetThreadCount(100))
.Start();//启动
RegisterConsul(7789);
Console.ReadKey();
}
/// <summary>
/// 注册Consul使用该功能时请先了解Consul然后配置基本如下。
/// </summary>
public static void RegisterConsul(int port)
{
var consulClient = new ConsulClient(p => { p.Address = new Uri($"http://127.0.0.1:8500"); });//请求注册的 Consul 地址
//这里的这个ip 就是本机的ip这个端口8500 这个是默认注册服务端口
var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),
//HTTP = $"http://127.0.0.1:{port}/api/Health",//健康检查地址
TCP = $"127.0.0.1:{ port}",
Timeout = TimeSpan.FromSeconds(5)
};
var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
ID = Guid.NewGuid().ToString(),
Name = "RRQM Tcp Service" + port,
Address = "127.0.0.1",
Port = port
};
consulClient.Agent.ServiceRegister(registration).Wait();//注册服务
//consulClient.Agent.ServiceDeregister(registration.ID).Wait();//registration.ID是guid
//当服务停止时需要取消服务注册,不然,下次启动服务时,会再注册一个服务。
//但是如果该服务长期不启动那consul会自动删除这个服务大约23分钟就会删了
}
}
}

View File

@@ -1,171 +0,0 @@
using Consul;
using System;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Core.Plugins;
using TouchSocket.Http;
using TouchSocket.Http.WebSockets;
using TouchSocket.Http.WebSockets.Plugins;
using TouchSocket.Rpc;
using TouchSocket.Rpc.JsonRpc;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Rpc.WebApi;
using TouchSocket.Rpc.XmlRpc;
using TouchSocket.Sockets;
namespace ServiceConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("输入本地监听端口");
int port = int.Parse(Console.ReadLine());
//此处直接建立HttpTouchRpcService。
//此组件包含Http所有功能可以承载JsonRpc、XmlRpc、WebSocket、TouchRpc等等。
var service = new TouchSocketConfig()
.UsePlugin()
.SetBufferLength(1024 * 64)
.SetThreadCount(50)
.SetReceiveType(ReceiveType.Auto)
.SetListenIPHosts(new IPHost[] { new IPHost(port) })
.ConfigureContainer(a =>
{
a.SetSingletonLogger<ConsoleLogger>();
})
.BuildWithHttpTouchRpcService();
service.Logger.Info("Http服务器已启动");
service.AddPlugin<WebSocketServerPlugin>().//添加WebSocket功能
SetWSUrl("/ws");
service.Logger.Info($"WS插件已加载使用 ws://127.0.0.1:{port}/ws 连接");
service.AddPlugin<MyWebSocketPlug>();//添加WebSocket业务数据接收插件
service.AddPlugin<MyWebSocketCommand>();//添加WebSocket快捷实现常规WS客户端发送文本“Add 10 20”即可得到30。
service.Logger.Info("WS命令行插件已加载使用WS发送文本“Add 10 20”获取答案");
IRpcParser jsonRpcParser = service.AddPlugin<JsonRpcParserPlugin>()
.SetJsonRpcUrl("/jsonrpc");
service.Logger.Info($"jsonrpc插件已加载使用 Http://127.0.0.1:{port}/jsonrpc +JsonRpc规范调用");
IRpcParser xmlRpcParser = service.AddPlugin<XmlRpcParserPlugin>()
.SetXmlRpcUrl("/xmlrpc");
service.Logger.Info($"jsonrpc插件已加载使用 Http://127.0.0.1:{port}/xmlrpc +XmlRpc规范调用");
IRpcParser webApiParser = service.AddPlugin<WebApiParserPlugin>();
service.Logger.Info("WebApi插件已加载");
RpcStore rpcStore = new RpcStore(new TouchSocket.Core.Dependency.Container());
rpcStore.AddRpcParser("httpTouchRpcService", service);
rpcStore.AddRpcParser("jsonRpcParser", jsonRpcParser);
rpcStore.AddRpcParser("xmlRpcParser", xmlRpcParser);
rpcStore.AddRpcParser("webApiParser", webApiParser);
rpcStore.RegisterServer<MyServer>();
service.Logger.Info("RPC注册完成。");
//rpcStore.ShareProxy(new IPHost(8848));
//rpcStore.ProxyUrl = "/proxy";
//service.Logger.Message("RPC代理文件已分享使用 Http://127.0.0.1:8848/proxy?proxy=all 获取");
RegisterConsul(port);
service.Logger.Info("Consul已成功注册");
while (Console.ReadKey().Key != ConsoleKey.Escape)
{
Console.WriteLine("按ESC键退出。");
}
}
/// <summary>
/// 注册Consul使用该功能时请先了解Consul然后配置基本如下。
/// </summary>
public static void RegisterConsul(int port)
{
var consulClient = new ConsulClient(p => { p.Address = new Uri($"http://127.0.0.1:8500"); });//请求注册的 Consul 地址
//这里的这个ip 就是本机的ip这个端口8500 这个是默认注册服务端口
var httpCheck = new AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册
Interval = TimeSpan.FromSeconds(10),//间隔固定的时间访问一次https://127.0.0.1:7789/api/Health
HTTP = $"http://127.0.0.1:{port}/api/Health",//健康检查地址
Timeout = TimeSpan.FromSeconds(5)
};
var registration = new AgentServiceRegistration()
{
Checks = new[] { httpCheck },
ID = Guid.NewGuid().ToString(),
Name = "RRQMService" + port,
Address = "127.0.0.1",
Port = port
};
consulClient.Agent.ServiceRegister(registration).Wait();//注册服务
//consulClient.Agent.ServiceDeregister(registration.ID).Wait();//registration.ID是guid
//当服务停止时需要取消服务注册,不然,下次启动服务时,会再注册一个服务。
//但是如果该服务长期不启动那consul会自动删除这个服务大约23分钟就会删了
}
}
internal class MyServer : RpcServer
{
[WebApi(HttpMethodType.GET)]
[XmlRpc]
[JsonRpc]
[TouchRpc]
public string SayHello(string name)
{
return $"{name},RRQM says hello to you.";
}
/// <summary>
/// 健康检测
/// </summary>
/// <returns></returns>
[Router("/api/health")]
[WebApi(HttpMethodType.GET)]
public string Health()
{
return "ok";
}
}
/// <summary>
/// WS命令行执行
/// </summary>
internal class MyWebSocketCommand : WSCommandLinePlugin
{
public int AddCommand(int a, int b)
{
return a + b;
}
}
/// <summary>
/// WS收到数据等业务。
/// </summary>
internal class MyWebSocketPlug : WebSocketPluginBase
{
protected override void OnHandshaked(ITcpClientBase client, HttpContextEventArgs e)
{
SocketClient socketClient = (SocketClient)client;
client.Logger.Info($"WS客户端连接ID={socketClient.ID}IPHost={client.IP}:{client.Port}");
base.OnHandshaked(client, e);
}
protected override void OnHandleWSDataFrame(ITcpClientBase client, WSDataFrameEventArgs e)
{
if (e.DataFrame.Opcode == WSDataType.Text)
{
client.Logger.Info($"WS Msg={e.DataFrame.ToText()}");
}
base.OnHandleWSDataFrame(client, e);
}
}
}

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Consul" Version="1.6.10.7" />
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,124 +0,0 @@

namespace WinFormsApp
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.listBox1 = new System.Windows.Forms.ListBox();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.button3 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// listBox1
//
this.listBox1.DisplayMember = "Service";
this.listBox1.FormattingEnabled = true;
this.listBox1.ItemHeight = 17;
this.listBox1.Location = new System.Drawing.Point(13, 47);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(217, 395);
this.listBox1.TabIndex = 0;
//
// button1
//
this.button1.Location = new System.Drawing.Point(13, 18);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(217, 23);
this.button1.TabIndex = 1;
this.button1.Text = "获取所有服务";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(475, 46);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 2;
this.button2.Text = "TouchRpc";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(283, 46);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(171, 23);
this.textBox1.TabIndex = 3;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(236, 49);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(43, 17);
this.label1.TabIndex = 4;
this.label1.Text = "Name";
//
// button3
//
this.button3.Location = new System.Drawing.Point(556, 46);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(75, 23);
this.button3.TabIndex = 5;
this.button3.Text = "JsonRpc";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.button3);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.listBox1);
this.Name = "Form1";
this.Text = "JsonRpc";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button3;
}
}

View File

@@ -1,86 +0,0 @@
using Consul;
using System;
using System.Linq;
using System.Windows.Forms;
using TouchSocket.Core.Config;
using TouchSocket.Rpc.JsonRpc;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace WinFormsApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private AgentService[] services;
private async void button1_Click(object sender, EventArgs e)
{
var consulClient = new ConsulClient(x => x.Address = new Uri($"http://127.0.0.1:8500"));//请求注册的 Consul 地址
var ret = await consulClient.Agent.Services();
services = ret.Response.Values.ToArray();
this.listBox1.DataSource = services;
}
private void button2_Click(object sender, EventArgs e)
{
if (this.listBox1.SelectedItem is AgentService agentService)
{
try
{
HttpTouchRpcClient client = new HttpTouchRpcClient();
client.Setup(new TouchSocketConfig()
.SetRemoteIPHost($"{agentService.Address}:{agentService.Port}"));
client.Connect();
//直接调用时,第一个参数为服务名+方法名(必须全小写)
//第二个参数为调用配置参数,可设置调用超时时间,取消调用等功能。
//后续参数为调用参数。
string result = client.Invoke<string>("myserver/sayhello", InvokeOption.WaitInvoke, textBox1.Text);
client.SafeDispose();
MessageBox.Show(result);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show("请先选择一个服务器节点。");
}
}
private void button3_Click(object sender, EventArgs e)
{
if (this.listBox1.SelectedItem is AgentService agentService)
{
try
{
JsonRpcClient client = new JsonRpcClient();
client.Setup(new TouchSocketConfig()
.SetJRPT(JRPT.Http)
.SetRemoteIPHost($"http://{agentService.Address}:{agentService.Port}/jsonrpc"));
client.Connect();
string result = client.Invoke<string>("myserver/sayhello", InvokeOption.WaitInvoke, textBox1.Text);
client.SafeDispose();
MessageBox.Show(result);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else
{
MessageBox.Show("请先选择一个服务器节点。");
}
}
}
}

View File

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

View File

@@ -1,20 +0,0 @@
using System;
using System.Windows.Forms;
namespace WinFormsApp
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View File

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Consul" Version="1.6.10.7" />
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocketPro" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,359 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在RRQMCore.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://www.yuque.com/eo2w71/rrqm
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace EERPCClientDemo
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button2 = new System.Windows.Forms.Button();
this.checkBox3 = new System.Windows.Forms.CheckBox();
this.checkBox2 = new System.Windows.Forms.CheckBox();
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.textBox3 = new System.Windows.Forms.TextBox();
this.listBox1 = new System.Windows.Forms.ListBox();
this.button5 = new System.Windows.Forms.Button();
this.textBox4 = new System.Windows.Forms.TextBox();
this.button6 = new System.Windows.Forms.Button();
this.button7 = new System.Windows.Forms.Button();
this.button8 = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.SuspendLayout();
//
// button2
//
this.button2.Location = new System.Drawing.Point(38, 121);
this.button2.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 27);
this.button2.TabIndex = 14;
this.button2.Text = "刷新所有事件";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// checkBox3
//
this.checkBox3.AutoSize = true;
this.checkBox3.Location = new System.Drawing.Point(423, 43);
this.checkBox3.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.checkBox3.Name = "checkBox3";
this.checkBox3.Size = new System.Drawing.Size(80, 21);
this.checkBox3.TabIndex = 13;
this.checkBox3.Text = "Everyone";
this.checkBox3.UseVisualStyleBackColor = true;
//
// checkBox2
//
this.checkBox2.AutoSize = true;
this.checkBox2.Location = new System.Drawing.Point(355, 43);
this.checkBox2.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.checkBox2.Name = "checkBox2";
this.checkBox2.Size = new System.Drawing.Size(68, 21);
this.checkBox2.TabIndex = 12;
this.checkBox2.Text = "Service";
this.checkBox2.UseVisualStyleBackColor = true;
//
// checkBox1
//
this.checkBox1.AutoSize = true;
this.checkBox1.Checked = true;
this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBox1.Location = new System.Drawing.Point(285, 43);
this.checkBox1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(65, 21);
this.checkBox1.TabIndex = 11;
this.checkBox1.Text = "Owner";
this.checkBox1.UseVisualStyleBackColor = true;
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(77, 43);
this.textBox2.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(201, 23);
this.textBox2.TabIndex = 10;
//
// button1
//
this.button1.Location = new System.Drawing.Point(513, 43);
this.button1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 27);
this.button1.TabIndex = 9;
this.button1.Text = "发布事件";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(12, 412);
this.textBox1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(708, 102);
this.textBox1.TabIndex = 8;
//
// button3
//
this.button3.Location = new System.Drawing.Point(15, 16);
this.button3.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(75, 27);
this.button3.TabIndex = 15;
this.button3.Text = "连接";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// button4
//
this.button4.Location = new System.Drawing.Point(285, 89);
this.button4.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(75, 27);
this.button4.TabIndex = 17;
this.button4.Text = "订阅事件";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// textBox3
//
this.textBox3.Location = new System.Drawing.Point(77, 89);
this.textBox3.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.textBox3.Name = "textBox3";
this.textBox3.Size = new System.Drawing.Size(201, 23);
this.textBox3.TabIndex = 16;
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.ItemHeight = 17;
this.listBox1.Location = new System.Drawing.Point(38, 152);
this.listBox1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(201, 106);
this.listBox1.TabIndex = 18;
//
// button5
//
this.button5.Location = new System.Drawing.Point(600, 152);
this.button5.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(75, 27);
this.button5.TabIndex = 20;
this.button5.Text = "触发事件";
this.button5.UseVisualStyleBackColor = true;
this.button5.Click += new System.EventHandler(this.button5_Click);
//
// textBox4
//
this.textBox4.Location = new System.Drawing.Point(247, 152);
this.textBox4.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.textBox4.Name = "textBox4";
this.textBox4.Size = new System.Drawing.Size(332, 23);
this.textBox4.TabIndex = 19;
//
// button6
//
this.button6.Location = new System.Drawing.Point(600, 43);
this.button6.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button6.Name = "button6";
this.button6.Size = new System.Drawing.Size(75, 27);
this.button6.TabIndex = 21;
this.button6.Text = "取消发布";
this.button6.UseVisualStyleBackColor = true;
this.button6.Click += new System.EventHandler(this.button6_Click);
//
// button7
//
this.button7.Location = new System.Drawing.Point(371, 89);
this.button7.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button7.Name = "button7";
this.button7.Size = new System.Drawing.Size(75, 27);
this.button7.TabIndex = 22;
this.button7.Text = "取消订阅";
this.button7.UseVisualStyleBackColor = true;
this.button7.Click += new System.EventHandler(this.button7_Click);
//
// button8
//
this.button8.Location = new System.Drawing.Point(365, 381);
this.button8.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.button8.Name = "button8";
this.button8.Size = new System.Drawing.Size(75, 27);
this.button8.TabIndex = 23;
this.button8.Text = "清空";
this.button8.UseVisualStyleBackColor = true;
this.button8.Click += new System.EventHandler(this.button8_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(12, 377);
this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(32, 17);
this.label2.TabIndex = 24;
this.label2.Text = "日志";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(31, 45);
this.label4.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(44, 17);
this.label4.TabIndex = 25;
this.label4.Text = "事件名";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(31, 91);
this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(44, 17);
this.label1.TabIndex = 26;
this.label1.Text = "事件名";
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Location = new System.Drawing.Point(15, 48);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(709, 320);
this.tabControl1.TabIndex = 27;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.textBox2);
this.tabPage1.Controls.Add(this.label1);
this.tabPage1.Controls.Add(this.button1);
this.tabPage1.Controls.Add(this.label4);
this.tabPage1.Controls.Add(this.checkBox1);
this.tabPage1.Controls.Add(this.checkBox2);
this.tabPage1.Controls.Add(this.checkBox3);
this.tabPage1.Controls.Add(this.button7);
this.tabPage1.Controls.Add(this.button2);
this.tabPage1.Controls.Add(this.button6);
this.tabPage1.Controls.Add(this.textBox3);
this.tabPage1.Controls.Add(this.button5);
this.tabPage1.Controls.Add(this.button4);
this.tabPage1.Controls.Add(this.textBox4);
this.tabPage1.Controls.Add(this.listBox1);
this.tabPage1.Location = new System.Drawing.Point(4, 26);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(701, 290);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "EventBus";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tabPage2
//
this.tabPage2.Location = new System.Drawing.Point(4, 26);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(701, 290);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "RPC";
this.tabPage2.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(752, 547);
this.Controls.Add(this.tabControl1);
this.Controls.Add(this.button8);
this.Controls.Add(this.button3);
this.Controls.Add(this.label2);
this.Controls.Add(this.textBox1);
this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage1.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button2;
private System.Windows.Forms.CheckBox checkBox3;
private System.Windows.Forms.CheckBox checkBox2;
private System.Windows.Forms.CheckBox checkBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.TextBox textBox3;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.TextBox textBox4;
private System.Windows.Forms.Button button6;
private System.Windows.Forms.Button button7;
private System.Windows.Forms.Button button8;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
}
}

View File

@@ -1,181 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在RRQMCore.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://www.yuque.com/eo2w71/rrqm
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Windows.Forms;
using TouchSocket.Core;
using TouchSocket.Core.Config;
using TouchSocket.Rpc;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace EERPCClientDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void ShowMsg(string msg)
{
this.Invoke((Action)(delegate () { this.textBox1.AppendText(msg + "\r\n"); }));
}
private TcpTouchRpcClient tcpRpcClient;
private void button3_Click(object sender, EventArgs e)
{
this.tcpRpcClient = new TcpTouchRpcClient();
this.tcpRpcClient.Disconnected += TcpRpcClient_Disconnected;
tcpRpcClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.ConfigureRpcStore(a=>
{
a.RegisterServer<ThisRpcServer>();
}))
.Connect(1000 * 100);
this.button3.Enabled = false;
this.Text = this.tcpRpcClient.ID;
ShowMsg("连接成功");
}
private void TcpRpcClient_Disconnected(ITcpClientBase client, ClientDisconnectedEventArgs e)
{
ShowMsg("已断开连接");
}
private void button1_Click(object sender, EventArgs e)
{
try
{
AccessType accessType = AccessType.Owner;
if (this.checkBox1.Checked)
{
accessType = accessType | AccessType.Owner;
}
if (this.checkBox2.Checked)
{
accessType = accessType | AccessType.Service;
}
if (this.checkBox3.Checked)
{
accessType = accessType | AccessType.Everyone;
}
this.tcpRpcClient.PublishEvent(this.textBox2.Text, accessType);
ShowMsg("发布成功");
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void button2_Click(object sender, EventArgs e)
{
string[] events = this.tcpRpcClient.GetAllEvents();
this.listBox1.Items.Clear();
this.listBox1.Items.AddRange(events);
}
private void button4_Click(object sender, EventArgs e)
{
try
{
this.tcpRpcClient.SubscribeEvent<string>(this.textBox3.Text, SubscribeEvent);
this.ShowMsg($"订阅成功");
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void SubscribeEvent(EventSender eventSender, string arg)
{
this.ShowMsg($"从{eventSender.RaiseSourceType}收到通知事件{eventSender.EventName},信息:{arg}");
}
private void button5_Click(object sender, EventArgs e)
{
try
{
if (listBox1.SelectedItem is string eventName)
{
this.tcpRpcClient.RaiseEvent(eventName, this.textBox4.Text);
ShowMsg("触发成功");
}
else
{
ShowMsg("请先选择事件");
}
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void button6_Click(object sender, EventArgs e)
{
try
{
this.tcpRpcClient.UnpublishEvent(this.textBox2.Text);
ShowMsg("取消发布成功");
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void button7_Click(object sender, EventArgs e)
{
try
{
this.tcpRpcClient.UnsubscribeEvent(this.textBox3.Text);
ShowMsg("取消订阅成功");
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void button8_Click(object sender, EventArgs e)
{
this.textBox1.Clear();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
Enterprise.ForTest();
}
catch (Exception ex)
{
this.ShowMsg("正在试用企业版功能1小时后失效。");
}
}
}
internal class ThisRpcServer : RpcServer
{
[TouchRpc(true)]
public DateTime GetDataTime()
{
return DateTime.Now;
}
}
}

View File

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

View File

@@ -1,33 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在RRQMCore.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://www.yuque.com/eo2w71/rrqm
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Windows.Forms;
namespace EERPCClientDemo
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new Form1().Show();
Application.Run(new Form1());
}
}
}

View File

@@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocketPro" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,459 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在RRQMCore.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://www.yuque.com/eo2w71/rrqm
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace EERPCServiceDemo
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.textBox2 = new System.Windows.Forms.TextBox();
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.checkBox2 = new System.Windows.Forms.CheckBox();
this.checkBox3 = new System.Windows.Forms.CheckBox();
this.button2 = new System.Windows.Forms.Button();
this.textBox3 = new System.Windows.Forms.TextBox();
this.button3 = new System.Windows.Forms.Button();
this.listBox1 = new System.Windows.Forms.ListBox();
this.button4 = new System.Windows.Forms.Button();
this.textBox4 = new System.Windows.Forms.TextBox();
this.button5 = new System.Windows.Forms.Button();
this.button6 = new System.Windows.Forms.Button();
this.listBox2 = new System.Windows.Forms.ListBox();
this.checkBox4 = new System.Windows.Forms.CheckBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label6 = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.button7 = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.button8 = new System.Windows.Forms.Button();
this.button9 = new System.Windows.Forms.Button();
this.groupBox1.SuspendLayout();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(500, 765);
this.textBox1.Margin = new System.Windows.Forms.Padding(4);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(1220, 409);
this.textBox1.TabIndex = 1;
//
// button1
//
this.button1.Location = new System.Drawing.Point(788, 95);
this.button1.Margin = new System.Windows.Forms.Padding(4);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(150, 49);
this.button1.TabIndex = 2;
this.button1.Text = "发布事件";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(110, 100);
this.textBox2.Margin = new System.Windows.Forms.Padding(4);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(204, 38);
this.textBox2.TabIndex = 3;
//
// checkBox1
//
this.checkBox1.AutoSize = true;
this.checkBox1.Checked = true;
this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBox1.Location = new System.Drawing.Point(326, 100);
this.checkBox1.Margin = new System.Windows.Forms.Padding(4);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(123, 35);
this.checkBox1.TabIndex = 4;
this.checkBox1.Text = "Owner";
this.checkBox1.UseVisualStyleBackColor = true;
//
// checkBox2
//
this.checkBox2.AutoSize = true;
this.checkBox2.Location = new System.Drawing.Point(466, 100);
this.checkBox2.Margin = new System.Windows.Forms.Padding(4);
this.checkBox2.Name = "checkBox2";
this.checkBox2.Size = new System.Drawing.Size(128, 35);
this.checkBox2.TabIndex = 5;
this.checkBox2.Text = "Service";
this.checkBox2.UseVisualStyleBackColor = true;
//
// checkBox3
//
this.checkBox3.AutoSize = true;
this.checkBox3.Location = new System.Drawing.Point(620, 100);
this.checkBox3.Margin = new System.Windows.Forms.Padding(4);
this.checkBox3.Name = "checkBox3";
this.checkBox3.Size = new System.Drawing.Size(152, 35);
this.checkBox3.TabIndex = 6;
this.checkBox3.Text = "Everyone";
this.checkBox3.UseVisualStyleBackColor = true;
//
// button2
//
this.button2.Location = new System.Drawing.Point(186, 346);
this.button2.Margin = new System.Windows.Forms.Padding(4);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(150, 49);
this.button2.TabIndex = 7;
this.button2.Text = "刷新所有事件";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// textBox3
//
this.textBox3.Location = new System.Drawing.Point(108, 157);
this.textBox3.Margin = new System.Windows.Forms.Padding(4);
this.textBox3.Name = "textBox3";
this.textBox3.Size = new System.Drawing.Size(204, 38);
this.textBox3.TabIndex = 8;
//
// button3
//
this.button3.Location = new System.Drawing.Point(324, 153);
this.button3.Margin = new System.Windows.Forms.Padding(4);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(150, 49);
this.button3.TabIndex = 9;
this.button3.Text = "订阅事件";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.ItemHeight = 31;
this.listBox1.Location = new System.Drawing.Point(66, 416);
this.listBox1.Margin = new System.Windows.Forms.Padding(4);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(1106, 159);
this.listBox1.TabIndex = 10;
//
// button4
//
this.button4.Location = new System.Drawing.Point(324, 215);
this.button4.Margin = new System.Windows.Forms.Padding(4);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(150, 49);
this.button4.TabIndex = 12;
this.button4.Text = "触发事件";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// textBox4
//
this.textBox4.Location = new System.Drawing.Point(108, 219);
this.textBox4.Margin = new System.Windows.Forms.Padding(4);
this.textBox4.Name = "textBox4";
this.textBox4.Size = new System.Drawing.Size(204, 38);
this.textBox4.TabIndex = 11;
//
// button5
//
this.button5.Location = new System.Drawing.Point(488, 153);
this.button5.Margin = new System.Windows.Forms.Padding(4);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(150, 49);
this.button5.TabIndex = 13;
this.button5.Text = "取消订阅";
this.button5.UseVisualStyleBackColor = true;
this.button5.Click += new System.EventHandler(this.button5_Click);
//
// button6
//
this.button6.Location = new System.Drawing.Point(946, 95);
this.button6.Margin = new System.Windows.Forms.Padding(4);
this.button6.Name = "button6";
this.button6.Size = new System.Drawing.Size(150, 49);
this.button6.TabIndex = 14;
this.button6.Text = "取消发布";
this.button6.UseVisualStyleBackColor = true;
this.button6.Click += new System.EventHandler(this.button6_Click);
//
// listBox2
//
this.listBox2.FormattingEnabled = true;
this.listBox2.ItemHeight = 31;
this.listBox2.Location = new System.Drawing.Point(12, 47);
this.listBox2.Margin = new System.Windows.Forms.Padding(4);
this.listBox2.Name = "listBox2";
this.listBox2.Size = new System.Drawing.Size(472, 1120);
this.listBox2.TabIndex = 15;
//
// checkBox4
//
this.checkBox4.AutoSize = true;
this.checkBox4.Checked = true;
this.checkBox4.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBox4.Location = new System.Drawing.Point(24, 49);
this.checkBox4.Margin = new System.Windows.Forms.Padding(4);
this.checkBox4.Name = "checkBox4";
this.checkBox4.Size = new System.Drawing.Size(166, 35);
this.checkBox4.TabIndex = 16;
this.checkBox4.Text = "服务器操作";
this.checkBox4.UseVisualStyleBackColor = true;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(66, 352);
this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(110, 31);
this.label1.TabIndex = 17;
this.label1.Text = "事件列表";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(500, 705);
this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(62, 31);
this.label2.TabIndex = 18;
this.label2.Text = "日志";
//
// groupBox1
//
this.groupBox1.Controls.Add(this.label6);
this.groupBox1.Controls.Add(this.label5);
this.groupBox1.Controls.Add(this.label4);
this.groupBox1.Controls.Add(this.checkBox4);
this.groupBox1.Controls.Add(this.textBox2);
this.groupBox1.Controls.Add(this.button1);
this.groupBox1.Controls.Add(this.checkBox1);
this.groupBox1.Controls.Add(this.button4);
this.groupBox1.Controls.Add(this.button6);
this.groupBox1.Controls.Add(this.textBox4);
this.groupBox1.Controls.Add(this.checkBox2);
this.groupBox1.Controls.Add(this.button5);
this.groupBox1.Controls.Add(this.checkBox3);
this.groupBox1.Controls.Add(this.textBox3);
this.groupBox1.Controls.Add(this.button3);
this.groupBox1.Location = new System.Drawing.Point(66, 49);
this.groupBox1.Margin = new System.Windows.Forms.Padding(4);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Padding = new System.Windows.Forms.Padding(4);
this.groupBox1.Size = new System.Drawing.Size(1106, 283);
this.groupBox1.TabIndex = 19;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "操作";
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(14, 222);
this.label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(62, 31);
this.label6.TabIndex = 19;
this.label6.Text = "参数";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(14, 159);
this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(86, 31);
this.label5.TabIndex = 18;
this.label5.Text = "事件名";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(14, 100);
this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(86, 31);
this.label4.TabIndex = 17;
this.label4.Text = "事件名";
//
// button7
//
this.button7.Location = new System.Drawing.Point(1570, 708);
this.button7.Margin = new System.Windows.Forms.Padding(4);
this.button7.Name = "button7";
this.button7.Size = new System.Drawing.Size(150, 49);
this.button7.TabIndex = 17;
this.button7.Text = "清空";
this.button7.UseVisualStyleBackColor = true;
this.button7.Click += new System.EventHandler(this.button7_Click);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(12, 9);
this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(134, 31);
this.label3.TabIndex = 20;
this.label3.Text = "客户端列表";
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Location = new System.Drawing.Point(498, 47);
this.tabControl1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(1222, 647);
this.tabControl1.TabIndex = 21;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.groupBox1);
this.tabPage1.Controls.Add(this.button2);
this.tabPage1.Controls.Add(this.listBox1);
this.tabPage1.Controls.Add(this.label1);
this.tabPage1.Location = new System.Drawing.Point(8, 45);
this.tabPage1.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5);
this.tabPage1.Size = new System.Drawing.Size(1206, 594);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "EventBus";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.button9);
this.tabPage2.Controls.Add(this.button8);
this.tabPage2.Location = new System.Drawing.Point(8, 45);
this.tabPage2.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(6, 5, 6, 5);
this.tabPage2.Size = new System.Drawing.Size(1206, 594);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "RPC";
this.tabPage2.UseVisualStyleBackColor = true;
//
// button8
//
this.button8.Location = new System.Drawing.Point(24, 33);
this.button8.Name = "button8";
this.button8.Size = new System.Drawing.Size(262, 46);
this.button8.TabIndex = 0;
this.button8.Text = "从客户端获取时间";
this.button8.UseVisualStyleBackColor = true;
this.button8.Click += new System.EventHandler(this.button8_Click);
//
// button9
//
this.button9.Location = new System.Drawing.Point(304, 33);
this.button9.Name = "button9";
this.button9.Size = new System.Drawing.Size(262, 46);
this.button9.TabIndex = 1;
this.button9.Text = "从服务器获取时间";
this.button9.UseVisualStyleBackColor = true;
this.button9.Click += new System.EventHandler(this.button9_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(14F, 31F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1739, 1196);
this.Controls.Add(this.tabControl1);
this.Controls.Add(this.label3);
this.Controls.Add(this.button7);
this.Controls.Add(this.listBox2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.label2);
this.Margin = new System.Windows.Forms.Padding(6, 5, 6, 5);
this.Name = "Form1";
this.Text = "Form1";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage1.PerformLayout();
this.tabPage2.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.CheckBox checkBox1;
private System.Windows.Forms.CheckBox checkBox2;
private System.Windows.Forms.CheckBox checkBox3;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox textBox3;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.TextBox textBox4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.Button button6;
private System.Windows.Forms.ListBox listBox2;
private System.Windows.Forms.CheckBox checkBox4;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Button button7;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.Button button8;
private System.Windows.Forms.Button button9;
}
}

View File

@@ -1,330 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在RRQMCore.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://www.yuque.com/eo2w71/rrqm
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Windows.Forms;
using TouchSocket.Core;
using TouchSocket.Core.Config;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace EERPCServiceDemo
{
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
this.Load += this.Form1_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
Enterprise.ForTest();
}
catch (Exception ex)
{
this.ShowMsg("正在试用企业版功能1小时后失效。");
}
Control.CheckForIllegalCrossThreadCalls = false;
this.tcpRpcService = new TcpTouchRpcService();
this.tcpRpcService.Connected += this.TcpRpcParser_Connected;
this.tcpRpcService.Handshaking += this.TcpRpcParser_Handshaking;
this.tcpRpcService.Handshaked += this.TcpRpcParser_Handshaked;
this.tcpRpcService.Disconnected += this.TcpRpcParser_Disconnected;
var config = new TouchSocketConfig();
config.SetListenIPHosts(new IPHost[] { new IPHost(7789) });
this.tcpRpcService.Setup(config).Start();
this.ShowMsg("服务器已启动");
}
private void TcpRpcParser_Handshaking(TcpTouchRpcSocketClient client, VerifyOptionEventArgs e)
{
Debug.WriteLine("Handshaking");
}
private void TcpRpcParser_Connected(TcpTouchRpcSocketClient client, TouchSocketEventArgs e)
{
Debug.WriteLine("Connected");
}
private void TcpRpcParser_Disconnected(TcpTouchRpcSocketClient client, TouchSocketEventArgs e)
{
lock (this)
{
this.listBox2.Items.Remove(client.ID);
}
}
private void TcpRpcParser_Handshaked(TcpTouchRpcSocketClient client, TouchSocketEventArgs e)
{
Debug.WriteLine("Handshaked");
this.listBox2.Items.Add(client.ID);
}
public void ShowMsg(string msg)
{
this.Invoke((Action)(delegate () { this.textBox1.AppendText(msg + "\r\n"); }));
}
private TcpTouchRpcService tcpRpcService;
private void button1_Click(object sender, EventArgs e)
{
try
{
AccessType accessType = AccessType.Owner;
if (this.checkBox1.Checked)
{
accessType = accessType | AccessType.Owner;
}
if (this.checkBox2.Checked)
{
accessType = accessType | AccessType.Service;
}
if (this.checkBox3.Checked)
{
accessType = accessType | AccessType.Everyone;
}
if (this.checkBox4.Checked)
{
this.tcpRpcService.PublishEvent(this.textBox2.Text, accessType);
this.ShowMsg("发布成功");
}
else if (this.listBox2.SelectedItem is string id)
{
if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient))
{
socketClient.PublishEvent(this.textBox2.Text, accessType);
this.ShowMsg("发布成功");
}
else
{
this.ShowMsg("没有找到对应客户端");
}
}
else
{
this.ShowMsg("请选择一个客户端ID");
}
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void button2_Click(object sender, EventArgs e)
{
string[] events = this.tcpRpcService.GetAllEvents();
this.listBox1.Items.Clear();
this.listBox1.Items.AddRange(events);
}
private void button3_Click(object sender, EventArgs e)
{
try
{
if (this.checkBox4.Checked)
{
this.tcpRpcService.SubscribeEvent<string>(this.textBox3.Text, this.SubscribeEvent);
this.ShowMsg("订阅成功");
}
else if (this.listBox2.SelectedItem is string id)
{
if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient))
{
socketClient.SubscribeEvent<string>(this.textBox3.Text, this.SubscribeEvent);
this.ShowMsg("订阅成功");
}
else
{
this.ShowMsg("没有找到对应客户端");
}
}
else
{
this.ShowMsg("请选择一个客户端ID");
}
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void SubscribeEvent(EventSender eventSender, string arg)
{
this.ShowMsg($"从{eventSender.RaiseSourceType}收到通知事件{eventSender.EventName},信息:{arg}");
}
private void button4_Click(object sender, EventArgs e)
{
try
{
if (this.listBox1.SelectedItem is string eventName)
{
if (this.checkBox4.Checked)
{
this.tcpRpcService.RaiseEvent(eventName, this.textBox4.Text);
this.ShowMsg("触发成功");
}
else if (this.listBox2.SelectedItem is string id)
{
if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient))
{
socketClient.RaiseEvent(eventName, this.textBox4.Text);
this.ShowMsg("触发成功");
}
else
{
this.ShowMsg("没有找到对应客户端");
}
}
else
{
this.ShowMsg("请选择一个客户端ID");
}
}
else
{
this.ShowMsg("请先选择事件");
}
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void button5_Click(object sender, EventArgs e)
{
try
{
if (this.checkBox4.Checked)
{
this.tcpRpcService.UnsubscribeEvent(this.textBox3.Text);
this.ShowMsg("取消订阅成功");
}
else if (this.listBox2.SelectedItem is string id)
{
if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient))
{
socketClient.UnsubscribeEvent(this.textBox3.Text);
this.ShowMsg("取消订阅成功");
}
else
{
this.ShowMsg("没有找到对应客户端");
}
}
else
{
this.ShowMsg("请选择一个客户端ID");
}
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void button6_Click(object sender, EventArgs e)
{
try
{
if (this.checkBox4.Checked)
{
this.tcpRpcService.UnpublishEvent(this.textBox2.Text);
this.ShowMsg("取消发布成功");
}
else if (this.listBox2.SelectedItem is string id)
{
if (this.tcpRpcService.TryGetSocketClient(id, out TcpTouchRpcSocketClient socketClient))
{
socketClient.UnpublishEvent(this.textBox2.Text);
this.ShowMsg("取消发布成功");
}
else
{
this.ShowMsg("没有找到对应客户端");
}
}
else
{
this.ShowMsg("请选择一个客户端ID");
}
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void button7_Click(object sender, EventArgs e)
{
this.textBox1.Clear();
}
private bool TryGetSelectedClient(out TcpTouchRpcSocketClient socketClient)
{
if (this.listBox2.SelectedItem is string id)
{
if (this.tcpRpcService.TryGetSocketClient(id, out socketClient))
{
return true;
}
else
{
this.ShowMsg("没有找到对应客户端");
return false;
}
}
else
{
this.ShowMsg("请选择一个客户端ID");
}
socketClient = null;
return false;
}
private void button8_Click(object sender, EventArgs e)
{
if (this.TryGetSelectedClient(out TcpTouchRpcSocketClient client))
{
var time = client.Invoke<DateTime>("GetDataTime", default);
this.ShowMsg(time.ToString());
}
}
private void button9_Click(object sender, EventArgs e)
{
if (this.listBox2.SelectedItem is string id)
{
var time = this.tcpRpcService.Invoke<DateTime>(id, "GetDataTime", default);
this.ShowMsg(time.ToString());
}
else
{
this.ShowMsg("请选择一个客户端ID");
}
}
}
}

View File

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

View File

@@ -1,32 +0,0 @@
//------------------------------------------------------------------------------
// 此代码版权除特别声明或在RRQMCore.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://www.yuque.com/eo2w71/rrqm
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Windows.Forms;
namespace EERPCServiceDemo
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,55 +0,0 @@
using System;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace FileServiceConsoleApp
{
class Program
{
static void Main(string[] args)
{
TcpTouchRpcService service = GetService();
service.Logger.Info("服务器成功启动");
Console.ReadKey();
}
static TcpTouchRpcService GetService()
{
var service = new TouchSocketConfig()//配置
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.SetSingletonLogger<LoggerGroup<ConsoleLogger, FileLogger>>();
})
.SetVerifyToken("File")//连接验证口令。
.BuildWithTcpTouchRpcService();//此处build相当于new TcpTouchRpcService然后Setup然后Start。
service.Handshaked += (client, e) =>
{
client.Logger.Info($"有客户端成功验证ID={client.ID}");
};
service.Disconnected += (client, e) =>
{
client.Logger.Info($"有客户端断开ID={client.ID}");
};
service.FileTransfering += (client, e) =>
{
//有可能是上传,也有可能是下载
client.Logger.Info($"有客户端请求传输文件ID={client.ID},请求类型={e.TransferType},请求文件名={e.FileRequest.Path}");
};
service.FileTransfered += (client, e) =>
{
//传输结束但是不一定成功需要从e.Result判断状态。
client.Logger.Info($"客户端传输文件结束ID={client.ID},请求类型={e.TransferType},文件名={e.FileRequest.Path},请求状态={e.Result}");
};
return service;
}
}
}

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,68 +0,0 @@
using System;
using TouchSocket.Core;
using TouchSocket.Core.Config;
using TouchSocket.Core.Log;
using TouchSocket.Core.Run;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace FileClientConsoleApp
{
class Program
{
static void Main(string[] args)
{
TcpTouchRpcClient client = new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.SetVerifyToken("File")
.BuildWithTcpTouchRpcClient();
client.FileTransfering += (client, e) =>
{
//有可能是上传,也有可能是下载
client.Logger.Info($"服务器请求传输文件ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName}");
};
client.FileTransfered += (client, e) =>
{
//传输结束但是不一定成功需要从e.Result判断状态。
client.Logger.Info($"服务器传输文件结束ID={client.ID},请求类型={e.TransferType},文件名={e.FileInfo.FileName},请求状态={e.Result}");
};
client.Logger.Info("连接成功");
//第一个参数是请求路径,第二个是保存路径。
FileRequest fileRequest = new FileRequest(@"D:\System\Windows.iso", $@"Windows.iso");
fileRequest.Flags = TransferFlags.BreakpointResume;//尝试断点续传使用断点续传时会验证MD5值
FileOperator fileOperator = new FileOperator();//实例化本次传输的控制器,用于获取传输进度、速度、状态等。
fileOperator.Timeout = 60 * 1000;//当传输大文件且启用断点续传时服务器可能会先计算MD5而延时响应所以需要设置超时时间。
//此处的作用相当于Timer定时每秒输出当前的传输进度和速度。
LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
{
if (fileOperator.Result.ResultCode != ResultCode.Default)
{
loop.Dispose();
}
client.Logger.Info($"进度:{fileOperator.Progress},速度:{fileOperator.Speed()}");
});
loopAction.RunAsync();
Metadata metadata = new Metadata();//传递到服务器的元数据
metadata.Add("1", "1");
metadata.Add("2", "2");
//此方法会阻塞直到传输结束也可以使用PullFileAsync
IResult result = client.PullFile(fileRequest, fileOperator, metadata);
client.Logger.Info(result.ToString());
Console.ReadKey();
}
}
}

View File

@@ -1,6 +0,0 @@
<Application x:Class="FileClientGUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources />
</Application>

View File

@@ -1,28 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Windows;
namespace FileClientGUI
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
new MainWindow().Show();
base.OnStartup(e);
}
}
}

View File

@@ -1,22 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net45</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\Images\完成.png" />
<None Remove="Resources\Images\未完成.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="RRQMSkin" Version="4.0.0" />
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Images\完成.png" />
<Resource Include="Resources\Images\未完成.png" />
</ItemGroup>
</Project>

View File

@@ -1,112 +0,0 @@
<Window x:Class="FileClientGUI.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="RRQM_Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FileClientGUI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="客户端" Width="800"
Height="600" mc:Ignorable="d">
<Window.Resources>
<Style x:Key="ListBox_Transfer" TargetType="ListBox">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="border" Height="40" Margin="2" BorderBrush="Transparent" BorderThickness="1"
CornerRadius="3"
ToolTip="{Binding Mes}">
<Grid Margin="3" Background="#92BCE1">
<Grid.RowDefinitions>
<RowDefinition Height="7*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<ProgressBar Grid.RowSpan="2" Background="Transparent" BorderThickness="0" Foreground="#43E17C" Maximum="1"
Value="{Binding Progress}" />
<TextBlock Margin="5,0,0,0" VerticalAlignment="Center" FontSize="15" FontWeight="Bold"
Text="{Binding FileName}" />
<TextBlock Grid.Row="1" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="10" Foreground="#70779D"
Text="{Binding FilePath}" />
<StackPanel Grid.RowSpan="2" Margin="0,0,5,0" HorizontalAlignment="Right" VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock Width="70" VerticalAlignment="Center"
Text="{Binding TransferType}" />
<TextBlock Width="70" VerticalAlignment="Center"
Text="{Binding FileLength}" />
<TextBlock Width="70" VerticalAlignment="Center"
Text="{Binding Speed}" />
<Image Width="30" Height="30" HorizontalAlignment="Center" VerticalAlignment="Center"
Source="{Binding Status}" />
</StackPanel>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="#0AE459" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="#2E8CEF" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<GroupBox Margin="5" Header="功能区">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="cb_resume" VerticalContentAlignment="Center" Content="断点续传" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Width="70" Height="30" Margin="5,0" Click="ConButton_Click" Content="连接" />
<Button Width="70" Height="30" Margin="5,0" Click="Button_Click_1" Content="Push" />
<Button Width="70" Height="30" Margin="5,0" Click="Button_Click_2" Content="Pull" />
<Button Width="70" Height="30" Margin="5,0" Click="Button_Click_4" Content="发送协议" />
</StackPanel>
</Grid>
</GroupBox>
<GroupBox Grid.Column="1" Margin="5" Header="传输控制">
<StackPanel Grid.ColumnSpan="3" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Text="传输限速:" />
<controls:InputBox Width="100" VerticalAlignment="Center" InputFilter="Uint" TextChanged="InputBox_TextChanged" />
<Button Margin="10,0,0,0" VerticalAlignment="Center" Click="Button_Click" Content="取消传输" />
<Button Margin="10,0,0,0" VerticalAlignment="Center" Click="PingButton_Click" Content="Ping" />
</StackPanel>
</GroupBox>
<GroupBox Grid.Row="1" Grid.ColumnSpan="2" Margin="5" Header="当前队列">
<ListBox x:Name="ListBox_LocalTransfer" SelectionChanged="ListBox_SelectionChanged"
Style="{StaticResource ListBox_Transfer}" />
</GroupBox>
<GroupBox Grid.Row="2" Grid.ColumnSpan="2" Margin="5" Header="远程队列">
<ListBox x:Name="ListBox_RemoteTransfer" SelectionChanged="ListBox_SelectionChanged"
Style="{StaticResource ListBox_Transfer}" />
</GroupBox>
<GroupBox Grid.Row="3" Grid.ColumnSpan="3" Margin="5" Background="AliceBlue" Header="日志">
<TextBox x:Name="msgBox" Background="Transparent" BorderThickness="0" />
</GroupBox>
</Grid>
</Window>

View File

@@ -1,265 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using FileClientGUI.Models;
using FileClientGUI.Win;
using RRQMSkin.MVVM;
using System;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using TouchSocket.Core;
using TouchSocket.Core.ByteManager;
using TouchSocket.Core.Config;
using TouchSocket.Core.IO;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace FileClientGUI
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += this.MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
this.remoteModels = new RRQMList<TransferModel>();
this.localModels = new RRQMList<TransferModel>();
this.ListBox_RemoteTransfer.ItemsSource = this.remoteModels;
this.ListBox_LocalTransfer.ItemsSource = this.localModels;
}
private RRQMList<TransferModel> remoteModels;
private RRQMList<TransferModel> localModels;
private void ShowMsg(string msg)
{
this.UIInvoke(() =>
{
this.msgBox.AppendText($"{msg}\r\n");
});
}
private void UIInvoke(Action action)
{
this.Dispatcher.Invoke(() =>
{
action.Invoke();
});
}
private TcpTouchRpcClient fileClient;
private static int id = 0;
private void ConButton_Click(object sender, RoutedEventArgs e)
{
fileClient = new TcpTouchRpcClient();
fileClient.FileTransfering += this.FileClient_BeforeFileTransfer;
fileClient.Received += FileClient_Received;
fileClient.Disconnected += this.FileClient_Disconnected;
fileClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost(new IPHost("127.0.0.1:7789"))
.SetVerifyToken("FileService"));
try
{
fileClient.Connect();
((Button)sender).IsEnabled = false;
fileClient.ResetID((++id).ToString());
ShowMsg($"连接成功ID={this.fileClient.ID}");
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void FileClient_Disconnected(ITcpClientBase client, ClientDisconnectedEventArgs e)
{
}
private void FileClient_Received(TcpTouchRpcClient client, short protocol, ByteBlock byteBlock)
{
ShowMsg($"收到数据:协议={protocol},数据长度:{byteBlock.Len - 2}");
}
private void FileClient_BeforeFileTransfer(TcpTouchRpcClient client, FileOperationEventArgs e)
{
TransferModel model = new TransferModel();
model.FileOperator = e.FileOperator;
model.TransferType = e.TransferType;
switch (e.TransferType)
{
case TransferType.Push:
model.FilePath = e.FileRequest.SavePath;
model.FileLength = FileUtility.ToFileLengthString(e.FileInfo.FileLength);
break;
case TransferType.Pull:
model.FilePath = e.FileRequest.Path;
model.FileLength = FileUtility.ToFileLengthString(new FileInfo(e.FileRequest.Path).Length);
break;
default:
break;
}
model.Start();
UIInvoke(() =>
{
this.remoteModels.Add(model);
});
}
private TransferModel transferModel;
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (((ListBox)sender).SelectedItem is TransferModel transferModel)
{
this.transferModel = transferModel;
}
}
private void InputBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (transferModel == null || transferModel.FileOperator.Result.ResultCode != ResultCode.Default)
{
MessageBox.Show("请选择一个条目,然后控制。");
return;
}
try
{
if (string.IsNullOrEmpty(((TextBox)sender).Text))
{
return;
}
//this.transferModel.FileOperator.SetMaxSpeed(int.Parse(((TextBox)sender).Text));
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
PushWindow pushWindow = new PushWindow();
if (pushWindow.SelectRequest(out FileRequest fileRequest, out string clientID))
{
if (this.cb_resume.IsChecked == true)
{
fileRequest.Flags = TransferFlags.BreakpointResume;
}
FileOperator fileOperator = new FileOperator();
//fileOperator.SetMaxSpeed(10240);
FileInfo fileInfo = new FileInfo(fileRequest.Path);
TransferModel model = new TransferModel()
{
FileLength = FileUtility.ToFileLengthString(fileInfo.Length),
FilePath = fileRequest.Path,
FileOperator = fileOperator,
TransferType = TransferType.Push
};
model.Start();
this.localModels.Add(model);
if (string.IsNullOrEmpty(clientID))
{
this.fileClient.PushFileAsync(fileRequest, fileOperator);
}
else
{
this.fileClient.PushFileAsync(clientID, fileRequest, fileOperator);
}
}
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
PullWindow pullWindow = new PullWindow();
if (pullWindow.SelectRequest(out FileRequest fileRequest, out string clientID))
{
if (this.cb_resume.IsChecked == true)
{
fileRequest.Flags = TransferFlags.BreakpointResume;
}
FileOperator fileOperator = new FileOperator();
TransferModel model = new TransferModel()
{
FileLength = "未知",
FilePath = fileRequest.Path,
FileOperator = fileOperator,
TransferType = TransferType.Pull
};
model.Start();
this.localModels.Add(model);
if (string.IsNullOrEmpty(clientID))
{
this.fileClient.PullFileAsync(fileRequest, fileOperator);
}
else
{
this.fileClient.PullFileAsync(clientID, fileRequest, fileOperator);
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//取消
if (transferModel == null || transferModel.FileOperator.Result.ResultCode != ResultCode.Default)
{
MessageBox.Show("请选择一个条目,然后控制。");
return;
}
try
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
this.transferModel.FileOperator.Token = tokenSource.Token;
tokenSource.Cancel();
}
catch (Exception ex)
{
ShowMsg(ex.Message);
}
}
private void Button_Click_4(object sender, RoutedEventArgs e)
{
this.fileClient.Send(10, new byte[] { 1, 2, 3 });
}
private void PingButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(this.fileClient.Ping().ToString());
}
}
}

View File

@@ -1,98 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using TouchSocket.Core;
using TouchSocket.Core.IO;
using TouchSocket.Core.Run;
using TouchSocket.Rpc.TouchRpc;
namespace FileClientGUI.Models
{
public class TransferModel : RRQMSkin.MVVM.ObservableObject
{
public string FileName { get => string.IsNullOrEmpty(FilePath) ? null : Path.GetFileName(FilePath); }
public string FilePath { get; set; }
public string FileLength { get; set; }
private string speed;
public string Speed
{
get { return speed; }
set { SetProperty(ref speed, value); }
}
private float progress;
public float Progress
{
get { return progress; }
set { SetProperty(ref progress, value); }
}
private ImageSource status;
public ImageSource Status
{
get { return status; }
set { SetProperty(ref status, value); }
}
public FileOperator FileOperator { get; set; }
public TransferType TransferType { get; set; }
private string mes;
public string Mes
{
get { return mes; }
set { SetProperty(ref mes, value); }
}
public void Start()
{
LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
{
if (this.FileOperator.Result.ResultCode == ResultCode.Default)
{
this.Progress = this.FileOperator.Progress;
this.Speed = FileUtility.ToFileLengthString(this.FileOperator.Speed());
}
else if (this.FileOperator.Result.ResultCode == ResultCode.Success)
{
UIInvoke(() =>
{
this.Status = new BitmapImage(new Uri("Resources/Images/完成.png", UriKind.RelativeOrAbsolute));
});
this.Progress = 1;
loop.Dispose();
}
else
{
UIInvoke(() =>
{
this.Status = new BitmapImage(new Uri("Resources/Images/未完成.png", UriKind.RelativeOrAbsolute));
});
this.Mes = this.FileOperator.Result.ToString();
loop.Dispose();
}
});
loopAction.RunAsync();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,32 +0,0 @@
<Window x:Class="FileClientGUI.Win.PullWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FileClientGUI.Win"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="PullWindow"
Width="500" Height="170" mc:Ignorable="d">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Text="请求路径:" />
<TextBox x:Name="tb1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" TextChanged="tb1_TextChanged" />
<TextBlock Grid.Row="1" VerticalAlignment="Center" Text="保存路径:" />
<TextBox x:Name="tb2" Grid.Row="1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" Text="互传ID" />
<TextBox x:Name="tb3" Grid.Row="2" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<Button Grid.Row="3" Grid.ColumnSpan="3" Width="100" Height="30" Click="Button_Click"
Content="确定" />
</Grid>
</Window>

View File

@@ -1,58 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Windows;
using System.Windows.Controls;
using TouchSocket.Rpc.TouchRpc;
namespace FileClientGUI.Win
{
/// <summary>
/// PullWindow.xaml 的交互逻辑
/// </summary>
public partial class PullWindow : Window
{
public PullWindow()
{
InitializeComponent();
}
public bool SelectRequest(out FileRequest fileRequest, out string clientID)
{
this.ShowDialog();
fileRequest = this.fileRequest;
clientID = this.clientID;
return this.go;
}
private void tb1_TextChanged(object sender, TextChangedEventArgs e)
{
this.tb2.Text = System.IO.Path.GetFileName(this.tb1.Text);
}
private FileRequest fileRequest;
private bool go;
private string clientID;
private void Button_Click(object sender, RoutedEventArgs e)
{
fileRequest = new FileRequest()
{
Path = this.tb1.Text,
SavePath = this.tb2.Text
};
this.clientID = this.tb3.Text;
this.go = true;
this.Close();
}
}
}

View File

@@ -1,32 +0,0 @@
<Window x:Class="FileClientGUI.Win.PushWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="PushWindow"
Width="500" Height="170" mc:Ignorable="d">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Text="选择文件:" />
<TextBox x:Name="tb1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<Button Grid.Column="2" Width="30" VerticalAlignment="Center" Click="Button_Click_1" Content="..." />
<TextBlock Grid.Row="1" VerticalAlignment="Center" Text="保存路径:" />
<TextBox x:Name="tb2" Grid.Row="1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<TextBlock Grid.Row="2" VerticalAlignment="Center" Text="互传ID" />
<TextBox x:Name="tb3" Grid.Row="2" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<Button Grid.Row="3" Grid.ColumnSpan="3" Width="100" Height="30" Click="Button_Click"
Content="确定" />
</Grid>
</Window>

View File

@@ -1,64 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using Microsoft.Win32;
using System.Windows;
using TouchSocket.Rpc.TouchRpc;
namespace FileClientGUI.Win
{
/// <summary>
/// PushWindow.xaml 的交互逻辑
/// </summary>
public partial class PushWindow : Window
{
public PushWindow()
{
InitializeComponent();
}
public bool SelectRequest(out FileRequest fileRequest, out string clientID)
{
this.ShowDialog();
fileRequest = this.fileRequest;
clientID = this.clientID;
return this.go;
}
private FileRequest fileRequest;
private bool go;
private string clientID;
private void Button_Click(object sender, RoutedEventArgs e)
{
fileRequest = new FileRequest()
{
Path = this.tb1.Text,
SavePath = this.tb2.Text
};
this.go = true;
this.clientID = this.tb3.Text;
this.Close();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.ShowDialog();
if (!string.IsNullOrEmpty(dialog.FileName))
{
this.tb1.Text = dialog.FileName;
this.tb2.Text = System.IO.Path.GetFileName(dialog.FileName);
}
}
}
}

View File

@@ -1,4 +0,0 @@
<Application x:Class="FileServiceGUI.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml">
<Application.Resources />
</Application>

View File

@@ -1,23 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Windows;
namespace FileServiceGUI
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
}
}

View File

@@ -1,22 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net45</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\Images\完成.png" />
<None Remove="Resources\Images\未完成.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="RRQMSkin" Version="4.0.0" />
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Images\完成.png" />
<Resource Include="Resources\Images\未完成.png" />
</ItemGroup>
</Project>

View File

@@ -1,115 +0,0 @@
<Window x:Class="FileServiceGUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="RRQM_Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FileServiceGUI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="服务器" Width="800"
Height="600" mc:Ignorable="d">
<Window.Resources>
<Style x:Key="ListBox_Transfer" TargetType="ListBox">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="border" Height="40" Margin="2" BorderBrush="Transparent" BorderThickness="1"
CornerRadius="3"
ToolTip="{Binding Mes}">
<Grid Margin="3" Background="#92BCE1">
<Grid.RowDefinitions>
<RowDefinition Height="7*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<ProgressBar Grid.RowSpan="2" Background="Transparent" BorderThickness="0" Foreground="#43E17C" Maximum="1"
Value="{Binding Progress}" />
<TextBlock Margin="5,0,0,0" VerticalAlignment="Center" FontSize="15" FontWeight="Bold"
Text="{Binding FileName}" />
<TextBlock Grid.Row="1" Margin="5,0,0,0" VerticalAlignment="Center" FontSize="10" Foreground="#70779D"
Text="{Binding FilePath}" />
<StackPanel Grid.RowSpan="2" Margin="0,0,5,0" HorizontalAlignment="Right" VerticalAlignment="Center"
Orientation="Horizontal">
<TextBlock Width="70" VerticalAlignment="Center"
Text="{Binding TransferType}" />
<TextBlock Width="70" VerticalAlignment="Center"
Text="{Binding FileLength}" />
<TextBlock Width="70" VerticalAlignment="Center"
Text="{Binding Speed}" />
<Image Width="30" Height="30" HorizontalAlignment="Center" VerticalAlignment="Center"
Source="{Binding Status}" />
</StackPanel>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="#0AE459" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="#2E8CEF" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition />
<RowDefinition />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<GroupBox Margin="5" Header="功能区">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="cb_resume" VerticalContentAlignment="Center" Content="断点续传" />
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Width="70" Height="30" Margin="5,0" Click="Button_Click_1" Content="Push" />
<Button Width="70" Height="30" Margin="5,0,5,2" VerticalAlignment="Bottom" Click="Button_Click_2"
Content="Pull" />
</StackPanel>
</Grid>
</GroupBox>
<GroupBox Grid.Column="1" Margin="5" Header="传输控制">
<StackPanel Grid.ColumnSpan="3" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Text="传输限速:" />
<controls:InputBox Width="100" VerticalAlignment="Center" InputFilter="Uint" TextChanged="InputBox_TextChanged" />
<Button Margin="10,0,0,0" VerticalAlignment="Center" Click="Button_Click" Content="取消传输" />
</StackPanel>
</GroupBox>
<GroupBox Grid.Row="1" Grid.RowSpan="2" Margin="5" Header="在线客户端">
<ListBox x:Name="ListBox_Clients" BorderThickness="0" DisplayMemberPath="ID" />
</GroupBox>
<GroupBox Grid.Row="1" Grid.Column="2" Margin="5" Header="当前队列">
<ListBox x:Name="ListBox_LocalTransfer" SelectionChanged="ListBox_SelectionChanged"
Style="{StaticResource ListBox_Transfer}" />
</GroupBox>
<GroupBox Grid.Row="2" Grid.Column="2" Margin="5" Header="远程队列">
<ListBox x:Name="ListBox_RemoteTransfer" SelectionChanged="ListBox_SelectionChanged"
Style="{StaticResource ListBox_Transfer}" />
</GroupBox>
<GroupBox Grid.Row="3" Grid.ColumnSpan="3" Margin="5" Background="AliceBlue" Header="日志">
<TextBox x:Name="msgBox" Background="Transparent" BorderThickness="0" />
</GroupBox>
</Grid>
</Window>

View File

@@ -1,282 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using FileServiceGUI.Models;
using FileServiceGUI.Win;
using RRQMSkin.MVVM;
using System;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using TouchSocket.Core;
using TouchSocket.Core.ByteManager;
using TouchSocket.Core.Config;
using TouchSocket.Core.IO;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace FileServiceGUI
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.Loaded += this.MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
this.clients = new RRQMList<TcpTouchRpcSocketClient>();
this.remoteModels = new RRQMList<TransferModel>();
this.localModels = new RRQMList<TransferModel>();
this.ListBox_Clients.ItemsSource = this.clients;
this.ListBox_RemoteTransfer.ItemsSource = this.remoteModels;
this.ListBox_LocalTransfer.ItemsSource = this.localModels;
this.Start();
}
private RRQMList<TcpTouchRpcSocketClient> clients;
private RRQMList<TransferModel> remoteModels;
private RRQMList<TransferModel> localModels;
private void ShowMsg(string msg)
{
this.UIInvoke(() =>
{
this.msgBox.AppendText($"{msg}\r\n");
});
}
private void UIInvoke(Action action)
{
this.Dispatcher.Invoke(() =>
{
action.Invoke();
});
}
private TcpTouchRpcService fileService;
private void Start()
{
//启动
if (this.fileService != null)
{
return;
}
this.fileService = new TcpTouchRpcService();
this.fileService.Received += this.FileService_Received;
this.fileService.Connected += this.FileService_Connected;
this.fileService.Disconnected += this.FileService_Disconnected;
this.fileService.FileTransfering += this.FileService_FileTransfering;
var config = new TouchSocketConfig();
config.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.SetVerifyToken("FileService");
try
{
this.fileService.Setup(config);
this.fileService.Start();
this.ShowMsg("启动成功");
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void FileService_Received(TcpTouchRpcSocketClient socketClient, short protocol, ByteBlock byteBlock)
{
this.ShowMsg($"收到数据:协议={protocol},数据长度:{byteBlock.Len - 2}");
if (protocol == -1)
{
socketClient.Send(byteBlock.ToArray(2));
}
else
{
socketClient.Send(protocol, byteBlock.ToArray(2));
}
}
private void FileService_FileTransfering(TcpTouchRpcSocketClient client, FileOperationEventArgs e)
{
TransferModel model = new TransferModel();
model.FileOperator = e.FileOperator;
model.TransferType = e.TransferType;
switch (e.TransferType)
{
case TransferType.Push:
model.FilePath = e.FileRequest.SavePath;
model.FileLength = FileUtility.ToFileLengthString(e.FileInfo.FileLength);
break;
case TransferType.Pull:
model.FilePath = e.FileRequest.Path;
model.FileLength = FileUtility.ToFileLengthString(new FileInfo(e.FileRequest.Path).Length);
break;
default:
break;
}
model.Start();
this.UIInvoke(() =>
{
this.remoteModels.Add(model);
});
}
private void FileService_Disconnected(TcpTouchRpcSocketClient client, TouchSocketEventArgs e)
{
this.UIInvoke(() =>
{
this.clients.Remove(client);
});
}
private void FileService_Connected(TcpTouchRpcSocketClient client, TouchSocketEventArgs e)
{
this.UIInvoke(() =>
{
this.clients.Add(client);
});
}
private TransferModel transferModel;
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (((ListBox)sender).SelectedItem is TransferModel transferModel)
{
this.transferModel = transferModel;
}
}
private void InputBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (this.transferModel == null || this.transferModel.FileOperator.Result.ResultCode != ResultCode.Default)
{
MessageBox.Show("请选择一个条目,然后控制。");
return;
}
try
{
if (string.IsNullOrEmpty(((TextBox)sender).Text))
{
return;
}
//this.transferModel.FileOperator.SetMaxSpeed(int.Parse(((TextBox)sender).Text));
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//取消
if (this.transferModel == null || this.transferModel.FileOperator.Result.ResultCode != ResultCode.Default)
{
MessageBox.Show("请选择一个条目,然后控制。");
return;
}
try
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
this.transferModel.FileOperator.Token = tokenSource.Token;
tokenSource.Cancel();
}
catch (Exception ex)
{
this.ShowMsg(ex.Message);
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
//Push
if (this.ListBox_Clients.SelectedItem is TcpTouchRpcSocketClient client)
{
PushWindow pushWindow = new PushWindow();
if (pushWindow.SelectRequest(out FileRequest fileRequest))
{
if (this.cb_resume.IsChecked == true)
{
fileRequest.Flags = TransferFlags.BreakpointResume;
}
FileOperator fileOperator = new FileOperator();
FileInfo fileInfo = new FileInfo(fileRequest.Path);
TransferModel model = new TransferModel()
{
FileLength = FileUtility.ToFileLengthString(fileInfo.Length),
FilePath = fileRequest.Path,
FileOperator = fileOperator,
TransferType = TransferType.Push
};
model.Start();
this.localModels.Add(model);
client.PushFileAsync(fileRequest, fileOperator);
}
}
else
{
MessageBox.Show("请选择一个客户端");
}
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
//Pull
if (this.ListBox_Clients.SelectedItem is TcpTouchRpcSocketClient client)
{
PullWindow pullWindow = new PullWindow();
if (pullWindow.SelectRequest(out FileRequest fileRequest))
{
if (this.cb_resume.IsChecked == true)
{
fileRequest.Flags = TransferFlags.BreakpointResume;
}
FileOperator fileOperator = new FileOperator();
TransferModel model = new TransferModel()
{
FileLength = "未知",
FilePath = fileRequest.Path,
FileOperator = fileOperator,
TransferType = TransferType.Pull
};
model.Start();
this.localModels.Add(model);
client.PullFileAsync(fileRequest, fileOperator);
}
}
else
{
MessageBox.Show("请选择一个客户端");
}
}
}
}

View File

@@ -1,98 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using TouchSocket.Core;
using TouchSocket.Core.IO;
using TouchSocket.Core.Run;
using TouchSocket.Rpc.TouchRpc;
namespace FileServiceGUI.Models
{
public class TransferModel : RRQMSkin.MVVM.ObservableObject
{
public string FileName => string.IsNullOrEmpty(this.FilePath) ? null : Path.GetFileName(this.FilePath);
public string FilePath { get; set; }
public string FileLength { get; set; }
private string speed;
public string Speed
{
get => this.speed;
set => this.SetProperty(ref this.speed, value);
}
private float progress;
public float Progress
{
get => this.progress;
set => this.SetProperty(ref this.progress, value);
}
private ImageSource status;
public ImageSource Status
{
get => this.status;
set => this.SetProperty(ref this.status, value);
}
public FileOperator FileOperator { get; set; }
public TransferType TransferType { get; set; }
private string mes;
public string Mes
{
get => this.mes;
set => this.SetProperty(ref this.mes, value);
}
public void Start()
{
LoopAction loopAction = LoopAction.CreateLoopAction(-1, 1000, (loop) =>
{
if (this.FileOperator.Result.ResultCode == ResultCode.Default)
{
this.Progress = this.FileOperator.Progress;
this.Speed = FileUtility.ToFileLengthString(this.FileOperator.Speed());
}
else if (this.FileOperator.Result.ResultCode == ResultCode.Success)
{
App.Current.Dispatcher.Invoke(() =>
{
this.Status = new BitmapImage(new Uri("Resources/Images/完成.png", UriKind.RelativeOrAbsolute));
});
this.Progress = 1;
loop.Dispose();
}
else
{
App.Current.Dispatcher.Invoke(() =>
{
this.Status = new BitmapImage(new Uri("Resources/Images/未完成.png", UriKind.RelativeOrAbsolute));
});
this.Mes = this.FileOperator.Result.ToString();
loop.Dispose();
}
});
loopAction.RunAsync();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,27 +0,0 @@
<Window x:Class="FileServiceGUI.Win.PullWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="PullWindow"
Width="500" Height="170" mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Text="请求路径:" />
<TextBox x:Name="tb1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" TextChanged="tb1_TextChanged" />
<TextBlock Grid.Row="1" VerticalAlignment="Center" Text="文件保存路径:" />
<TextBox x:Name="tb2" Grid.Row="1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<Button Grid.Row="2" Grid.ColumnSpan="3" Width="100" Height="30" Click="Button_Click"
Content="确定" />
</Grid>
</Window>

View File

@@ -1,55 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Windows;
using System.Windows.Controls;
using TouchSocket.Rpc.TouchRpc;
namespace FileServiceGUI.Win
{
/// <summary>
/// PullWindow.xaml 的交互逻辑
/// </summary>
public partial class PullWindow : Window
{
public PullWindow()
{
this.InitializeComponent();
}
public bool SelectRequest(out FileRequest fileRequest)
{
this.ShowDialog();
fileRequest = this.fileRequest;
return this.go;
}
private void tb1_TextChanged(object sender, TextChangedEventArgs e)
{
this.tb2.Text = System.IO.Path.GetFileName(this.tb1.Text);
}
private FileRequest fileRequest;
private bool go;
private void Button_Click(object sender, RoutedEventArgs e)
{
this.fileRequest = new FileRequest()
{
Path = this.tb1.Text,
SavePath = this.tb2.Text
};
this.go = true;
this.Close();
}
}
}

View File

@@ -1,29 +0,0 @@
<Window x:Class="FileServiceGUI.Win.PushWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FileServiceGUI.Win"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="PushWindow"
Width="509" Height="172" mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Text="选择文件:" />
<TextBox x:Name="tb1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<Button Grid.Column="2" Width="30" VerticalAlignment="Center" Click="Button_Click_1" Content="..." />
<TextBlock Grid.Row="1" VerticalAlignment="Center" Text="文件保存路径:" />
<TextBox x:Name="tb2" Grid.Row="1" Grid.Column="1" Margin="10,0" VerticalAlignment="Center" />
<Button Grid.Row="2" Grid.ColumnSpan="3" Width="100" Height="30" Click="Button_Click"
Content="确定" />
</Grid>
</Window>

View File

@@ -1,61 +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://www.yuque.com/rrqm/touchsocket/index
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using Microsoft.Win32;
using System.Windows;
using TouchSocket.Rpc.TouchRpc;
namespace FileServiceGUI.Win
{
/// <summary>
/// PushWindow.xaml 的交互逻辑
/// </summary>
public partial class PushWindow : Window
{
public PushWindow()
{
this.InitializeComponent();
}
public bool SelectRequest(out FileRequest fileRequest)
{
this.ShowDialog();
fileRequest = this.fileRequest;
return this.go;
}
private FileRequest fileRequest;
private bool go;
private void Button_Click(object sender, RoutedEventArgs e)
{
this.fileRequest = new FileRequest()
{
Path = this.tb1.Text,
SavePath = this.tb2.Text
};
this.go = true;
this.Close();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.ShowDialog();
if (!string.IsNullOrEmpty(dialog.FileName))
{
this.tb1.Text = dialog.FileName;
this.tb2.Text = System.IO.Path.GetFileName(dialog.FileName);
}
}
}
}

View File

@@ -1,70 +0,0 @@
using System;
using TouchSocket.Core;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Log;
using TouchSocket.Core.Plugins;
using TouchSocket.Http;
using TouchSocket.Http.Plugins;
using TouchSocket.Http.WebSockets;
using TouchSocket.Http.WebSockets.Plugins;
using TouchSocket.Sockets;
namespace ConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
//证书在RRQMBox/Ssl证书相关/证书生成.zip 解压获取。
//然后放在运行目录。
//最后客户端需要先安装证书。
var service = new HttpService();
service.Setup(new TouchSocketConfig()//加载配置
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7789) })
.ConfigureContainer(a =>
{
a.SetSingletonLogger<ConsoleLogger>();
})
.ConfigurePlugins(a =>
{
a.Add<MyHttpPlug>();
}))
.Start();
Console.WriteLine("Http服务器已启动");
Console.WriteLine("访问 http://127.0.0.1:7789/success 返回响应");
Console.WriteLine("访问 http://127.0.0.1:7789/file 响应文件");
Console.ReadKey();
}
}
/// <summary>
/// 支持GET、Post、PutDelete或者其他
/// </summary>
internal class MyHttpPlug : HttpPluginBase
{
protected override void OnGet(ITcpClientBase client, HttpContextEventArgs e)
{
if (e.Context.Request.UrlEquals("/success"))
{
e.Context.Response.FromText("Success").Answer();//直接回应
Console.WriteLine("处理完毕");
e.Handled = true;
}
else if (e.Context.Request.UrlEquals("/file"))
{
e.Context.Response
.SetStatus()//必须要有状态
.FromFile(@"D:\System\Windows.iso", e.Context.Request);//直接回应文件。
}
base.OnGet(client, e);
}
}
}

View File

@@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
<ItemGroup>
<None Update="RRQMSocket.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

View File

@@ -1,62 +0,0 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "openapi.yaml",
defaultModelsExpandDepth: 0,
displayRequestDuration: true,
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>

View File

@@ -1,75 +0,0 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
window.addEventListener('DOMContentLoaded', function () {
run();
});
</script>

View File

@@ -1,170 +0,0 @@
openapi: 3.0.0
info:
version: "1.0"
title: HTTP Cache Server API
description: HTTP Cache Server API
contact:
name: chronoxor
url: https://github.com/chronoxor/CppServer
email: chronoxor@gmail.com
servers:
- url: /api
description: Cache API
tags:
- name: Cache
description: Cache methods
paths:
/cache:
get:
tags:
- Cache
summary: Get the cache value
operationId: GetCacheValue
parameters:
- name: key
in: query
description: Cache key (optional)
required: false
schema:
type: string
example: 'test'
responses:
200:
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/CacheItems'
text/plain:
schema:
type: string
404:
description: Cache key not found
content: {}
500:
description: Internal server error
content: {}
post:
tags:
- Cache
summary: Create the cache value
operationId: CreateCacheValue
parameters:
- name: key
in: query
description: Cache key
required: true
schema:
type: string
example: 'test'
requestBody:
description: Cache value to create
required: true
content:
text/plain:
schema:
type: string
example: 'value'
responses:
200:
description: Success
content: {}
500:
description: Internal server error
content: {}
put:
tags:
- Cache
summary: Modify the cache value
operationId: ModifyCacheValue
parameters:
- name: key
in: query
description: Cache key
required: true
schema:
type: string
example: 'test'
requestBody:
description: Cache value to modify
required: true
content:
text/plain:
schema:
type: string
example: 'modified'
responses:
200:
description: Success
content: {}
500:
description: Internal server error
content: {}
delete:
tags:
- Cache
summary: Delete the cache value
operationId: DeleteCacheValue
parameters:
- name: key
in: query
description: Cache key
required: true
schema:
type: string
example: 'test'
responses:
200:
description: Success
content:
text/plain:
schema:
type: string
404:
description: Cache key not found
content: {}
500:
description: Internal server error
content: {}
head:
tags:
- Cache
summary: Get the cache headers
operationId: GetCacheHeaders
responses:
200:
description: Success
content: {}
500:
description: Internal server error
content: {}
options:
tags:
- Cache
summary: Get the cache options
operationId: GetCacheOptions
responses:
200:
description: Success
content: {}
500:
description: Internal server error
content: {}
components:
schemas:
CacheItem:
type: object
properties:
key:
type: string
value:
type: string
CacheItems:
type: array
items:
$ref: '#/components/schemas/CacheItem'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,350 +0,0 @@
using System;
using TouchSocket.Core;
using TouchSocket.Sockets;
using TouchSocket.Rpc;
using TouchSocket.Rpc.TouchRpc;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
namespace JsonRpcProxy
{
public interface IServer:IRemoteServer
{
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
System.String TestJsonRpc(System.String str,IInvokeOption invokeOption = default);
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
Task<System.String> TestJsonRpcAsync(System.String str,IInvokeOption invokeOption = default);
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
System.String TestJsonRpc1(System.String str,IInvokeOption invokeOption = default);
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
Task<System.String> TestJsonRpc1Async(System.String str,IInvokeOption invokeOption = default);
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
System.String TestGetContext(System.String str,IInvokeOption invokeOption = default);
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
Task<System.String> TestGetContextAsync(System.String str,IInvokeOption invokeOption = default);
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject TestJObject(TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject obj,IInvokeOption invokeOption = default);
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
Task<TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject> TestJObjectAsync(TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject obj,IInvokeOption invokeOption = default);
}
public class Server :IServer
{
public Server(IRpcClient client)
{
this.Client=client;
}
public IRpcClient Client{get;private set; }
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public System.String TestJsonRpc(System.String str,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
System.String returnData=Client.Invoke<System.String>("jsonrpcconsoleapp.server.testjsonrpc",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public Task<System.String> TestJsonRpcAsync(System.String str,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
return Client.InvokeAsync<System.String>("jsonrpcconsoleapp.server.testjsonrpc",invokeOption, parameters);
}
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public System.String TestJsonRpc1(System.String str,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
System.String returnData=Client.Invoke<System.String>("TestJsonRpc1",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public Task<System.String> TestJsonRpc1Async(System.String str,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
return Client.InvokeAsync<System.String>("TestJsonRpc1",invokeOption, parameters);
}
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public System.String TestGetContext(System.String str,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
System.String returnData=Client.Invoke<System.String>("jsonrpcconsoleapp.server.testgetcontext",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public Task<System.String> TestGetContextAsync(System.String str,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
return Client.InvokeAsync<System.String>("jsonrpcconsoleapp.server.testgetcontext",invokeOption, parameters);
}
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject TestJObject(TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject obj,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{obj};
TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject returnData=Client.Invoke<TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject>("jsonrpcconsoleapp.server.testjobject",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public Task<TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject> TestJObjectAsync(TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject obj,IInvokeOption invokeOption = default)
{
if(Client==null)
{
throw new RpcException("IRpcClient为空请先初始化或者进行赋值");
}
if (Client.TryCanInvoke?.Invoke(Client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{obj};
return Client.InvokeAsync<TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject>("jsonrpcconsoleapp.server.testjobject",invokeOption, parameters);
}
}
public static class ServerExtensions
{
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public static System.String TestJsonRpc<TClient>(this TClient client,System.String str,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
System.String returnData=client.Invoke<System.String>("jsonrpcconsoleapp.server.testjsonrpc",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public static Task<System.String> TestJsonRpcAsync<TClient>(this TClient client,System.String str,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
return client.InvokeAsync<System.String>("jsonrpcconsoleapp.server.testjsonrpc",invokeOption, parameters);
}
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public static System.String TestJsonRpc1<TClient>(this TClient client,System.String str,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
System.String returnData=client.Invoke<System.String>("TestJsonRpc1",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public static Task<System.String> TestJsonRpc1Async<TClient>(this TClient client,System.String str,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
return client.InvokeAsync<System.String>("TestJsonRpc1",invokeOption, parameters);
}
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public static System.String TestGetContext<TClient>(this TClient client,System.String str,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
System.String returnData=client.Invoke<System.String>("jsonrpcconsoleapp.server.testgetcontext",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public static Task<System.String> TestGetContextAsync<TClient>(this TClient client,System.String str,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{str};
return client.InvokeAsync<System.String>("jsonrpcconsoleapp.server.testgetcontext",invokeOption, parameters);
}
///<summary>
///无注释信息
///</summary>
/// <exception cref="System.TimeoutException">调用超时</exception>
/// <exception cref="TouchSocket.Rpc.RpcInvokeException">Rpc调用异常</exception>
/// <exception cref="System.Exception">其他异常</exception>
public static TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject TestJObject<TClient>(this TClient client,TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject obj,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{obj};
TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject returnData=client.Invoke<TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject>("jsonrpcconsoleapp.server.testjobject",invokeOption, parameters);
return returnData;
}
///<summary>
///无注释信息
///</summary>
public static Task<TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject> TestJObjectAsync<TClient>(this TClient client,TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject obj,IInvokeOption invokeOption = default) where TClient:
TouchSocket.Rpc.JsonRpc.IJsonRpcClient{
if (client.TryCanInvoke?.Invoke(client)==false)
{
throw new RpcException("Rpc无法执行。");
}
object[] parameters = new object[]{obj};
return client.InvokeAsync<TouchSocket.Core.XREF.Newtonsoft.Json.Linq.JObject>("jsonrpcconsoleapp.server.testjobject",invokeOption, parameters);
}
}
}

View File

@@ -1,230 +0,0 @@
using JsonRpcProxy;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using TouchSocket.Core;
using TouchSocket.Core.ByteManager;
using TouchSocket.Core.Config;
using TouchSocket.Core.Plugins;
using TouchSocket.Core.XREF.Newtonsoft.Json.Linq;
using TouchSocket.Http;
using TouchSocket.Rpc;
using TouchSocket.Rpc.JsonRpc;
using TouchSocket.Rpc.TouchRpc;
using TouchSocket.Sockets;
namespace JsonRpcConsoleApp
{
internal class Program
{
//JSONRPC 通讯基础示例 TPC和HTTP 未来考虑扩展升级WebSocket
//1.完成了JSONRPC 的基本调用方法
//2.JSONRPC 服务端和客户端的创建
//3.服务端进行主动通知客户端
//4.客户端处理服务端推送的自定义消息处理
//5.[JsonRpc(true)]特性使用 标记为true 表示直接使用方法名称,否则使用明明空间+类名+方法名 全小写
//6.RPC上下文获取。通过上下文进行自定义消息推送
private static void Main(string[] args)
{
RpcStore rpcStore = new RpcStore(new TouchSocket.Core.Dependency.Container());
//添加解析器解析器根据传输协议序列化方式的不同调用RPC服务
rpcStore.AddRpcParser("tcpJsonRpcParser ", CreateTcpJsonRpcParser());
rpcStore.AddRpcParser("httpJsonRpcParser ", CreateHTTPJsonRpcParser());
//注册当前程序集的所有服务
rpcStore.RegisterAllServer();
//分享代理代理文件可通过RRQMTool远程获取。
//rpcService.ShareProxy(new IPHost(8848));
//或者直接本地导出代理文件。
//ServerCellCode[] cellCodes = rpcStore.GetProxyInfo(typeof(JsonRpcAttribute));//当想导出全部时RpcStore.ProxyAttributeMap.Values.ToArray()
//string codeString = CodeGenerator.ConvertToCode("RRQMProxy", cellCodes);
JsonRpcClientInvokeByTcp();
JsonRpcClientInvokeByHttp();
File.WriteAllText("../../../JsonRpcProxy.cs", rpcStore.GetProxyCodes("JsonRpcProxy"));
Console.WriteLine("代理文件已经写入到当前项目。");
Console.WriteLine("请按任意键退出");
Console.ReadKey();
}
private static void JsonRpcClientInvokeByHttp()
{
JsonRpcClient jsonRpcClient = new JsonRpcClient();
jsonRpcClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost("http://127.0.0.1:7706/jsonrpc")
.SetJRPT(JRPT.Http));
jsonRpcClient.Connect();
Console.WriteLine("连接成功");
string result = jsonRpcClient.Invoke<string>("jsonrpcconsoleapp.server.testjsonrpc", InvokeOption.WaitInvoke, "RRQM");
Console.WriteLine($"Http返回结果:{result}");
JObject obj = new JObject();
obj.Add("A", "A");
obj.Add("B", 10);
obj.Add("C", 100.1);
JObject newObj = jsonRpcClient.Invoke<JObject>("jsonrpcconsoleapp.server.testjobject", InvokeOption.WaitInvoke, obj);
Console.WriteLine($"Http返回结果:{newObj}");
}
private static void JsonRpcClientInvokeByTcp()
{
JsonRpcClient jsonRpcClient = new JsonRpcClient();
jsonRpcClient.Setup(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7705")
.SetJRPT(JRPT.Tcp));
jsonRpcClient.Connect();
Console.WriteLine("连接成功");
string result = jsonRpcClient.Invoke<string>("jsonrpcconsoleapp.server.testjsonrpc", InvokeOption.WaitInvoke, "RRQM");
Console.WriteLine($"Tcp返回结果:{result}");
result = jsonRpcClient.Invoke<string>("TestJsonRpc1", InvokeOption.WaitInvoke, "RRQM");
Console.WriteLine($"Tcp返回结果:{result}");
result = jsonRpcClient.Invoke<string>("jsonrpcconsoleapp.server.testgetcontext", InvokeOption.WaitInvoke, "RRQM");
Console.WriteLine($"Tcp返回结果:{result}");
JObject obj = new JObject();
obj.Add("A", "A");
obj.Add("B", 10);
obj.Add("C", 100.1);
JObject newObj = jsonRpcClient.Invoke<JObject>("jsonrpcconsoleapp.server.testjobject", InvokeOption.WaitInvoke, obj);
Console.WriteLine($"Tcp返回结果:{newObj}");
NotifyAll();
}
static List<SocketClient> Clients = new List<SocketClient>();
private static IRpcParser CreateTcpJsonRpcParser()
{
TcpService service = new TcpService();
service.Connecting += (client, e) =>
{
Console.WriteLine("客户端连接成功");
client.SetDataHandlingAdapter(new TerminatorPackageAdapter("\r\n"));
Console.WriteLine(client.ID);
};
service.Connected += (SocketClient client, TouchSocketEventArgs e) =>
{
Clients.Add(client);
Console.WriteLine(client.ID);
Console.WriteLine("客户端连接完成");
};
service.Disconnected += (client, e) =>
{
Clients.Remove(client);
Console.WriteLine("客户端连接断开");
Console.WriteLine(client.ID);
};
service.Setup(new TouchSocketConfig()
.UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7705) }))
.Start();
return service.AddPlugin<JsonRpcParserPlugin>();
}
/// <summary>
/// 通知所有客户端
/// </summary>
private static void NotifyAll()
{
for (int i = 0; i < Clients.Count; i++)
{
//如果在线
if (Clients[i].Online)
{
try
{
Clients[i].Send(Encoding.UTF8.GetBytes("Hello Word"));
}
catch (Exception ex)
{
//有可能判断的时候在线发送的时候不在线
Console.WriteLine(ex.Message);
}
}
}
}
private static IRpcParser CreateHTTPJsonRpcParser()
{
HttpService service = new HttpService();
service.Setup(new TouchSocketConfig().UsePlugin()
.SetListenIPHosts(new IPHost[] { new IPHost(7706) }))
.Start();
return service.AddPlugin<JsonRpcParserPlugin>()
.SetJsonRpcUrl("/jsonRpc");
}
}
public class Server : RpcServer
{
[JsonRpc]
public string TestJsonRpc(string str)
{
return "RRQM" + str;
}
/// <summary>
/// 当标记为true时直接使用方法名称
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
[JsonRpc(true)]
public string TestJsonRpc1(string str)
{
return "RRQM" + str;
}
/// <summary>
/// 使用调用上下文。
/// 可以从上下文获取调用的SocketClient。从而获得IP和Port等相关信息。
/// </summary>
/// <param name="callContext"></param>
/// <param name="str"></param>
/// <returns></returns>
[JsonRpc]
[TouchRpc(MethodFlags = MethodFlags.IncludeCallContext)]//使用调用上才文
public string TestGetContext(ICallContext callContext, string str)
{
if (callContext.Caller is HttpSocketClient)
{
Console.WriteLine("HTTP请求");
var client = callContext.Caller as HttpSocketClient;
var ip = client.IP;
var port = client.Port;
Console.WriteLine($"HTTP请求{ip}:{port}");
}
if (callContext.Caller is SocketClient)
{
Console.WriteLine("Tcp请求");
var client = callContext.Caller as SocketClient;
var ip = client.IP;
var port = client.Port;
client.Send(Encoding.UTF8.GetBytes("Hello Word"));
Console.WriteLine($"Tcp请求{ip}:{port}");
}
return "RRQM" + str;
}
[JsonRpc]
public JObject TestJObject(JObject obj)
{
return obj;
}
}
}

View File

@@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocketPro" Version="0.4.5" />
</ItemGroup>
</Project>

View File

@@ -1,71 +0,0 @@
using System;
using TouchSocket.Core;
using TouchSocket.Core.ByteManager;
using TouchSocket.Core.Config;
using TouchSocket.Core.Log;
using TouchSocket.Core.Plugins;
using TouchSocket.Sockets;
using TouchSocket.Sockets.Plugins;
namespace NATServiceConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
MyNATService service = new MyNATService();
var config = new TouchSocketConfig();
config.SetListenIPHosts(new IPHost[] { new IPHost(7788) });
service.Setup(config);
service.Start();
Console.WriteLine("转发服务器已启动。已将7788端口转发到127.0.0.1:7789地址");
}
}
internal class MyNATService : NATService
{
protected override void OnConnected(NATSocketClient socketClient, TouchSocketEventArgs e)
{
base.OnConnected(socketClient, e);
try
{
//此处模拟的是只要连接到NAT服务器就转发。
//实际上,这个方法可以随时调用。
socketClient.AddTargetClient(new TouchSocketConfig()
.SetRemoteIPHost("127.0.0.1:7789")
.ConfigurePlugins(a=>
{
//在企业版中,使用以下任意方式,可实现转发客户端的断线重连。
a.Add<PollingKeepAlivePlugin<TcpClient>>()
.SetTick(1000);//每秒检查
//a.UseReconnection();
}));
}
catch (Exception ex)
{
socketClient.Logger.Exception(ex);
}
}
protected override void OnTargetClientDisconnected(NATSocketClient socketClient, ITcpClient tcpClient, ClientDisconnectedEventArgs e)
{
socketClient.Logger.Info($"{socketClient.IP}:{socketClient.Port}的转发客户端{tcpClient.IP}:{tcpClient.Port}已经断开连接。");
base.OnTargetClientDisconnected(socketClient, tcpClient, e);
}
protected override byte[] OnNATReceived(NATSocketClient socketClient, ByteBlock byteBlock, IRequestInfo requestInfo)
{
//服务器收到的数据
return base.OnNATReceived(socketClient, byteBlock, requestInfo);
}
protected override byte[] OnTargetClientReceived(NATSocketClient socketClient, ITcpClient tcpClient, ByteBlock byteBlock, IRequestInfo requestInfo)
{
//连接的客户端收到的数据
return base.OnTargetClientReceived(socketClient, tcpClient, byteBlock, requestInfo);
}
}
}

View File

@@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TouchSocket" Version="0.4.5" />
</ItemGroup>
</Project>

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