文件归档
@@ -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` 仓库 DEMO,DEMO 提供最简单的错误逻辑代码,否则不予处理。⚠⚠**
|
||||
|
||||
您的代码下载地址?
|
||||
|
||||
---
|
||||
|
||||
### 期待结果
|
||||
|
||||
期待的结果是?
|
||||
|
||||
---
|
||||
341
.gitignore
vendored
@@ -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
@@ -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.
|
||||
218
README.en.md
@@ -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">
|
||||
|
||||
[](https://www.nuget.org/packages/TouchSocket/)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://gitee.com/dotnetchina/TouchSocket/stargazers)
|
||||
[](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开源协议开源。_**
|
||||
|
||||
| 名称|地址 |描述|
|
||||
|---|---|---|
|
||||
|[](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秒。|
|
||||
| [](https://www.nuget.org/packages/TouchSocket.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket) | TouchSocket.AspNetCore是适用于AspNetCore的专属版本。|
|
||||
|
||||
## 🎫企业版描述
|
||||
**_以下Nuget包,并未开源,其源代码需要付费购买。_**
|
||||
| 名称|地址 |描述|
|
||||
|---|---|---|
|
||||
|[](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)|
|
||||
| [](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,亦或者直接安装RRQMSocketFramework,Mono则直接加载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的支持,如果还有其他问题,请加群QQ:234762506讨论。
|
||||
|
||||
## 支持作者
|
||||
|
||||
[支持入口](https://www.yuque.com/rrqm/touchsocket/a5199820843b324f025633fdeee44394)
|
||||
221
README.md
@@ -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">
|
||||
|
||||
[](https://www.nuget.org/packages/TouchSocket/)
|
||||
[](https://www.nuget.org/packages/TouchSocket/)
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0.html)
|
||||
[](https://gitee.com/dotnetchina/TouchSocket/stargazers)
|
||||
[](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>
|
||||
[](https://github.com/RRQM/TouchSocket)
|
||||
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
雄关漫道真如铁,而今迈步从头越。从头越,苍山如海,残阳如血。
|
||||
|
||||
</div>
|
||||
|
||||
中文 | [English](README.en.md)
|
||||
|
||||
## 🎀描述
|
||||
|
||||
【开源版】
|
||||
| 名称|地址 |描述|
|
||||
|---|---|---|
|
||||
|[](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秒。|
|
||||
| [](https://www.nuget.org/packages/TouchSocket.AspNetCore)|[Gitee](https://gitee.com/dotnetchina/TouchSocket)<br>[Github](https://github.com/RRQM/TouchSocket) | TouchSocket.AspNetCore是适用于AspNetCore的专属版本。|
|
||||
|
||||
【企业版】
|
||||
| 名称|地址 |描述|
|
||||
|---|---|---|
|
||||
|[](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)|
|
||||
| [](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,或者加群QQ:234762506讨论。
|
||||
|
||||
## 支持作者
|
||||
|
||||
[支持入口](https://www.yuque.com/rrqm/touchsocket/a5199820843b324f025633fdeee44394)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1 +0,0 @@
|
||||
https://www.yuque.com/rrqm/touchsocket/mf3zif <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 186 KiB |
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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会自动删除这个服务,大约2,3分钟就会删了
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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会自动删除这个服务,大约2,3分钟就会删了
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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("请先选择一个服务器节点。");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
359
examples/EventBus简单示例/EventBusClient/Form1.Designer.cs
generated
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
459
examples/EventBus简单示例/EventBusServer/Form1.Designer.cs
generated
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)]
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)]
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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("请选择一个客户端");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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、Put,Delete,或者其他
|
||||
/// </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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
|
Before Width: | Height: | Size: 665 B |
|
Before Width: | Height: | Size: 628 B |
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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'
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||