规范代码文件

This commit is contained in:
若汝棋茗
2021-08-26 22:23:24 +08:00
parent 341c9fd502
commit 99a3165be0
238 changed files with 0 additions and 27702 deletions

341
.gitignore vendored
View File

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

201
LICENSE
View File

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

393
README.md
View File

@@ -1,393 +0,0 @@
<p></p>
<p></p>
<p align="center">
<img src="https://ftp.bmp.ovh/imgs/2021/06/351eeccfadc07014.png" width = "100" height = "100" alt="图片名称" align=center />
</p>
<div align="center">
[![NuGet version (RRQMSocket)](https://img.shields.io/nuget/v/RRQMSocket.svg?style=flat-square)](https://www.nuget.org/packages/RRQMSocket/)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Download](https://img.shields.io/nuget/dt/RRQMSocket)](https://www.nuget.org/packages/RRQMSocket/)
[![star](https://gitee.com/dotnetchina/RRQMSocket/badge/star.svg?theme=gvp)](https://gitee.com/dotnetchina/RRQMSocket/stargazers)
[![fork](https://gitee.com/dotnetchina/RRQMSocket/badge/fork.svg?theme=gvp)](https://gitee.com/dotnetchina/RRQMSocket/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>
<div align="center">
<img src="https://i.bmp.ovh/imgs/2021/06/0bb09b575906f48b.png" alt="图片名称" align=center />
</div>
## 💿描述
| 名称 |描述|
|---|---|
|[![NuGet version (RRQMSocket)](https://img.shields.io/nuget/v/RRQMSocket.svg?label=RRQMSocket)](https://www.nuget.org/packages/RRQMSocket/)| **RRQMSocket**是一个整合性的、超轻量级的、可以免费商用使用的网络通信服务框架。<br>它具有 **高并发连接****高并发处理****事件订阅****插件式扩展**<br> **多线程处理****内存池****对象池** 等特点,<br>让使用者能够更加简单的、快速的搭建网络框架。|
|[![NuGet version](https://img.shields.io/nuget/v/RRQMSocketFramework.svg?label=RRQMSocketFramework)](https://www.nuget.org/packages/RRQMSocketFramework/)| **RRQMSocketFramework**是RRQMSocket系列的企业版<br>两者在功能上几乎没有区别但是RRQMSocketFramework无任何依赖<br>且可以提供专属的定制功能。后续也会加入企业已定制的优秀功能,希望大家多多支持。|
| [![NuGet version (RRQMSocket.FileTransfer)](https://img.shields.io/nuget/v/RRQMSocket.FileTransfer.svg?label=RRQMSocket.FileTransfer)](https://www.nuget.org/packages/RRQMSocket.FileTransfer/) | RRQMSocket.FileTransfer是一个高性能的文件传输框架<br>您可以用它传输**任意大小**的文件,它可以完美支持**上传下载混合式队列传输**、<br>**断点续传**、 **快速上传** 、**传输限速**、**获取文件信息**、**删除文件**等。<br>在实时测试中它的传输速率可达1000Mb/s。 |
|[![NuGet version (RRQMSocket.RPC)](https://img.shields.io/nuget/v/RRQMSocket.RPC.svg?label=RRQMSocket.RPC)](https://www.nuget.org/packages/RRQMSocket.RPC/) |RPC是一个超轻量、高性能、可扩展的微服务管理平台框架<br>目前已完成开发**RRQMRPC**、**XmlRpc**、**JsonRpc**、**WebApi**部分。<br> **RRQMRPC**部分使用RRQM专属协议支持客户端**异步调用**<br>服务端**异步触发**、以及**out**和**ref**关键字,**函数回调**等。<br>在调用效率上也是非常强悍,在调用空载函数,且返回状态时,<br>**10w**次调用仅用时**3.8**秒,不返回状态用时**0.9**秒。<br>其他协议调用性能详看性能评测。|
|[![NuGet version (RRQMSocket.RPC.WebApi)](https://img.shields.io/nuget/v/RRQMSocket.RPC.WebApi.svg?label=RRQMSocket.RPC.WebApi)](https://www.nuget.org/packages/RRQMSocket.RPC.WebApi/)| WebApi是一个扩展于RRQMSocket.RPC的WebApi组件<br>可以通过该组件创建WebApi服务解析器让桌面端、Web端、移动端可以跨语言调用RPC函数。<br>功能支持路由、Get传参、Post传参等。|
|[![NuGet version (RRQMSocket.RPC.XmlRpc)](https://img.shields.io/nuget/v/RRQMSocket.RPC.XmlRpc.svg?label=RRQMSocket.RPC.XmlRpc)](https://www.nuget.org/packages/RRQMSocket.RPC.XmlRpc/)| XmlRpc是一个扩展于RRQMSocket.RPC的XmlRpc组件<br>可以通过该组件创建XmlRpc服务解析器完美支持XmlRpc数据类型类型嵌套<br>Array等也能与CookComputing.XmlRpcV2完美对接。不限WebAndroid等平台。|
| [![NuGet version (RRQMSocket.RPC.JsonRpc)](https://img.shields.io/nuget/v/RRQMSocket.RPC.JsonRpc.svg?label=RRQMSocket.RPC.JsonRpc)](https://www.nuget.org/packages/RRQMSocket.RPC.JsonRpc/)| JsonRpc是一个扩展于RRQMSocket.RPC的JsonRpc组件<br>可以通过该组件创建JsonRpc服务解析器支持JsonRpc全部功能可与WebAndroid等平台无缝对接。|
| [![NuGet version (RRQMSocket.Http)](https://img.shields.io/nuget/v/RRQMSocket.Http.svg?label=RRQMSocket.Http)](https://www.nuget.org/packages/RRQMSocket.Http/) | RRQMSocket.Http是一个能够简单解析Http的服务组件<br>能够快速响应Http服务请求。|
## 🖥支持环境
- .NET Framework4.5及以上。
- .NET Core3.1及以上。
- .NET Standard2.0及以上。
## 🥪支持框架
- WPF
- Winform
- Blazor
- Xamarin
- Mono
- Unity
- 其他即所有C#系
## 🌴RRQMSocket特点速览
#### 对象池
对象池在RRQMSocket有很多应用最主要的两个就是**连接对象池**和**处理对象池**。连接对象池就是当客户端成功连接时首先会去连接对象池中找SocketClient然后没有的话才会创建。如果哪个客户端掉线了它的SocketClient就会被回收。
然后就是处理对象池在RRQMSocket中接收数据的线程和IOCP内核线程是分开的也可以设置拥塞接收也就是比如说客户端给服务器发送了1w条数据但是服务器收到后处理起来很慢那传统的iocp肯定会放慢接收速率然后通知客户端的tcp窗口发生拥塞然后让客户端暂缓发送。但是在RRQMSocket中会把收到的数据通过队列全都存起来首先不影响iocp的接收同时再分配线程去处理收到的报文信息这样就相当于一个“泄洪湖泊”能很大程度的提高处理数据的能力。
#### 多线程
由于有**处理对象池**的存在使多线程处理变得简单。在客户端连接完成时会自动分配该客户端辅助类TcpSocketClient的消息处理逻辑线程假如服务器线程数量为10则第一个连接的客户端会被分配到0号线程中第二个连接将被分配到1号线程中以此类推循环分配。当某个客户端收到数据时会将数据排入当前线程所独自拥有的队列当中并唤醒线程执行。
#### 传统IOCP和RRQMSocket
RRQMSocket的IOCP和传统也不一样就以微软官方示例为例使用MemoryBuffer开辟一块内存均分然后给每个会话分配一个区接收等收到数据后再**复制**源数据然后把复制的数据进行处理。而RRQMSocket是每次接收之前从内存池拿一个可用内存块然后**直接用于接收**,等收到数据以后,直接就把这个内存块抛出处理,这样就避免了**复制操作**,虽然只是细小的设计,但是在传输**1000w**次**64kb**的数据时,性能相差了**10倍**。
#### 数据处理适配器
相信大家都使用过其他的Socket产品例如HPSocketSuperSocket等那么RRQMSocket在设计时也是借鉴了其他产品的优秀设计理念数据处理适配器就是其中之一但和其他产品的设计不同的是RRQMSocket的适配器功能更加强大它不仅可以提前解析数据包还可以解析数据对象。例如可以使用固定包头对数据进行预处理从而解决数据分包、粘包的问题。也可以直接解析HTTP协议经过适配器处理后传回一个HttpRequest对象等。
#### 粘包、分包解决
在RRQMSocket中处理TCP粘包、分包问题是非常简单的。只需要更改不同的**数据处理适配器**即可。例如:使用**固定包头**只需要给SocketClient和TcpClient配置注入**FixedHeaderDataHandlingAdapter**的实例即可。同样对应的处理器也有**固定长度** 、 **终止字符分割** 等。
#### 兼容性与适配
RRQMSocket提供多种框架模型能够完全兼容基于TCP、UDP协议的所有协议。例如TcpService与TcpClient其基础功能和Socket一模一样只是增强了框架的**坚固性**和**并发性**,将**连接**和**接收数据**通过事件的形式抛出,让使用者能够更加友好的使用。
其次RRQMSocket也提供了一些特定的服务器和客户端如TokenService和TokenClient这两个就必须配套使用不然在验证Token时会被主动断开。
## 🔗联系作者
- [CSDN博客主页](https://blog.csdn.net/qq_40374647)
- [哔哩哔哩视频](https://space.bilibili.com/94253567)
- [源代码仓库主页](https://gitee.com/RRQM_Home)
- 交流QQ群234762506
## 🍻RRQM系产品
| 名称| 版本Nuget Version|下载Nuget Download| 描述 |
|------|----------|-------------|-------|
| [RRQMCore](https://gitee.com/RRQM_OS/RRQMCore) | [![NuGet version (RRQMCore)](https://img.shields.io/nuget/v/RRQMCore.svg?style=flat-square)](https://www.nuget.org/packages/RRQMCore/) | [![Download](https://img.shields.io/nuget/dt/RRQMCore)](https://www.nuget.org/packages/RRQMCore/) | RRQMCore是为RRQM系提供基础服务功能的库其中包含**内存池**、**对象池**、**等待逻辑池**、**AppMessenger**、**3DES加密**、**Xml快速存储**、**运行时间测量器**、**文件快捷操作**、**高性能序列化器**、**规范日志接口**等。 |
| [RRQMSkin](https://gitee.com/RRQM_OS/RRQMSkin) | [![NuGet version (RRQMSkin)](https://img.shields.io/nuget/v/RRQMSkin.svg?style=flat-square)](https://www.nuget.org/packages/RRQMSkin/) | [![Download](https://img.shields.io/nuget/dt/RRQMSkin)](https://www.nuget.org/packages/RRQMSkin/) | RRQMSkin是WPF的控件样式库其中包含 **无边框窗体****圆角窗体****水波纹按钮****输入提示筛选框****控件拖动效果** 、**圆角图片框**、 **弧形文字****扇形元素****指针元素****饼图****时钟****速度表盘** 等。|
## 一、TCP框架
#### 1.1 说明
TCP框架是RRQMSocket最基础的框架它定制了后继成员的创建、管理维护、使用等一系列的规则让使用者无需关心连接、掉线、失活检测、多线程安全等问题能够专注于数据处理。
#### 1.2 安装
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket
```
#### 1.3 特点
- 简单易用。
- 多线程。
- **多地址监听**可以一次性监听多个IP及端口
- 适配器预处理,一键式解决**分包**、**粘包**、对象解析(如HTTPJson)等。
- 超简单的同步发送、异步发送、接收等操作。
- 基于事件驱动,让每一步操作尽在掌握。
- 高性能服务器每秒可接收200w条信息
- **独立线程内存池**(每个线程拥有自己的内存池)
#### 1.4 应用场景
- C/S服务器开发。
- 制造业自动化控制服务器。
- 物联网数据采集服务器。
- 游戏服务器开发。
#### 1.5 API文档
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984527&doc_id=1402901)
#### 1.6 Demo
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
## 二、Token框架
#### 2.1 说明
TokenService框架是RRQMSocket提供的派生自TcpService的基础框架它在TCP基础之上通过验证Token的方式可以规范、筛选连接者。这样可以很大程度的**保护服务器**不疲于非法连接者的攻击。
#### 2.2 安装
工具➨Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket
```
#### 2.3 特点
- **规范**、**筛选**连接者,保护服务器。
- 客户端与服务器必须**配套**使用。
#### 2.4 应用场景
- C/S服务器开发。
- 制造业自动化控制服务器。
- 游戏服务器开发。
#### 2.5 API文档
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984517&doc_id=1402901)
#### 2.6 Demo
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
## 三、Protocol框架
#### 3.1 说明
ProtocolService框架是RRQMSocket提供的派生自TokenService的基础框架它在Token基础之上提供**协议+数据**的形式发送,其中还包括**协议冲突检测**、**协议数据占位**等。
#### 3.2 安装
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket
```
#### 3.3 特点
- 支持**ID同步**。
- 快捷**协议发送**。
#### 3.4 应用场景
- C/S服务器开发。
- 制造业自动化控制服务器。
- 游戏服务器开发。
#### 3.5 API文档
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984517&doc_id=1402901)
#### 3.6 Demo
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
## 四、RPCService框架
#### 4.1 说明
RPCService框架是所有远程过程调用的微服务调用管理平台在该平台的托管下使多种协议、多种序列化方式调用成为可能。目前可使用RRQMRPC、WebApi、XmlRpc、JsonRpc共同调用。
#### 4.2 RPC解析器
**说明:** RPCService仅仅是对调用的服务进行管理和维护并不参与实质性的通信过程。实际上由于通信协议、序列化方式的不同需要创建相对应的解析器才能完成调用操作。
#### 4.3 RPC解析器之RRQMRPC
##### 4.3.1 说明
RRQMRPC是基于Protocol框架、固定包头解析的远程调用框架也是RRQM中性能最强悍、使用最简单、功能最强大的RPC框架。
##### 4.3.2 特点
- 支持**自定义**类型参数。
- 支持具有**默认值**的参数设定。
- 支持**out、ref** 关键字参数。
- 支持服务器**回调客户端** 。
- 支持**客户端**之间**相互调用**。
- 支持TCP、UDP等不同的协议调用相同服务。
- 支持异步调用。
- 支持权限管理,让非法调用死在萌芽时期。
- 支持**静态织入调用****静态编译调用**,也支持**方法名+参数**调用。
- 支持**调用配置**类似MQTT的AtMostOnceAtLeastOnceExactlyOnce
- **支持EventBus**(企业版支持)。
- 支持**自定义序列化**。
- **全异常反馈** ,服务器调用状态会完整的反馈到客户端(可以设置不反馈)。
- 高性能在保证送达但不返回的情况下10w次调用用时0.8s在返回的情况下用时3.9s。
##### 4.3.3 安装
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket.RPC
```
##### 4.3.4 RRQMRPC性能测试
**说明:**
图一、图二、图三分别为`UDP无反馈调用``TCP有反馈调用``TCP连接池有反馈调用`。调用次数均为10w次调用性能非常nice。在无反馈中吞吐量达14.28w在有反馈中达2.72w。
![输入图片说明](https://images.gitee.com/uploads/images/2021/0409/191343_e5827d04_8553710.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2021/0409/191501_abec9e45_8553710.png "屏幕截图.png")
![输入图片说明](https://images.gitee.com/uploads/images/2021/0409/191531_d7f0a8d4_8553710.png "屏幕截图.png")
#### 4.4 RPC解析器之WebApi
##### 4.4.1 说明
使用WebApi解析器就可以在RPCService中通过WebApi的调用方式直接调用服务。
##### 4.4.2 特点
- 高性能100个客户端10w次调用仅用时17s。
- **全异常反馈** 。
- 支持大部分路由规则。
- 支持js、Android等调用。
##### 4.4.3 安装
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket.RPC.WebApi
```
#### 4.5 RPC解析器之XmlRpc
##### 4.5.1 说明
使用XmlRpc解析器就可以在RPCService中通过XmlRpc的调用方式直接调用服务客户端可以使用**CookComputing.XmlRpcV2**进行对接。
##### 4.5.2 特点
- **异常反馈** 。
- 支持自定义类型。
- 支持类型嵌套。
- 支持Array及自定义Array嵌套。
- 支持js、Android等调用。
##### 4.5.3 安装
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket.RPC.XmlRpc
```
#### 4.6 RPC解析器之JsonRpc
##### 4.6.1 说明
使用JsonRpc解析器就可以在RPCService中通过Json字符串直接调用服务。
##### 4.6.2 特点
- **异常反馈** 。
- 支持自定义类型。
- 支持类型嵌套。
- 支持js、Android等调用。
##### 4.6.3 安装
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket.RPC.JsonRpc
```
#### 4.7 API文档
[RRQMSocket API文档](https://gitee.com/RRQM_OS/RRQM/wikis/pages?sort_id=3984517&doc_id=1402901)
#### 4.8 Demo
[RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
## 五、文件传输框架
#### 5.1 说明
RRQMSocket.FileTransfer是一个高性能的文件传输框架由于它派生自RRQMRPC所以也具备RPC的全部特性。
#### 5.2 特点
- 简单易用。
- 多线程处理。
- 高性能,传输速度可达**1000Mb/s**。
- 超简单的**传输限速**设置1k-10Gb 无级调节。
- 超简单的传输速度、传输进度获取。
- 随心所欲的暂停、继续、停止传输。
- 系统化的权限管理,让敏感文件只允许**私有化下载**。
- **RPC交互**,让客户端和服务器交流不延迟。
- 基于**事件驱动**,让每一步操作尽在掌握。
- 可视化的文件块流,可以实现像迅雷一样的**填充式进度条**。
- 超简单的**断点续传**设置,为大文件传输保驾护航。
- 无状态上传断点续传设置,让同一个文件,在不同客户端之间**接力上传**。
- **断网续传**(企业版支持)
- 已经上传的文件,再次上传时,可实现**快速上传**。
- 极少的GC释放。
#### 5.3 安装
工具 ➨ Nuegt包管理器 ➨ 程序包管理器控制台
```CSharp
Install-Package RRQMSocket.FileTransfer
```
#### 5.4 Demo示例
**Demo位置** [RRQMBox](https://gitee.com/RRQM_OS/RRQMBox)
#### 5.5 性能测试
**说明:** 可以看到下图正在上传一个Window的系统镜像文件大约4.2Gb传输速度已达到800Mb/s性能非常强悍。其次GC基本上没有释放。
![](https://s3.bmp.ovh/imgs/2021/08/08f17f67b9e06bc7.gif)
## 致谢
谢谢大家对我的支持如果还有其他问题请加群QQ234762506讨论。
## 💕 支持本项目
您的支持就是我不懈努力的动力。
#### 爱心赞助名单(以下排名只按照打赏时间顺序)
1. Bobo Joker200¥
2. UnitySir66¥
3. Coffee100¥
4. Ninety50¥
5. *琼100¥
6. **安5¥
#### 商业采购名单(以下排名只按照商业采购时间顺序)
1.凯斯得****有限公司
<img src="https://images.gitee.com/uploads/images/2021/0330/234046_7662fb8c_8553710.png" width = "600" height = "400" alt="图片名称" align=center />

View File

@@ -1,40 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件块
/// </summary>
public class FileBlock
{
/// <summary>
/// 文件快索引
/// </summary>
public int Index { get; internal set; }
/// <summary>
/// 文件流位置
/// </summary>
public long Position { get; internal set; }
/// <summary>
/// 文件块长度
/// </summary>
public long UnitLength { get; internal set; }
/// <summary>
/// 请求状态
/// </summary>
public RequestStatus RequestStatus { get; internal set; }
}
}

View File

@@ -1,80 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.IO;
using System.IO;
using System.Security.Cryptography;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件Hash校验
/// </summary>
public static class FileHashGenerator
{
private static FileHashType fileCheckType;
/// <summary>
/// 文件
/// </summary>
public static FileHashType FileCheckType
{
get { return fileCheckType; }
set { fileCheckType = value; }
}
/// <summary>
/// 获取文件Hash
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static string GetFileHash(string path)
{
using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
return GetFileHash(fileStream);
}
}
/// <summary>
/// 获取文件Hash
/// </summary>
/// <param name="fileStream"></param>
/// <returns></returns>
public static string GetFileHash(FileStream fileStream)
{
HashAlgorithm hash;
switch (fileCheckType)
{
case FileHashType.MD5:
hash = MD5.Create();
break;
case FileHashType.SHA1:
hash = SHA1.Create();
break;
case FileHashType.SHA256:
hash = SHA256.Create();
break;
case FileHashType.SHA512:
hash = SHA512.Create();
break;
default:
hash = null;
break;
}
return FileControler.GetStreamHash(fileStream, hash);
}
}
}

View File

@@ -1,254 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Exceptions;
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件流池
/// </summary>
public static class FileStreamPool
{
internal static ConcurrentDictionary<string, RRQMStream> pathStream = new ConcurrentDictionary<string, RRQMStream>();
private readonly static object locker = new object();
private static ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();
internal static bool CheckAllFileBlockFinished(string path)
{
lock (locker)
{
RRQMStream stream;
if (!pathStream.TryGetValue(path, out stream))
{
return false;
}
if (stream.StreamType == StreamOperationType.Read)
{
return false;
}
foreach (var block in stream.Blocks)
{
if (block.RequestStatus != RequestStatus.Finished)
{
return false;
}
}
return true;
}
}
internal static void DisposeReadStream(string path)
{
RRQMStream stream;
if (pathStream.TryGetValue(path, out stream))
{
if (Interlocked.Decrement(ref stream.reference) == 0)
{
if (pathStream.TryRemove(path, out stream))
{
stream.Dispose();
}
}
}
}
internal static void DisposeWriteStream(string path, bool finished)
{
if (string.IsNullOrEmpty(path))
{
return;
}
RRQMStream stream;
if (pathStream.TryGetValue(path, out stream))
{
if (Interlocked.Decrement(ref stream.reference) == 0)
{
if (pathStream.TryRemove(path, out stream))
{
if (finished)
{
stream.FinishStream();
}
else
{
stream.Dispose();
}
}
}
}
}
internal static bool GetFreeFileBlock(string path, out FileBlock fileBlock, out string mes)
{
lock (locker)
{
RRQMStream stream;
if (!pathStream.TryGetValue(path, out stream))
{
mes = "没有此路径的写入信息";
fileBlock = null;
return false;
}
if (stream.StreamType == StreamOperationType.Read)
{
mes = "该路径的流为只读";
fileBlock = null;
return false;
}
foreach (var block in stream.Blocks)
{
if (block.RequestStatus == RequestStatus.Hovering)
{
block.RequestStatus = RequestStatus.InProgress;
fileBlock = block;
mes = null;
return true;
}
}
fileBlock = null;
mes = null;
return true;
}
}
internal static bool LoadReadStream(ref UrlFileInfo urlFileInfo, out string mes)
{
RRQMStream stream;
if (pathStream.TryGetValue(urlFileInfo.FilePath, out stream))
{
Interlocked.Increment(ref stream.reference);
mes = null;
return true;
}
else
{
if (RRQMStream.CreateReadStream(out stream, ref urlFileInfo, out mes))
{
Interlocked.Increment(ref stream.reference);
pathStream.TryAdd(urlFileInfo.FilePath, stream);
return true;
}
else
{
return false;
}
}
}
internal static bool LoadWriteStream(ref ProgressBlockCollection blocks, bool onlySearch, out string mes)
{
RRQMStream stream;
string rrqmPath = blocks.UrlFileInfo.SaveFullPath + ".rrqm";
if (!pathStream.TryGetValue(rrqmPath, out stream))
{
if (RRQMStream.CreateWriteStream(out stream, ref blocks, out mes))
{
Interlocked.Increment(ref stream.reference);
mes = null;
return pathStream.TryAdd(rrqmPath, stream);
}
else
{
return false;
}
}
else
{
if (onlySearch)
{
blocks = stream.Blocks;
mes = null;
return true;
}
mes = "该文件流正在被其他客户端拥有";
return false;
}
}
internal static bool ReadFile(string path, out string mes, long beginPosition, ByteBlock byteBlock, int offset, int length)
{
lockSlim.EnterReadLock();
try
{
if (pathStream.TryGetValue(path, out RRQMStream stream))
{
stream.FileStream.Position = beginPosition;
if (byteBlock.Buffer.Length < length + offset)
{
byteBlock.SetBuffer(new byte[length + offset]);
}
int r = stream.FileStream.Read(byteBlock.Buffer, offset, length);
if (r == length)
{
byteBlock.Position = offset + length;
byteBlock.SetLength(offset + length);
mes = null;
return true;
}
}
mes = "没有找到该路径下的流文件";
return false;
}
catch (Exception ex)
{
mes = ex.Message;
return false;
}
finally
{
lockSlim.ExitReadLock();
}
}
internal static void SaveProgressBlockCollection(string path)
{
RRQMStream stream;
if (pathStream.TryGetValue(path, out stream))
{
stream.SaveProgressBlockCollection();
}
else
{
throw new RRQMException("没有找到该路径下的流文件");
}
}
internal static bool WriteFile(string path, out string mes, out RRQMStream stream, long streamPosition, byte[] buffer, int offset, int length)
{
try
{
if (pathStream.TryGetValue(path, out stream))
{
stream.FileStream.Position = streamPosition;
stream.FileStream.Write(buffer, offset, length);
stream.FileStream.Flush();
mes = null;
return true;
}
mes = "未找到该路径下的流";
return false;
}
catch (Exception ex)
{
mes = ex.Message;
stream = null;
return false;
}
}
}
}

View File

@@ -1,28 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Exceptions;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件传输错误码映射
/// </summary>
public class FileTransferErrorExceptionMapping : ErrorExceptionMapping
{
private static FileTransferErrorExceptionMapping _instance = new FileTransferErrorExceptionMapping();
/// <summary>
/// 默认实例
/// </summary>
public static FileTransferErrorExceptionMapping Default { get => _instance; }
}
}

View File

@@ -1,20 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Run;
namespace RRQMSocket.FileTransfer
{
internal class FileWaitResult : WaitResult
{
public PBCollectionTemp PBCollectionTemp { get; set; }
}
}

View File

@@ -1,64 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Generic;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 临时序列化
/// </summary>
public class PBCollectionTemp
{
/// <summary>
/// 文件信息
/// </summary>
public UrlFileInfo UrlFileInfo { get; internal set; }
/// <summary>
/// 块集合
/// </summary>
public List<FileBlock> Blocks { get; internal set; }
/// <summary>
/// 从文件块转换
/// </summary>
/// <param name="progressBlocks"></param>
/// <returns></returns>
public static PBCollectionTemp GetFromProgressBlockCollection(ProgressBlockCollection progressBlocks)
{
if (progressBlocks == null)
{
return null;
}
PBCollectionTemp collectionTemp = new PBCollectionTemp();
collectionTemp.UrlFileInfo = progressBlocks.UrlFileInfo;
collectionTemp.Blocks = new List<FileBlock>();
collectionTemp.Blocks.AddRange(progressBlocks);
return collectionTemp;
}
/// <summary>
/// 转换为ProgressBlockCollection
/// </summary>
/// <returns></returns>
public ProgressBlockCollection ToPBCollection()
{
ProgressBlockCollection progressBlocks = new ProgressBlockCollection();
progressBlocks.UrlFileInfo = this.UrlFileInfo;
if (this.Blocks != null)
{
progressBlocks.AddRange(this.Blocks);
}
return progressBlocks;
}
}
}

View File

@@ -1,106 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Serialization;
using System;
using System.IO;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件进度块集合
/// </summary>
public class ProgressBlockCollection : ReadOnlyList<FileBlock>
{
/// <summary>
/// 文件信息
/// </summary>
public UrlFileInfo UrlFileInfo { get; internal set; }
private static int blockLength = 1024 * 1024 * 10;
/// <summary>
/// 分块长度,min=1024*1024*5
/// </summary>
public static int BlockLength
{
get { return blockLength; }
set
{
if (value < 1024 * 1024 * 5)
{
value = 1024 * 1024 * 5;
}
blockLength = value;
}
}
/// <summary>
/// 保存
/// </summary>
/// <param name="path"></param>
internal void Save(string path)
{
if (File.Exists(path))
{
File.Delete(path);
}
byte[] buffer = SerializeConvert.RRQMBinarySerialize(this, true);
using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
fileStream.Write(buffer, 0, buffer.Length);
}
}
/// <summary>
/// 读取
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
internal static ProgressBlockCollection Read(string path)
{
try
{
using (FileStream stream = File.OpenRead(path))
{
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
return SerializeConvert.RRQMBinaryDeserialize<ProgressBlockCollection>(buffer, 0);
}
}
catch (Exception)
{
return null;
}
}
internal static ProgressBlockCollection CreateProgressBlockCollection(UrlFileInfo urlFileInfo)
{
ProgressBlockCollection blocks = new ProgressBlockCollection();
blocks.UrlFileInfo = urlFileInfo;
long position = 0;
long surLength = urlFileInfo.FileLength;
int index = 0;
while (surLength > 0)
{
FileBlock block = new FileBlock();
block.Index = index++;
block.RequestStatus = RequestStatus.Hovering;
block.Position = position;
block.UnitLength = surLength > blockLength ? blockLength : surLength;
blocks.Add(block);
position += block.UnitLength;
surLength -= block.UnitLength;
}
return blocks;
}
}
}

View File

@@ -1,157 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Serialization;
using System;
using System.IO;
namespace RRQMSocket.FileTransfer
{
internal class RRQMStream
{
internal int reference;
private ProgressBlockCollection blocks;
private FileStream fileStream;
private string rrqmPath;
private StreamOperationType streamType;
private UrlFileInfo urlFileInfo;
private RRQMStream()
{
}
public ProgressBlockCollection Blocks { get { return blocks; } }
public FileStream FileStream
{
get { return fileStream; }
}
public StreamOperationType StreamType
{
get { return streamType; }
}
public UrlFileInfo UrlFileInfo { get => urlFileInfo; }
internal static bool CreateReadStream(out RRQMStream stream, ref UrlFileInfo urlFileInfo, out string mes)
{
stream = new RRQMStream();
try
{
stream.streamType = StreamOperationType.Read;
stream.fileStream = File.OpenRead(urlFileInfo.FilePath);
urlFileInfo.FileLength = stream.fileStream.Length;
stream.urlFileInfo = urlFileInfo;
mes = null;
return true;
}
catch (Exception ex)
{
stream.Dispose();
stream = null;
mes = ex.Message;
return false;
}
}
internal static bool CreateWriteStream(out RRQMStream stream, ref ProgressBlockCollection blocks, out string mes)
{
stream = new RRQMStream();
stream.rrqmPath = blocks.UrlFileInfo.SaveFullPath + ".rrqm";
stream.urlFileInfo = blocks.UrlFileInfo;
stream.streamType = StreamOperationType.Write;
try
{
if (blocks.UrlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume) && File.Exists(stream.rrqmPath))
{
stream.fileStream = new FileStream(stream.rrqmPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
int blocksLength = (int)(stream.fileStream.Length - blocks.UrlFileInfo.FileLength);
if (blocksLength > 0)
{
stream.fileStream.Position = blocks.UrlFileInfo.FileLength;
byte[] buffer = new byte[blocksLength];
stream.fileStream.Read(buffer, 0, buffer.Length);
try
{
PBCollectionTemp readBlocks = SerializeConvert.RRQMBinaryDeserialize<PBCollectionTemp>(buffer);
if (readBlocks.UrlFileInfo != null && blocks.UrlFileInfo != null && readBlocks.UrlFileInfo.FileHash != null)
{
if (readBlocks.UrlFileInfo.FileHash == blocks.UrlFileInfo.FileHash)
{
stream.blocks = blocks = readBlocks.ToPBCollection();
mes = null;
return true;
}
}
}
catch
{
}
}
stream.fileStream.Dispose();
}
stream.blocks = blocks;
if (File.Exists(stream.rrqmPath))
{
File.Delete(stream.rrqmPath);
}
stream.fileStream = new FileStream(stream.rrqmPath, FileMode.Create, FileAccess.ReadWrite);
stream.SaveProgressBlockCollection();
mes = null;
return true;
}
catch (Exception ex)
{
mes = ex.Message;
stream.Dispose();
stream = null;
return false;
}
}
internal bool FinishStream()
{
this.fileStream.SetLength(this.urlFileInfo.FileLength);
this.fileStream.Flush();
UrlFileInfo info = this.urlFileInfo;
this.Dispose();
if (File.Exists(info.SaveFullPath))
{
File.Delete(info.SaveFullPath);
}
File.Move(info.SaveFullPath + ".rrqm", info.SaveFullPath);
return true;
}
internal void Dispose()
{
this.blocks = null;
this.urlFileInfo = null;
if (this.fileStream != null)
{
this.fileStream.Dispose();
this.fileStream = null;
}
}
internal void SaveProgressBlockCollection()
{
byte[] dataBuffer = SerializeConvert.RRQMBinarySerialize(PBCollectionTemp.GetFromProgressBlockCollection(blocks), true);
this.fileStream.Position = this.urlFileInfo.FileLength;
this.fileStream.WriteAsync(dataBuffer, 0, dataBuffer.Length);
this.fileStream.Flush();
}
}
}

View File

@@ -1,93 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 只读
/// </summary>
/// <typeparam name="T"></typeparam>
public class ReadOnlyList<T> : IEnumerable<T>
{
private List<T> list = new List<T>();
internal void Add(T block)
{
list.Add(block);
}
internal void AddRange(IEnumerable<T> collection)
{
list.AddRange(collection);
}
internal void Remove(T block)
{
list.Remove(block);
}
internal void RemoveAt(int index)
{
list.RemoveAt(index);
}
internal void RemoveAll(Predicate<T> match)
{
list.RemoveAll(match);
}
internal void RemoveRange(int index, int range)
{
list.RemoveRange(index, range);
}
internal void Clear()
{
list.Clear();
}
internal void Insert(int index, T item)
{
list.Insert(index, item);
}
internal void InsertRange(int index, IEnumerable<T> collection)
{
list.InsertRange(index, collection);
}
/// <summary>
/// 返回迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<T> GetEnumerator()
{
return this.list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.list.GetEnumerator();
}
/// <summary>
/// 获取对象
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T this[int index] { get { return list[index]; } }
}
}

View File

@@ -1,22 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
///
/// </summary>
internal class Speed
{
internal static long downloadSpeed;
internal static long uploadSpeed;
}
}

View File

@@ -1,92 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 传输集合
/// </summary>
public class TransferCollection : IEnumerable<UrlFileInfo>
{
internal TransferCollection()
{
list = new List<UrlFileInfo>();
}
internal event RRQMMessageEventHandler OnCollectionChanged;
private List<UrlFileInfo> list;
/// <summary>
/// 返回一个循环访问集合的枚举器
/// </summary>
/// <returns></returns>
public IEnumerator<UrlFileInfo> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
internal void Add(UrlFileInfo fileInfo)
{
this.list.Add(fileInfo);
Task.Run(() =>
{
OnCollectionChanged?.Invoke(null, new MesEventArgs("添加"));
});
}
internal void Clear()
{
this.list.Clear();
Task.Run(() =>
{
OnCollectionChanged?.Invoke(null, new MesEventArgs("清空"));
});
}
internal bool Remove(UrlFileInfo fileInfo)
{
Task.Run(() =>
{
OnCollectionChanged?.Invoke(null, new MesEventArgs("移除"));
});
return this.list.Remove(fileInfo);
}
internal bool GetFirst(out UrlFileInfo fileInfo)
{
lock (this)
{
if (this.list.Count > 0)
{
fileInfo = this.list[0];
this.list.RemoveAt(0);
Task.Run(() =>
{
OnCollectionChanged?.Invoke(null, new MesEventArgs("进入传输"));
});
return true;
}
fileInfo = null;
return false;
}
}
}
}

View File

@@ -1,203 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections.Concurrent;
using System.IO;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 传输文件Hash暂存字典
/// </summary>
public static class TransferFileHashDictionary
{
private static ConcurrentDictionary<string, UrlFileInfo> fileHashAndInfo = new ConcurrentDictionary<string, UrlFileInfo>();
private static ConcurrentDictionary<string, UrlFileInfo> filePathAndInfo = new ConcurrentDictionary<string, UrlFileInfo>();
/// <summary>
/// 字典存储文件Hash的最大数量默认为10000
/// </summary>
public static int MaxCount { get; set; } = 10000;
/// <summary>
/// 添加文件信息
/// </summary>
/// <param name="filePath"></param>
/// <param name="breakpointResume"></param>
/// <returns></returns>
public static UrlFileInfo AddFile(string filePath, bool breakpointResume = true)
{
UrlFileInfo urlFileInfo = new UrlFileInfo();
using (FileStream stream = File.OpenRead(filePath))
{
urlFileInfo.FilePath = filePath;
urlFileInfo.FileLength = stream.Length;
urlFileInfo.FileName = Path.GetFileName(filePath);
if (breakpointResume)
{
urlFileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
}
}
AddFile(urlFileInfo);
return urlFileInfo;
}
/// <summary>
/// 添加文件信息
/// </summary>
/// <param name="urlFileInfo"></param>
public static void AddFile(UrlFileInfo urlFileInfo)
{
if (urlFileInfo == null)
{
return;
}
filePathAndInfo.AddOrUpdate(urlFileInfo.FilePath, urlFileInfo, (key, oldValue) =>
{
return urlFileInfo;
});
if (!string.IsNullOrEmpty(urlFileInfo.FileHash))
{
fileHashAndInfo.AddOrUpdate(urlFileInfo.FileHash, urlFileInfo, (key, oldValue) =>
{
return urlFileInfo;
});
}
if (filePathAndInfo.Count > MaxCount)
{
foreach (var item in filePathAndInfo.Keys)
{
if (filePathAndInfo.TryRemove(item, out _))
{
break;
}
}
}
if (fileHashAndInfo.Count > MaxCount)
{
foreach (var item in fileHashAndInfo.Keys)
{
if (fileHashAndInfo.TryRemove(item, out _))
{
break;
}
}
}
}
/// <summary>
/// 清除全部
/// </summary>
public static void ClearDictionary()
{
if (filePathAndInfo == null)
{
return;
}
filePathAndInfo.Clear();
}
/// <summary>
/// 获取文件信息
/// </summary>
/// <param name="filePath"></param>
/// <param name="urlFileInfo"></param>
/// <param name="breakpointResume"></param>
/// <returns></returns>
public static bool GetFileInfo(string filePath, out UrlFileInfo urlFileInfo, bool breakpointResume)
{
if (filePathAndInfo == null)
{
urlFileInfo = null;
return false;
}
if (filePathAndInfo.ContainsKey(filePath))
{
urlFileInfo = filePathAndInfo[filePath];
if (File.Exists(filePath))
{
using (FileStream stream = File.OpenRead(filePath))
{
if (urlFileInfo.FileLength == stream.Length)
{
if (breakpointResume && urlFileInfo.FileHash == null)
{
urlFileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
AddFile(urlFileInfo);
}
return true;
}
}
}
}
urlFileInfo = null;
return false;
}
/// <summary>
/// 通过FileHash获取文件信息
/// </summary>
/// <param name="fileHash"></param>
/// <param name="urlFileInfo"></param>
/// <returns></returns>
public static bool GetFileInfoFromHash(string fileHash, out UrlFileInfo urlFileInfo)
{
if (fileHashAndInfo == null)
{
urlFileInfo = null;
return false;
}
if (string.IsNullOrEmpty(fileHash))
{
urlFileInfo = null;
return false;
}
if (fileHashAndInfo.TryGetValue(fileHash, out urlFileInfo))
{
if (urlFileInfo.FileHash == fileHash)
{
if (File.Exists(urlFileInfo.FilePath))
{
using (FileStream stream = File.OpenRead(urlFileInfo.FilePath))
{
if (urlFileInfo.FileLength == stream.Length)
{
return true;
}
}
}
}
}
urlFileInfo = null;
return false;
}
/// <summary>
/// 移除
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static bool Remove(string filePath)
{
if (filePathAndInfo == null)
{
return false;
}
return filePathAndInfo.TryRemove(filePath, out _);
}
}
}

View File

@@ -1,166 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.IO;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件信息类
/// </summary>
public class UrlFileInfo
{
private string saveFullPath = string.Empty;
private int timeout = 30 * 1000;
/// <summary>
/// 文件哈希值
/// </summary>
public string FileHash { get; internal set; }
/// <summary>
/// 文件大小
/// </summary>
public long FileLength { get; internal set; }
/// <summary>
/// 文件名
/// </summary>
public string FileName { get; internal set; }
/// <summary>
/// 文件路径
/// </summary>
public string FilePath { get; internal set; }
/// <summary>
/// 传输标识
/// </summary>
public TransferFlags Flags { get; set; }
/// <summary>
/// 携带消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 存放目录
/// </summary>
public string SaveFullPath
{
get { return saveFullPath; }
set
{
if (value == null)
{
value = string.Empty;
}
saveFullPath = value;
}
}
/// <summary>
/// 超时时间默认30*1000 ms
/// </summary>
public int Timeout
{
get { return timeout; }
set { timeout = value; }
}
/// <summary>
/// 请求传输类型
/// </summary>
public TransferType TransferType { get; internal set; }
/// <summary>
/// 生成下载请求必要信息
/// </summary>
/// <param name="path"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static UrlFileInfo CreateDownload(string path, TransferFlags flags)
{
UrlFileInfo fileInfo = new UrlFileInfo();
fileInfo.FilePath = path;
fileInfo.Flags = flags;
fileInfo.FileName = Path.GetFileName(path);
fileInfo.TransferType = TransferType.Download;
return fileInfo;
}
/// <summary>
/// 生成上传请求必要信息
/// </summary>
/// <param name="path"></param>
/// <param name="flags"></param>
/// <returns></returns>
public static UrlFileInfo CreateUpload(string path, TransferFlags flags)
{
UrlFileInfo fileInfo = new UrlFileInfo();
fileInfo.TransferType = TransferType.Upload;
using (FileStream stream = File.OpenRead(path))
{
fileInfo.Flags = flags;
fileInfo.FilePath = path;
if (flags.HasFlag(TransferFlags.BreakpointResume) || flags.HasFlag(TransferFlags.QuickTransfer))
{
fileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
}
fileInfo.FileLength = stream.Length;
fileInfo.FileName = Path.GetFileName(path);
}
return fileInfo;
}
/// <summary>
/// 复制
/// </summary>
/// <param name="urlFileInfo"></param>
public void CopyFrom(UrlFileInfo urlFileInfo)
{
this.FileHash = urlFileInfo.FileHash;
this.FileLength = urlFileInfo.FileLength;
this.FileName = urlFileInfo.FileName;
this.FilePath = urlFileInfo.FilePath;
}
/// <summary>
/// 判断参数是否相同
/// </summary>
/// <param name="urlFileInfo"></param>
/// <returns></returns>
public bool Equals(UrlFileInfo urlFileInfo)
{
if (urlFileInfo.FileHash != this.FileHash)
{
return false;
}
if (urlFileInfo.FileLength != this.FileLength)
{
return false;
}
if (urlFileInfo.FileName != this.FileName)
{
return false;
}
if (urlFileInfo.FilePath != this.FilePath)
{
return false;
}
return true;
}
}
}

View File

@@ -1,86 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Dependency;
using RRQMSocket.RPC.RRQMRPC;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件客户端配置
/// </summary>
public class FileClientConfig : TcpRpcClientConfig
{
/// <summary>
/// 构造函数
/// </summary>
public FileClientConfig()
{
this.BufferLength = 64 * 1024;
}
/// <summary>
/// 默认接收文件的存放目录
/// </summary>
public string ReceiveDirectory
{
get { return (string)GetValue(ReceiveDirectoryProperty); }
set
{
if (value == null)
{
value = string.Empty;
}
SetValue(ReceiveDirectoryProperty, value);
}
}
/// <summary>
/// 默认接收文件的存放目录, 所需类型<see cref="string"/>
/// </summary>
public static readonly DependencyProperty ReceiveDirectoryProperty =
DependencyProperty.Register("ReceiveDirectory", typeof(string), typeof(FileClientConfig), string.Empty);
/// <summary>
/// 单次请求超时时间 min=5000,max=60*1000 ms
/// </summary>
public int Timeout
{
get { return (int)GetValue(TimeoutProperty); }
set
{
SetValue(TimeoutProperty, value);
}
}
/// <summary>
/// 单次请求超时时间 min=5000,max=60*1000 ms, 所需类型<see cref="int"/>
/// </summary>
public static readonly DependencyProperty TimeoutProperty =
DependencyProperty.Register("Timeout", typeof(int), typeof(FileClientConfig), 10*1000);
/// <summary>
/// 数据包尺寸
/// </summary>
public int PacketSize
{
get { return (int)GetValue(PacketSizeProperty); }
set { SetValue(PacketSizeProperty, value); }
}
/// <summary>
/// 数据包尺寸, 所需类型<see cref="int"/>
/// </summary>
[RRQMCore.Range]
public static readonly DependencyProperty PacketSizeProperty =
DependencyProperty.Register("PacketSize", typeof(int), typeof(FileClientConfig), 1024 * 1024);
}
}

View File

@@ -1,60 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Dependency;
using RRQMSocket.RPC.RRQMRPC;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件服务器配置
/// </summary>
public class FileServiceConfig : TcpRpcParserConfig
{
/// <summary>
/// 构造函数
/// </summary>
public FileServiceConfig()
{
this.BufferLength = 64 * 1024;
}
/// <summary>
/// 最大下载速度
/// </summary>
public long MaxDownloadSpeed
{
get { return (long)GetValue(MaxDownloadSpeedProperty); }
set { SetValue(MaxDownloadSpeedProperty, value); }
}
/// <summary>
/// 最大下载速度, 所需类型<see cref="long"/>
/// </summary>
public static readonly DependencyProperty MaxDownloadSpeedProperty =
DependencyProperty.Register("MaxDownloadSpeed", typeof(long), typeof(FileServiceConfig), 1024 * 1024L);
/// <summary>
/// 最大上传速度
/// </summary>
public long MaxUploadSpeed
{
get { return (long)GetValue(MaxUploadSpeedProperty); }
set { SetValue(MaxUploadSpeedProperty, value); }
}
/// <summary>
/// 最大上传速度, 所需类型<see cref="long"/>
/// </summary>
public static readonly DependencyProperty MaxUploadSpeedProperty =
DependencyProperty.Register("MaxUploadSpeed", typeof(long), typeof(FileServiceConfig), 1024 * 1024L);
}
}

View File

@@ -1,28 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 传输文件操作处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public delegate void RRQMFileOperationEventHandler(object sender, FileOperationEventArgs e);
/// <summary>
/// 传输文件消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public delegate void RRQMTransferFileMessageEventHandler(object sender, TransferFileMessageArgs e);
}

View File

@@ -1,39 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件Hash检验类型
/// </summary>
public enum FileHashType : byte
{
/// <summary>
/// MD5
/// </summary>
MD5,
/// <summary>
/// SHA1
/// </summary>
SHA1,
/// <summary>
/// SHA256
/// </summary>
SHA256,
/// <summary>
/// SHA512
/// </summary>
SHA512
}
}

View File

@@ -1,34 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 请求状态
/// </summary>
public enum RequestStatus : byte
{
/// <summary>
/// 未开始
/// </summary>
Hovering,
/// <summary>
/// 正在进行
/// </summary>
InProgress,
/// <summary>
/// 完成
/// </summary>
Finished
}
}

View File

@@ -1,29 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 流操作类型
/// </summary>
public enum StreamOperationType : byte
{
/// <summary>
/// 读
/// </summary>
Read,
/// <summary>
/// 写
/// </summary>
Write
}
}

View File

@@ -1,37 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 传输标识
/// </summary>
[Flags]
public enum TransferFlags
{
/// <summary>
/// 无任何标识
/// </summary>
None = 0,
/// <summary>
/// 断点续传
/// </summary>
BreakpointResume = 1,
/// <summary>
/// 快速传输
/// </summary>
QuickTransfer = 2
}
}

View File

@@ -1,44 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 传输类型
/// </summary>
public enum TransferStatus
{
/// <summary>
/// 无下载
/// </summary>
None,
/// <summary>
/// 上传
/// </summary>
Upload,
/// <summary>
/// 下载
/// </summary>
Download,
/// <summary>
/// 暂停下载状态
/// </summary>
PauseDownload,
/// <summary>
/// 暂停上传状态
/// </summary>
PauseUpload
}
}

View File

@@ -1,30 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 传输类型
/// </summary>
public enum TransferType
{
/// <summary>
/// 上传
/// </summary>
Upload,
/// <summary>
/// 下载
/// </summary>
Download,
}
}

View File

@@ -1,24 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 操作文件事件类
/// </summary>
public class FileOperationEventArgs : TransferFileMessageArgs
{
/// <summary>
/// 是否允许操作
/// </summary>
public bool IsPermitOperation { get; set; }
}
}

View File

@@ -1,29 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件传输消息
/// </summary>
public class TransferFileMessageArgs : MesEventArgs
{
/// <summary>
/// 文件信息
/// </summary>
public UrlFileInfo UrlFileInfo { get; internal set; }
/// <summary>
/// 传输类型
/// </summary>
public TransferType TransferType { get; internal set; }
}
}

View File

@@ -1,48 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Exceptions;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 传输错误
/// </summary>
public class RRQMTransferErrorException : RRQMException
{
/// <summary>
///
/// </summary>
public RRQMTransferErrorException() : base() { }
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public RRQMTransferErrorException(string message) : base(message) { }
/// <summary>
///
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
public RRQMTransferErrorException(string message, System.Exception inner) : base(message, inner) { }
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected RRQMTransferErrorException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}

View File

@@ -1,52 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Exceptions;
namespace RRQMSocket.FileTransfer
{
/*
若汝棋茗
*/
/// <summary>
/// 没有传输任务异常
/// </summary>
public class RRQMTransferingException : RRQMException
{
/// <summary>
///
/// </summary>
public RRQMTransferingException() : base() { }
/// <summary>
///
/// </summary>
/// <param name="message"></param>
public RRQMTransferingException(string message) : base(message) { }
/// <summary>
///
/// </summary>
/// <param name="message"></param>
/// <param name="inner"></param>
public RRQMTransferingException(string message, System.Exception inner) : base(message, inner) { }
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected RRQMTransferingException(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}

View File

@@ -1,40 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 文件终端接口
/// </summary>
public interface IFileClient
{
/// <summary>
/// 获取当前传输文件信息
/// </summary>
UrlFileInfo TransferFileInfo { get; }
/// <summary>
/// 获取当前传输进度
/// </summary>
float TransferProgress { get; }
/// <summary>
/// 获取当前传输速度
/// </summary>
long TransferSpeed { get; }
/// <summary>
/// 获取当前传输状态
/// </summary>
TransferStatus TransferStatus { get; }
}
}

View File

@@ -1,30 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 服务器接口
/// </summary>
public interface IFileService
{
/// <summary>
/// 最大下载速度
/// </summary>
long MaxDownloadSpeed { get; set; }
/// <summary>
/// 最大上传速度
/// </summary>
long MaxUploadSpeed { get; set; }
}
}

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license procotol 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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,71 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<ApplicationIcon>RRQM.ico</ApplicationIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
<Version>5.6.0</Version>
<Company>若汝棋茗</Company>
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
<Description>介绍RRQMSocket.FileTransfer是一个轻量级文件传输框架您可以用它传输任意大小的文件它可以完美支持断点续传、快速上传、传输限速等。在实时测试中它的传输速率可达1000Mb/s。
更新说明:
无特殊优化。
APIhttps://gitee.com/RRQM_OS/RRQM/wikis/pages
Demohttps://gitee.com/RRQM_OS/RRQMBox</Description>
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
<PackageIconUrl></PackageIconUrl>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PackageIcon>RRQM.png</PackageIcon>
<Authors>若汝棋茗</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageTags>FileTransfer,TCP,IOCP,BreakpointResume</PackageTags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.FileTransfer.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.FileTransfer.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
<DocumentationFile>bin\Debug\net45\RRQMSocket.FileTransfer.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
<DocumentationFile>bin\Release\net45\RRQMSocket.FileTransfer.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.FileTransfer.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.FileTransfer.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="RRQM.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="RRQMSocket.RPC" Version="5.6.0" />
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,130 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMSocket.RPC.RRQMRPC;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 通讯服务端主类
/// </summary>
public class FileService : TcpParser<FileSocketClient>, IFileService
{
#region
private long maxDownloadSpeed;
private long maxUploadSpeed;
/// <summary>
/// 获取下载速度
/// </summary>
public long DownloadSpeed
{
get
{
this.downloadSpeed = Speed.downloadSpeed;
Speed.downloadSpeed = 0;
return this.downloadSpeed;
}
}
/// <summary>
/// 最大下载速度
/// </summary>
public long MaxDownloadSpeed
{
get { return maxDownloadSpeed; }
set { maxUploadSpeed = value; }
}
/// <summary>
/// 最大上传速度
/// </summary>
public long MaxUploadSpeed
{
get { return maxUploadSpeed; }
set { maxUploadSpeed = value; }
}
/// <summary>
/// 获取上传速度
/// </summary>
public long UploadSpeed
{
get
{
this.uploadSpeed = Speed.uploadSpeed;
Speed.uploadSpeed = 0;
return this.uploadSpeed;
}
}
#endregion
#region
private long downloadSpeed;
private long uploadSpeed;
#endregion
#region
/// <summary>
/// 传输文件之前
/// </summary>
public event RRQMFileOperationEventHandler BeforeFileTransfer;
/// <summary>
/// 当文件传输完成时
/// </summary>
public event RRQMTransferFileMessageEventHandler FinishedFileTransfer;
#endregion
/// <summary>
/// 载入配置
/// </summary>
/// <param name="serviceConfig"></param>
protected override void LoadConfig(ServiceConfig serviceConfig)
{
base.LoadConfig(serviceConfig);
this.maxDownloadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxDownloadSpeedProperty);
this.maxUploadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxUploadSpeedProperty);
}
/// <summary>
/// 创建完成FileSocketClient
/// </summary>
/// <param name="socketClient"></param>
/// <param name="creatOption"></param>
protected override void OnCreateSocketCliect(FileSocketClient socketClient, CreateOption creatOption)
{
base.OnCreateSocketCliect(socketClient, creatOption);
socketClient.MaxDownloadSpeed = this.MaxDownloadSpeed;
socketClient.MaxUploadSpeed = this.MaxUploadSpeed;
socketClient.BeforeFileTransfer = this.OnBeforeFileTransfer;
socketClient.FinishedFileTransfer = this.OnFinishedFileTransfer;
}
private void OnBeforeFileTransfer(object sender, FileOperationEventArgs e)
{
this.BeforeFileTransfer?.Invoke(sender, e);
}
private void OnFinishedFileTransfer(object sender, TransferFileMessageArgs e)
{
this.FinishedFileTransfer?.Invoke(sender, e);
}
}
}

View File

@@ -1,685 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Log;
using RRQMCore.Serialization;
using RRQMSocket.RPC.RRQMRPC;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace RRQMSocket.FileTransfer
{
/// <summary>
/// 已接收的客户端
/// </summary>
public class FileSocketClient : RpcSocketClient, IFileService, IFileClient
{
/// <summary>
/// 传输文件之前
/// </summary>
internal RRQMFileOperationEventHandler BeforeFileTransfer;
/// <summary>
/// 当文件传输完成时
/// </summary>
internal RRQMTransferFileMessageEventHandler FinishedFileTransfer;
private long dataTransferLength;
private long maxDownloadSpeed = 1024 * 1024;
private long maxUploadSpeed = 1024 * 1024;
private long position;
private float progress;
private string rrqmPath;
private long speed;
private Stopwatch stopwatch = new Stopwatch();
private long tempLength;
private long timeTick;
private TransferStatus transferStatus;
private UrlFileInfo transferUrlFileInfo;
static FileSocketClient()
{
AddUsedProtocol(110, "同步设置");
AddUsedProtocol(111, "通用信道返回");
AddUsedProtocol(112, "请求下载");
AddUsedProtocol(113, "下载文件分块");
AddUsedProtocol(114, "退出下载通道");
AddUsedProtocol(115, "确认下载完成");
AddUsedProtocol(116, "请求上传");
AddUsedProtocol(117, "上传分块");
AddUsedProtocol(118, "停止上传");
AddUsedProtocol(119, "确认上传完成");
AddUsedProtocol(120, "智能包调节");
for (short i = 121; i < 200; i++)
{
AddUsedProtocol(i, "保留协议");
}
}
/// <summary>
/// 每秒最大下载速度Byte,不可小于1024
/// </summary>
public long MaxDownloadSpeed
{
get { return maxDownloadSpeed; }
set
{
if (value < 1024)
{
value = 1024;
}
this.maxDownloadSpeed = value;
}
}
/// <summary>
/// 每秒最大上传速度Byte,不可小于1024
/// </summary>
public long MaxUploadSpeed
{
get { return maxUploadSpeed; }
set
{
if (value < 1024)
{
value = 1024;
}
this.maxUploadSpeed = value;
}
}
/// <summary>
/// 获取当前传输文件信息
/// </summary>
public UrlFileInfo TransferFileInfo { get => this.transferUrlFileInfo; }
/// <summary>
/// 获取当前传输进度
/// </summary>
public float TransferProgress
{
get
{
if (transferUrlFileInfo == null)
{
return 0;
}
this.progress = transferUrlFileInfo.FileLength > 0 ? (float)position / transferUrlFileInfo.FileLength : 0;//计算下载完成进度
return progress <= 1 ? progress : 1;
}
}
/// <summary>
/// 获取当前传输速度
/// </summary>
public long TransferSpeed
{
get
{
this.speed = tempLength;
tempLength = 0;
return speed;
}
}
/// <summary>
/// 获取当前传输状态
/// </summary>
public TransferStatus TransferStatus
{
get { return transferStatus; }
}
/// <summary>
/// 释放资源
/// </summary>
public override void Dispose()
{
base.Dispose();
this.ResetVariable();
}
/// <summary>
/// 文件辅助类处理其他协议
/// </summary>
/// <param name="procotol"></param>
/// <param name="byteBlock"></param>
protected virtual void FileSocketClientHandleDefaultData(short? procotol, ByteBlock byteBlock)
{
this.OnHandleDefaultData(procotol, byteBlock);
}
/// <summary>
/// 封装协议
/// </summary>
/// <param name="procotol"></param>
/// <param name="byteBlock"></param>
protected sealed override void RPCHandleDefaultData(short? procotol, ByteBlock byteBlock)
{
byte[] buffer = byteBlock.Buffer;
switch (procotol)
{
case 110:
{
try
{
//this.P110_SynchronizeTransferSetting();
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 112:
{
try
{
UrlFileInfo fileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(buffer, 2);
P112_RequestDownload(fileInfo);
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 113:
{
try
{
P113_DownloadBlockData(byteBlock);
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 114:
{
try
{
P114_StopDownload();
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 115:
{
try
{
P115_DownloadFinished();
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 116:
{
try
{
UrlFileInfo urlFileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(buffer, 2);
P116_RequestUpload(urlFileInfo);
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 117:
{
try
{
P117_UploadBlockData(buffer);
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 118:
{
try
{
P118_StopUpload();
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
case 119:
{
try
{
P119_UploadFinished();
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, ex.Message, ex);
}
break;
}
default:
{
this.FileSocketClientHandleDefaultData(procotol, byteBlock);
break;
}
}
}
/// <summary>
/// 继承
/// </summary>
protected override void WaitReceive()
{
if (this.GetNowTick() - timeTick > 0)
{
//时间过了一秒
this.timeTick = GetNowTick();
this.dataTransferLength = 0;
this.dataTransferLength = 0;
stopwatch.Restart();
}
else
{
//在这一秒中
switch (this.transferStatus)
{
case TransferStatus.Upload:
if (this.dataTransferLength > this.maxUploadSpeed)
{
//上传饱和
stopwatch.Stop();
int sleepTime = 1000 - (int)stopwatch.ElapsedMilliseconds <= 0 ? 0 : 1000 - (int)stopwatch.ElapsedMilliseconds;
Thread.Sleep(sleepTime);
}
break;
case TransferStatus.Download:
if (this.dataTransferLength > this.maxDownloadSpeed)
{
//下载饱和
stopwatch.Stop();
int sleepTime = 1000 - (int)stopwatch.ElapsedMilliseconds <= 0 ? 0 : 1000 - (int)stopwatch.ElapsedMilliseconds;
Thread.Sleep(sleepTime);
}
break;
}
}
}
/// <summary>
/// 获取当前时间帧
/// </summary>
/// <returns></returns>
private long GetNowTick()
{
return DateTime.Now.Ticks / 10000000;
}
private FileOperationEventArgs OnBeforeFileTransfer(UrlFileInfo urlFileInfo)
{
FileOperationEventArgs args = new FileOperationEventArgs();
args.UrlFileInfo = urlFileInfo;
args.TransferType = urlFileInfo.TransferType;
args.IsPermitOperation = true;
if (urlFileInfo.TransferType == TransferType.Download)
{
//下载
urlFileInfo.FilePath = Path.GetFullPath(urlFileInfo.FilePath);
}
try
{
this.BeforeFileTransfer?.Invoke(this, args);//触发 接收文件事件
}
catch (Exception ex)
{
this.Logger.Debug(LogType.Error, this, $"在事件{nameof(BeforeFileTransfer)}中发生异常", ex);
}
if (urlFileInfo.TransferType == TransferType.Upload)
{
urlFileInfo.SaveFullPath = Path.GetFullPath(string.IsNullOrEmpty(urlFileInfo.SaveFullPath) ? urlFileInfo.FileName : urlFileInfo.SaveFullPath);
this.rrqmPath = urlFileInfo.SaveFullPath + ".rrqm";
}
this.transferUrlFileInfo = urlFileInfo;
return args;
}
private void OnFinishedFileTransfer(TransferType transferType)
{
if (!string.IsNullOrEmpty(this.transferUrlFileInfo.FileHash))
{
TransferFileHashDictionary.AddFile(this.transferUrlFileInfo);
}
TransferFileMessageArgs args = new TransferFileMessageArgs();
args.UrlFileInfo = this.transferUrlFileInfo;
args.TransferType = transferType;
if (transferType == TransferType.Download)
{
FileStreamPool.DisposeReadStream(this.transferUrlFileInfo.FilePath);
}
else
{
FileStreamPool.DisposeWriteStream(this.rrqmPath, true);
this.rrqmPath = null;
}
this.transferStatus = TransferStatus.None;
this.transferUrlFileInfo = null;
try
{
this.FinishedFileTransfer?.Invoke(this, args);
}
catch (Exception ex)
{
this.Logger.Debug(LogType.Error, this, $"在事件{nameof(FinishedFileTransfer)}中发生异常", ex);
}
this.ResetVariable();
}
private void P112_RequestDownload(UrlFileInfo urlFileInfo)
{
FileOperationEventArgs args = OnBeforeFileTransfer(urlFileInfo);
FileWaitResult waitResult = new FileWaitResult();
if (!args.IsPermitOperation)
{
waitResult.Message = string.IsNullOrEmpty(args.Message) ? "服务器拒绝下载" : args.Message;
waitResult.Status = 2;
this.transferStatus = TransferStatus.None;
}
else if (!File.Exists(urlFileInfo.FilePath))
{
waitResult.Message = $"路径{urlFileInfo.FilePath}文件不存在";
waitResult.Status = 2;
this.transferStatus = TransferStatus.None;
}
else
{
UrlFileInfo fileInfo;
if (!TransferFileHashDictionary.GetFileInfo(urlFileInfo.FilePath, out fileInfo, urlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume)))
{
fileInfo = TransferFileHashDictionary.AddFile(urlFileInfo.FilePath, urlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume));
}
urlFileInfo.CopyFrom(fileInfo);
if (FileStreamPool.LoadReadStream(ref urlFileInfo, out string mes))
{
this.transferStatus = TransferStatus.Download;
waitResult.Message = null;
waitResult.Status = 1;
this.transferUrlFileInfo = urlFileInfo;
waitResult.PBCollectionTemp = new PBCollectionTemp();
waitResult.PBCollectionTemp.UrlFileInfo = urlFileInfo;
}
else
{
waitResult.Message = mes;
waitResult.Status = 2;
}
}
this.SendDefaultObject(waitResult);
}
private void P113_DownloadBlockData(ByteBlock receivedByteBlock)
{
receivedByteBlock.Pos = 2;
long position = receivedByteBlock.ReadInt64();
int requestLength = receivedByteBlock.ReadInt32();
ByteBlock byteBlock = this.BytePool.GetByteBlock(requestLength + 7);
if (this.transferStatus != TransferStatus.Download)
{
byteBlock.Buffer[6] = 0;
}
string mes;
if (FileStreamPool.ReadFile(transferUrlFileInfo.FilePath, out mes, position, byteBlock, 7, requestLength))
{
Speed.downloadSpeed += requestLength;
this.position = position + requestLength;
this.tempLength += requestLength;
this.dataTransferLength += requestLength;
byteBlock.Buffer[6] = 1;
}
else
{
byteBlock.Position = 6;
byteBlock.Write((byte)2);
byteBlock.Write(Encoding.UTF8.GetBytes(string.IsNullOrEmpty(mes) ? "未知错误" : mes));
}
try
{
if (this.Online)
{
this.InternalSend(111, byteBlock.Buffer, 0, byteBlock.Len, true);
}
}
finally
{
byteBlock.Dispose();
}
}
private void P114_StopDownload()
{
this.transferUrlFileInfo = null;
this.transferStatus = TransferStatus.None;
this.InternalSend(111, new byte[] { 1 }, 0, 1);
}
private void P115_DownloadFinished()
{
if (this.transferStatus == TransferStatus.None)
{
this.InternalSend(111, new byte[] { 1 }, 0, 1);
return;
}
this.InternalSend(111, new byte[] { 1 }, 0, 1);
OnFinishedFileTransfer(TransferType.Download);
}
private void P116_RequestUpload(UrlFileInfo urlFileInfo)
{
FileOperationEventArgs args = OnBeforeFileTransfer(urlFileInfo);
FileWaitResult waitResult = new FileWaitResult();
if (!args.IsPermitOperation)
{
waitResult.Status = 2;
waitResult.Message = string.IsNullOrEmpty(args.Message) ? "服务器拒绝上传" : args.Message;
}
else
{
this.transferStatus = TransferStatus.Upload;
this.transferUrlFileInfo = urlFileInfo;
if (urlFileInfo.Flags.HasFlag(TransferFlags.QuickTransfer) && TransferFileHashDictionary.GetFileInfoFromHash(urlFileInfo.FileHash, out UrlFileInfo oldUrlFileInfo))
{
try
{
if (urlFileInfo.FilePath != oldUrlFileInfo.FilePath)
{
File.Copy(oldUrlFileInfo.FilePath, urlFileInfo.FilePath, true);
}
waitResult.Status = 3;
waitResult.Message = null;
this.SendDefaultObject(waitResult);
return;
}
catch (Exception ex)
{
waitResult.Status = 2;
waitResult.Message = ex.Message;
this.Logger.Debug(LogType.Error, this, "在处理快速上传时发生异常。", ex);
}
}
try
{
ProgressBlockCollection blocks = ProgressBlockCollection.CreateProgressBlockCollection(urlFileInfo);
if (FileStreamPool.LoadWriteStream(ref blocks, false, out string mes))
{
waitResult.Status = 1;
waitResult.Message = null;
waitResult.PBCollectionTemp = PBCollectionTemp.GetFromProgressBlockCollection(blocks);
}
else
{
waitResult.Status = 2;
waitResult.Message = mes;
}
}
catch (Exception ex)
{
waitResult.Status = 2;
waitResult.Message = ex.Message;
waitResult.PBCollectionTemp = null;
}
}
this.SendDefaultObject(waitResult);
}
private void P117_UploadBlockData(byte[] buffer)
{
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
try
{
if (this.transferStatus != TransferStatus.Upload)
{
byteBlock.Write((byte)4);
}
byte status = buffer[2];
int index = BitConverter.ToInt32(buffer, 3);
long position = BitConverter.ToInt64(buffer, 7);
int submitLength = BitConverter.ToInt32(buffer, 15);
string mes;
if (FileStreamPool.WriteFile(this.rrqmPath, out mes, out RRQMStream stream, position, buffer, 19, submitLength))
{
this.position = position + submitLength;
this.tempLength += submitLength;
this.dataTransferLength += submitLength;
Speed.uploadSpeed += submitLength;
byteBlock.Write((byte)1);
if (status == 1)
{
FileBlock fileProgress = stream.Blocks.FirstOrDefault(a => a.Index == index);
fileProgress.RequestStatus = RequestStatus.Finished;
stream.SaveProgressBlockCollection();
}
}
else
{
byteBlock.Write((byte)2);
byteBlock.Write(Encoding.UTF8.GetBytes(mes));
Logger.Debug(LogType.Error, this, $"上传文件写入错误,信息:{mes}");
}
this.InternalSend(111, byteBlock);
}
catch (Exception ex)
{
Logger.Debug(LogType.Error, this, "上传文件错误", ex);
}
finally
{
byteBlock.Dispose();
}
}
private void P118_StopUpload()
{
try
{
FileStreamPool.SaveProgressBlockCollection(this.rrqmPath);
FileStreamPool.DisposeWriteStream(this.rrqmPath, false);
this.ResetVariable();
this.InternalSend(111, new byte[] { 1 }, 0, 1);
}
catch (Exception ex)
{
this.Logger.Debug(LogType.Error, this, "客户端请求停止上传时发生异常", ex);
}
}
private void P119_UploadFinished()
{
if (this.transferStatus == TransferStatus.None)
{
this.InternalSend(111, new byte[] { 1 }, 0, 1);
return;
}
this.InternalSend(111, new byte[] { 1 }, 0, 1);
OnFinishedFileTransfer(TransferType.Upload);
}
private void ResetVariable()
{
this.transferStatus = TransferStatus.None;
this.transferUrlFileInfo = null;
this.progress = 0;
this.speed = 0;
if (!string.IsNullOrEmpty(this.rrqmPath))
{
FileStreamPool.DisposeWriteStream(this.rrqmPath, false);
this.rrqmPath = null;
}
}
private void SendDefaultObject(object obj)
{
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(obj, true));
try
{
this.InternalSend(111, byteBlock);
}
finally
{
byteBlock.Dispose();
}
}
}
}

View File

@@ -1,258 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace RRQMSocket.Http
{
/// <summary>
/// Http基础头部
/// </summary>
public abstract class HttpBase
{
/// <summary>
/// 构造函数
/// </summary>
public HttpBase()
{
this.headers = new Dictionary<string, string>();
}
/// <summary>
/// 服务器版本
/// </summary>
public static readonly string ServerVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
private string requestLine;
/// <summary>
/// 字符数据
/// </summary>
public string Body { get { return this.content == null ? null : this.encoding.GetString(this.content); } }
private byte[] content;
/// <summary>
/// 内容器
/// </summary>
public byte[] Content
{
get { return content; }
}
/// <summary>
/// 内容编码
/// </summary>
public string Content_Encoding { get; set; }
/// <summary>
/// 内容长度
/// </summary>
public int Content_Length { get; set; }
/// <summary>
/// 内容类型
/// </summary>
public string Content_Type { get; set; }
/// <summary>
/// 内容语言
/// </summary>
public string ContentLanguage { get; set; }
private Encoding encoding = Encoding.UTF8;
/// <summary>
/// 编码方式
/// </summary>
public Encoding Encoding
{
get { return encoding; }
set { encoding = value; }
}
/// <summary>
/// 传递标识
/// </summary>
public object Flag { get; set; }
/// <summary>
/// 请求头集合
/// </summary>
public Dictionary<string, string> Headers { get { return this.headers; } }
private Dictionary<string, string> headers;
/// <summary>
/// 协议名称
/// </summary>
public string Protocols { get; set; }
/// <summary>
/// HTTP协议版本
/// </summary>
public string ProtocolVersion { get; set; } = "1.1";
/// <summary>
/// 请求行
/// </summary>
public string RequestLine
{
get { return requestLine; }
}
/// <summary>
/// 构建数据
/// </summary>
/// <param name="byteBlock"></param>
public abstract void Build(ByteBlock byteBlock);
/// <summary>
/// 获取头值
/// </summary>
/// <param name="header"></param>
/// <returns></returns>
public string GetHeader(HttpHeaders header)
{
return GetHeaderByKey(header);
}
/// <summary>
/// 读取信息
/// </summary>
public abstract void ReadFromBase();
/// <summary>
/// 从内存中读取
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="length"></param>
public void ReadHeaders(byte[] buffer, int offset, int length)
{
string data = Encoding.UTF8.GetString(buffer, offset, length);
string[] rows = Regex.Split(data, Environment.NewLine);
//Request URL & Method & Version
this.requestLine = rows[0];
//Request Headers
GetRequestHeaders(rows);
string contentLength = this.GetHeader(HttpHeaders.ContentLength);
int.TryParse(contentLength, out int content_Length);
this.Content_Length = content_Length;
}
/// <summary>
/// 获取头集合的值
/// </summary>
/// <param name="header"></param>
/// <returns></returns>
protected string GetHeaderByKey(Enum header)
{
var fieldName = header.GetDescription();
if (fieldName == null) return null;
var hasKey = Headers.ContainsKey(fieldName);
if (!hasKey) return null;
return Headers[fieldName];
}
/// <summary>
/// 获取头集合的值
/// </summary>
/// <param name="fieldName"></param>
/// <returns></returns>
protected string GetHeaderByKey(string fieldName)
{
if (string.IsNullOrEmpty(fieldName)) return null;
var hasKey = Headers.ContainsKey(fieldName);
if (!hasKey) return null;
return Headers[fieldName];
}
/// <summary>
/// 设置头值
/// </summary>
protected void SetHeaderByKey(Enum header, string value)
{
var fieldName = header.GetDescription();
if (fieldName == null) return;
var hasKey = Headers.ContainsKey(fieldName);
if (!hasKey) Headers.Add(fieldName, value);
Headers[fieldName] = value;
}
/// <summary>
/// 设置头值
/// </summary>
/// <param name="fieldName"></param>
/// <param name="value"></param>
protected void SetHeaderByKey(string fieldName, string value)
{
if (string.IsNullOrEmpty(fieldName)) return;
var hasKey = Headers.ContainsKey(fieldName);
if (!hasKey) Headers.Add(fieldName, value);
Headers[fieldName] = value;
}
private void GetRequestHeaders(IEnumerable<string> rows)
{
this.headers.Clear();
if (rows == null || rows.Count() <= 0)
{
return;
}
foreach (var item in rows)
{
string[] kv = item.SplitFirst(':');
if (kv.Length == 2)
{
if (!this.headers.ContainsKey(kv[0]))
{
this.headers.Add(kv[0], kv[1]);
}
}
}
}
/// <summary>
/// 设置内容
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
public void SetContent(byte[] content)
{
this.content = content;
this.Content_Length = content.Length;
}
/// <summary>
/// 设置内容
/// </summary>
/// <param name="content"></param>
/// <param name="encoding"></param>
/// <returns></returns>
public void SetContent(string content, Encoding encoding = null)
{
//初始化内容
encoding = encoding != null ? encoding : Encoding.UTF8;
SetContent(encoding.GetBytes(content));
}
}
}

View File

@@ -1,222 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Exceptions;
using RRQMCore.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace RRQMSocket.Http
{
/// <summary>
/// HTTP请求定义
/// </summary>
public class HttpRequest : HttpBase
{
/// <summary>
/// 表单参数
/// </summary>
public Dictionary<string, string> Forms { get; set; }
/// <summary>
/// 获取时候保持连接
/// </summary>
public bool KeepAlive { get; set; }
/// <summary>
/// HTTP请求方式
/// </summary>
public string Method { get; set; }
/// <summary>
/// URL参数
/// </summary>
public Dictionary<string, string> Params { get; set; }
/// <summary>
/// url参数
/// </summary>
public Dictionary<string, string> Query { get; set; }
/// <summary>
/// 相对路径(不含参数)
/// </summary>
public string RelativeURL { get; set; }
/// <summary>
/// HTTP(S)地址
/// </summary>
public string URL { get; set; }
/// <summary>
/// 构建响应头部
/// </summary>
/// <returns></returns>
private void BuildHeader(ByteBlock byteBlock)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"{this.Method} / HTTP/{this.ProtocolVersion}");
this.SetHeader(HttpHeaders.UserAgent, "RRQMHTTP");
if (!string.IsNullOrEmpty(this.Content_Type))
stringBuilder.AppendLine("Content-Type: " + this.Content_Type);
stringBuilder.AppendLine("Content-Length: " + this.Content_Length);
foreach (var headerkey in this.Headers.Keys)
{
stringBuilder.Append($"{headerkey}: ");
stringBuilder.AppendLine(this.Headers[headerkey]);
}
stringBuilder.AppendLine();
byteBlock.Write(this.Encoding.GetBytes(stringBuilder.ToString()));
}
private void BuildContent(ByteBlock byteBlock)
{
if (this.Content_Length > 0)
{
if (this.Content_Length != this.Content.Length)
{
throw new RRQMException("内容实际长度与设置长度不相等");
}
byteBlock.Write(this.Content);
}
}
/// <summary>
/// 构建响应数据
/// </summary>
/// <param name="byteBlock"></param>
public override void Build(ByteBlock byteBlock)
{
BuildHeader(byteBlock);
BuildContent(byteBlock);
}
/// <summary>
/// 获取头值
/// </summary>
/// <param name="fieldName"></param>
/// <returns></returns>
public string GetHeader(string fieldName)
{
return GetHeaderByKey(fieldName);
}
/// <summary>
/// 从内存中读取
/// </summary>
public override void ReadFromBase()
{
var first = Regex.Split(this.RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray();
if (first.Length > 0) this.Method = first[0];
if (first.Length > 1)
{
this.URL = Uri.UnescapeDataString(first[1]);
this.RelativeURL = first[1].Split('?')[0];
}
if (first.Length > 2)
{
string[] ps = first[2].Split('/');
if (ps.Length == 2)
{
this.Protocols = ps[0];
this.ProtocolVersion = ps[1];
}
}
string contentLength = this.GetHeader(HttpHeaders.ContentLength);
int.TryParse(contentLength, out int content_Length);
this.Content_Length = content_Length;
if (this.Method == "GET")
{
var isUrlencoded = this.URL.Contains('?');
if (isUrlencoded) this.Query = GetRequestParameters(URL.Split('?')[1]);
}
if (this.ProtocolVersion == "1.1")
{
if (this.GetHeader(HttpHeaders.Connection) == "keep-alive")
{
this.KeepAlive = true;
}
else
{
this.KeepAlive = false;
}
}
else
{
this.KeepAlive = false;
}
if (this.Method == "POST")
{
this.Content_Type = GetHeader(HttpHeaders.ContentType);
if (this.Content_Type == @"application/x-www-form-urlencoded")
{
this.Params = GetRequestParameters(this.Body);
}
}
}
/// <summary>
/// 设置头值
/// </summary>
/// <param name="header"></param>
/// <param name="value"></param>
public void SetHeader(HttpHeaders header, string value)
{
SetHeaderByKey(header, value);
}
/// <summary>
/// 设置头值
/// </summary>
/// <param name="fieldName"></param>
/// <param name="value"></param>
public void SetHeader(string fieldName, string value)
{
SetHeaderByKey(fieldName, value);
}
private Dictionary<string, string> GetRequestParameters(string row)
{
if (string.IsNullOrEmpty(row))
{
return null;
}
string[] kvs = row.Split('&');
if (kvs == null || kvs.Count() == 0)
{
return null;
}
Dictionary<string, string> pairs = new Dictionary<string, string>();
foreach (var item in kvs)
{
string[] kv = item.SplitFirst('=');
if (kv.Length == 2)
{
pairs.Add(kv[0], kv[1]);
}
}
return pairs;
}
}
}

View File

@@ -1,123 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace RRQMSocket.Http
{
/// <summary>
/// Http响应
/// </summary>
public class HttpResponse : HttpBase
{
/// <summary>
/// 状态码
/// </summary>
public string StatusCode { get; set; }
/// <summary>
/// 获取头数据
/// </summary>
/// <param name="fieldName"></param>
/// <returns></returns>
public string GetHeader(string fieldName)
{
return GetHeaderByKey(fieldName);
}
/// <summary>
/// 设置头数据
/// </summary>
/// <param name="header"></param>
/// <param name="value"></param>
public void SetHeader(HttpHeaders header, string value)
{
SetHeaderByKey(header, value);
}
/// <summary>
/// 设置头数据
/// </summary>
/// <param name="fieldName"></param>
/// <param name="value"></param>
public void SetHeader(string fieldName, string value)
{
SetHeaderByKey(fieldName, value);
}
/// <summary>
/// 构建响应头部
/// </summary>
/// <returns></returns>
private void BuildHeader(ByteBlock byteBlock)
{
StringBuilder stringBuilder = new StringBuilder();
if (!string.IsNullOrEmpty(StatusCode))
stringBuilder.AppendLine($"HTTP/{this.ProtocolVersion} {StatusCode}");
if (!string.IsNullOrEmpty(this.Content_Type))
stringBuilder.AppendLine("Content-Type: " + this.Content_Type);
stringBuilder.AppendLine("Content-Length: " + this.Content_Length);
foreach (var headerkey in this.Headers.Keys)
{
stringBuilder.Append($"{headerkey}: ");
stringBuilder.AppendLine(this.Headers[headerkey]);
}
stringBuilder.AppendLine();
byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString()));
}
private void BuildContent(ByteBlock byteBlock)
{
if (this.Content_Length > 0)
{
byteBlock.Write(this.Content);
}
}
/// <summary>
/// 构建响应数据
/// </summary>
/// <param name="byteBlock"></param>
public override void Build(ByteBlock byteBlock)
{
BuildHeader(byteBlock);
BuildContent(byteBlock);
}
/// <summary>
/// 读取数据
/// </summary>
public override void ReadFromBase()
{
var first = Regex.Split(this.RequestLine, @"(\s+)").Where(e => e.Trim() != string.Empty).ToArray();
if (first.Length > 0)
{
string[] ps = first[0].Split('/');
if (ps.Length == 2)
{
this.Protocols = ps[0];
this.ProtocolVersion = ps[1];
}
}
if (first.Length > 1)
{
this.StatusCode = first[1];
}
string contentLength = this.GetHeader(HttpHeaders.ContentLength);
int.TryParse(contentLength, out int content_Length);
this.Content_Length = content_Length;
}
}
}

View File

@@ -1,185 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Helper;
using RRQMCore.Log;
using System;
using System.Text;
namespace RRQMSocket.Http
{
/// <summary>
/// Http数据处理适配器
/// </summary>
public class HttpDataHandlingAdapter : DataHandlingAdapter
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="maxSize"></param>
/// <param name="httpType"></param>
public HttpDataHandlingAdapter(int maxSize, HttpType httpType)
{
this.MaxSize = maxSize;
this.terminatorCode = Encoding.UTF8.GetBytes("\r\n\r\n");
this.httpType = httpType;
}
private HttpType httpType;
private byte[] terminatorCode;
/// <summary>
/// 允许的最大长度
/// </summary>
public int MaxSize { get; private set; }
private ByteBlock tempByteBlock;
private ByteBlock bodyByteBlock;
private HttpBase httpBase;
/// <summary>
/// 预处理
/// </summary>
/// <param name="byteBlock"></param>
protected override void PreviewReceived(ByteBlock byteBlock)
{
byte[] buffer = byteBlock.Buffer;
int r = byteBlock.Len;
if (this.tempByteBlock != null)
{
this.tempByteBlock.Write(buffer, 0, r);
buffer = this.tempByteBlock.ToArray();
r = this.tempByteBlock.Pos;
this.tempByteBlock.Dispose();
this.tempByteBlock = null;
}
if (this.httpBase == null)
{
this.Split(buffer, 0, r);
}
else
{
int surLen = this.httpBase.Content_Length - this.bodyByteBlock.Len;
if (r == surLen)
{
this.bodyByteBlock.Write(buffer, 0, surLen);
this.PreviewHandle(this.httpBase);
}
else if (r > surLen)
{
this.bodyByteBlock.Write(buffer, 0, surLen);
this.PreviewHandle(this.httpBase);
Split(buffer, surLen, r - surLen);
}
else
{
this.bodyByteBlock.Write(buffer, 0, r);
}
}
}
private void Split(byte[] buffer, int offset, int length)
{
int index = buffer.IndexOfFirst(offset, length, this.terminatorCode);
if (index > 0)
{
switch (this.httpType)
{
case HttpType.Server:
this.httpBase = new HttpRequest();
break;
case HttpType.Client:
this.httpBase = new HttpResponse();
break;
}
this.httpBase.ReadHeaders(buffer, 0, index);
if (this.httpBase.Content_Length > 0)
{
this.bodyByteBlock = this.BytePool.GetByteBlock(this.httpBase.Content_Length);
int surLength = length - (index + 1);
if (surLength-this.httpBase.Content_Length == 0)
{
this.bodyByteBlock.Write(buffer, index + 1, this.httpBase.Content_Length);
this.PreviewHandle(this.httpBase);
}
else if (surLength - this.httpBase.Content_Length > 0)
{
this.bodyByteBlock.Write(buffer, index + 1, this.httpBase.Content_Length);
int indexBuffer = index + 1 + this.httpBase.Content_Length;
this.PreviewHandle(this.httpBase);
this.Split(buffer, indexBuffer, length);
}
else
{
this.bodyByteBlock.Write(buffer, index + 1, surLength);
}
}
else
{
this.PreviewHandle(this.httpBase);
}
}
else if (length > this.MaxSize)
{
if (this.tempByteBlock != null)
{
this.tempByteBlock.Dispose();
this.tempByteBlock = null;
}
Logger.Debug(LogType.Error, this, "在已接收数据大于设定值的情况下未找到终止符号,已放弃接收");
return;
}
else if (this.tempByteBlock == null)
{
this.tempByteBlock = this.BytePool.GetByteBlock(length * 2);
this.tempByteBlock.Write(buffer,offset, length-offset);
}
}
private void PreviewHandle(HttpBase httpBase)
{
this.httpBase = null;
try
{
if (this.bodyByteBlock != null)
{
httpBase.SetContent(this.bodyByteBlock.ToArray());
this.bodyByteBlock.Dispose();
this.bodyByteBlock = null;
}
httpBase.ReadFromBase();
this.GoReceived(null, httpBase);
}
catch (Exception ex)
{
this.Logger.Debug(LogType.Error, this, "处理数据错误", ex);
}
}
/// <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)
{
this.GoSend(buffer, offset, length, isAsync);
}
}
}

View File

@@ -1,327 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.ComponentModel;
namespace RRQMSocket.Http
{
/// <summary>
/// 请求头枚举
/// </summary>
public enum HttpHeaders : byte
{
/// <summary>
/// Cache-Control 标头,指定请求/响应链上所有缓存控制机制必须服从的指令。
/// </summary>
[Description("Cache-Control")]
CacheControl = 0,
/// <summary>
/// Connection 标头,指定特定连接需要的选项。
/// </summary>
[Description("Connection")]
Connection = 1,
/// <summary>
/// Date 标头,指定开始创建请求的日期和时间。
/// </summary>
[Description("Date")]
Date = 2,
/// <summary>
/// Keep-Alive 标头,指定用以维护持久性连接的参数。
/// </summary>
[Description("Keep-Alive")]
KeepAlive = 3,
/// <summary>
/// Pragma 标头,指定可应用于请求/响应链上的任何代理的特定于实现的指令。
/// </summary>
[Description("Pragma")]
Pragma = 4,
/// <summary>
/// Trailer 标头,指定标头字段显示在以 chunked 传输编码方式编码的消息的尾部。
/// </summary>
[Description("Trailer")]
Trailer = 5,
/// <summary>
/// Transfer-Encoding 标头,指定对消息正文应用的转换的类型(如果有)。
/// </summary>
[Description("Transfer-Encoding")]
TransferEncoding = 6,
/// <summary>
/// Upgrade 标头,指定客户端支持的附加通信协议。
/// </summary>
[Description("Upgrade")]
Upgrade = 7,
/// <summary>
/// Via 标头,指定网关和代理程序要使用的中间协议。
/// </summary>
[Description("Via")]
Via = 8,
/// <summary>
/// Warning 标头,指定关于可能未在消息中反映的消息的状态或转换的附加信息。
/// </summary>
[Description("Warning")]
Warning = 9,
/// <summary>
/// Allow 标头,指定支持的 HTTP 方法集。
/// </summary>
[Description("Allow")]
Allow = 10,
/// <summary>
/// Content-Length 标头,指定伴随正文数据的长度(以字节为单位)。
/// </summary>
[Description("Content-Length")]
ContentLength = 11,
/// <summary>
/// Content-Type 标头,指定伴随正文数据的 MIME 类型。
/// </summary>
[Description("Content-Type")]
ContentType = 12,
/// <summary>
/// Content-Encoding 标头,指定已应用于伴随正文数据的编码。
/// </summary>
[Description("Content-Encoding")]
ContentEncoding = 13,
/// <summary>
/// Content-Langauge 标头,指定伴随正文数据的自然语言。
/// </summary>
[Description("Content-Langauge")]
ContentLanguage = 14,
/// <summary>
/// Content-Location 标头,指定可从其中获得伴随正文的 URI。
/// </summary>
[Description("Content-Location")]
ContentLocation = 15,
/// <summary>
/// Content-MD5 标头,指定伴随正文数据的 MD5 摘要,用于提供端到端消息完整性检查。
/// </summary>
[Description("Content-MD5")]
ContentMd5 = 16,
/// <summary>
/// Content-Range 标头,指定在完整正文中应用伴随部分正文数据的位置。
/// </summary>
[Description("Content-Range")]
ContentRange = 17,
/// <summary>
/// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。
/// </summary>
[Description("Expires")]
Expires = 18,
/// <summary>
/// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。
/// </summary>
[Description("Last-Modified")]
LastModified = 19,
/// <summary>
/// Accept 标头,指定响应可接受的 MIME 类型。
/// </summary>
[Description("Accept")]
Accept = 20,
/// <summary>
/// Accept-Charset 标头,指定响应可接受的字符集。
/// </summary>
[Description("Accept-Charset")]
AcceptCharset = 21,
/// <summary>
/// Accept-Encoding 标头,指定响应可接受的内容编码。
/// </summary>
[Description("Accept-Encoding")]
AcceptEncoding = 22,
/// <summary>
/// Accept-Langauge 标头,指定响应首选的自然语言。
/// </summary>
[Description("Accept-Langauge")]
AcceptLanguage = 23,
/// <summary>
/// Authorization 标头,指定客户端为向服务器验证自身身份而出示的凭据。
/// </summary>
[Description("Authorization")]
Authorization = 24,
/// <summary>
/// Cookie 标头,指定向服务器提供的 Cookie 数据。
/// </summary>
[Description("Cookie")]
Cookie = 25,
/// <summary>
/// Expect 标头,指定客户端要求的特定服务器行为。
/// </summary>
[Description("Expect")]
Expect = 26,
/// <summary>
/// From 标头,指定控制请求用户代理的用户的 Internet 电子邮件地址。
/// </summary>
[Description("From")]
From = 27,
/// <summary>
/// Host 标头,指定所请求资源的主机名和端口号。
/// </summary>
[Description("Host")]
Host = 28,
/// <summary>
/// If-Match 标头,指定仅当客户端的指示资源的缓存副本是最新的时,才执行请求的操作。
/// </summary>
[Description("If-Match")]
IfMatch = 29,
/// <summary>
/// If-Modified-Since 标头,指定仅当自指示的数据和时间之后修改了请求的资源时,才执行请求的操作。
/// </summary>
[Description("If-Modified-Since")]
IfModifiedSince = 30,
/// <summary>
/// If-None-Match 标头,指定仅当客户端的指示资源的缓存副本都不是最新的时,才执行请求的操作。
/// </summary>
[Description("If-None-Match")]
IfNoneMatch = 31,
/// <summary>
/// If-Range 标头,指定如果客户端的缓存副本是最新的,仅发送指定范围的请求资源。
/// </summary>
[Description("If-Range")]
IfRange = 32,
/// <summary>
/// If-Unmodified-Since 标头,指定仅当自指示的日期和时间之后修改了请求的资源时,才执行请求的操作。
/// </summary>
[Description("If-Unmodified-Since")]
IfUnmodifiedSince = 33,
/// <summary>
/// Max-Forwards 标头,指定一个整数,表示此请求还可转发的次数。
/// </summary>
[Description("Max-Forwards")]
MaxForwards = 34,
/// <summary>
/// Proxy-Authorization 标头,指定客户端为向代理验证自身身份而出示的凭据。
/// </summary>
[Description("Proxy-Authorization")]
ProxyAuthorization = 35,
/// <summary>
/// Referer 标头,指定从中获得请求 URI 的资源的 URI。
/// </summary>
[Description("Referer")]
Referer = 36,
/// <summary>
/// Range 标头,指定代替整个响应返回的客户端请求的响应的子范围。
/// </summary>
[Description("Range")]
Range = 37,
/// <summary>
/// TE 标头,指定响应可接受的传输编码方式。
/// </summary>
[Description("TE")]
Te = 38,
/// <summary>
/// Translate 标头,与 WebDAV 功能一起使用的 HTTP 规范的 Microsoft 扩展。
/// </summary>
[Description("Translate")]
Translate = 39,
/// <summary>
/// User-Agent 标头,指定有关客户端代理的信息。
/// </summary>
[Description("User-Agent")]
UserAgent = 40,
/// <summary>
/// Accept-Ranges 标头,指定服务器接受的范围。
/// </summary>
[Description("Accept-Ranges")]
AcceptRanges = 41,
/// <summary>
/// Age 标头,指定自起始服务器生成响应以来的时间长度(以秒为单位)。
/// </summary>
[Description("Age")]
Age = 42,
/// <summary>
/// Etag 标头,指定请求的变量的当前值。
/// </summary>
[Description("Etag")]
ETag = 43,
/// <summary>
/// Location 标头,指定为获取请求的资源而将客户端重定向到的 URI。
/// </summary>
[Description("Location")]
Location = 44,
/// <summary>
/// Proxy-Authenticate 标头,指定客户端必须对代理验证其自身。
/// </summary>
[Description("Proxy-Authenticate")]
ProxyAuthenticate = 45,
/// <summary>
/// Retry-After 标头,指定某个时间(以秒为单位)或日期和时间,在此时间之后客户端可以重试其请求。
/// </summary>
[Description("Retry-After")]
RetryAfter = 46,
/// <summary>
/// Server 标头,指定关于起始服务器代理的信息。
/// </summary>
[Description("Server")]
Server = 47,
/// <summary>
/// Set-Cookie 标头,指定提供给客户端的 Cookie 数据。
/// </summary>
[Description("Set-Cookie")]
SetCookie = 48,
/// <summary>
/// Vary 标头,指定用于确定缓存的响应是否为新响应的请求标头。
/// </summary>
[Description("Vary")]
Vary = 49,
/// <summary>
/// WWW-Authenticate 标头,指定客户端必须对服务器验证其自身。
/// </summary>
[Description("WWW-Authenticate")]
WwwAuthenticate = 50,
}
}

View File

@@ -1,30 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.Http
{
/// <summary>
/// 解析类型
/// </summary>
public enum HttpType : byte
{
/// <summary>
/// 服务器
/// </summary>
Server,
/// <summary>
/// 客户端
/// </summary>
Client
}
}

View File

@@ -1,72 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace RRQMSocket.Http
{
/// <summary>
/// 枚举扩展类
/// </summary>
public static class EnumHelper
{
private static ConcurrentDictionary<Enum, string> _cache = new ConcurrentDictionary<Enum, string>();
/// <summary>
/// 获取DescriptionAttribute
/// </summary>
/// <param name="enum"></param>
/// <returns></returns>
public static string GetDescription(this Enum @enum)
{
var result = string.Empty;
if (@enum == null) return result;
if (!_cache.TryGetValue(@enum, out result))
{
var typeInfo = @enum.GetType();
var enumValues = typeInfo.GetEnumValues();
foreach (var value in enumValues)
{
if (@enum.Equals(value))
{
MemberInfo memberInfo = typeInfo.GetMember(value.ToString()).First();
result = memberInfo.GetCustomAttribute<DescriptionAttribute>().Description;
}
}
_cache.TryAdd(@enum, result);
}
return result;
}
/// <summary>
/// 根据字符串获取枚举
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="str"></param>
/// <param name="result"></param>
/// <returns></returns>
public static bool GetEnum<T>(string str, out T result) where T : struct
{
return Enum.TryParse<T>(str, out result);
}
}
}

View File

@@ -1,58 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.Http
{
/// <summary>
/// 请求辅助类
/// </summary>
public static class RequestHelper
{
/// <summary>
/// 从Xml格式
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="xmlText"></param>
/// <returns></returns>
public static HttpRequest FromXML(this HttpRequest httpRequest, string xmlText)
{
httpRequest.SetContent(xmlText);
httpRequest.Content_Type = "text/xml";
return httpRequest;
}
/// <summary>
/// 从Json
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="jsonText"></param>
/// <returns></returns>
public static HttpRequest FromJson(this HttpRequest httpRequest, string jsonText)
{
httpRequest.SetContent(jsonText);
httpRequest.Content_Type = "text/json";
return httpRequest;
}
/// <summary>
/// 从文本
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="text"></param>
/// <returns></returns>
public static HttpRequest FromText(this HttpRequest httpRequest, string text)
{
httpRequest.SetContent(text);
httpRequest.Content_Type = "text/plain";
return httpRequest;
}
}
}

View File

@@ -1,100 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Helper;
using System;
namespace RRQMSocket.Http
{
/// <summary>
/// 响应扩展
/// </summary>
public static class ResponseHelper
{
///// <summary>
///// 从文件
///// </summary>
///// <param name="response"></param>
///// <param name="fileName"></param>
///// <returns></returns>
//public static HttpResponse FromFile(this HttpResponse response, string fileName)
//{
// if (!File.Exists(fileName))
// {
// response.SetContent("<html><body><h1>404 -RRQM Not Found</h1></body></html>");
// response.StatusCode = "404";
// response.Content_Type = "text/html";
// return response;
// }
// var content = File.ReadAllBytes(fileName);
// response.SetContent(content);
// return response.FromSuccess();
//}
/// <summary>
/// 从Xml格式
/// </summary>
/// <param name="response"></param>
/// <param name="xmlText"></param>
/// <param name="statusCode"></param>
/// <returns></returns>
public static HttpResponse FromXML(this HttpResponse response, string xmlText, string statusCode = "200")
{
response.SetContent(xmlText);
response.Content_Type = "text/xml";
return response.FromSuccess(statusCode);
}
/// <summary>
/// 从Json
/// </summary>
/// <param name="response"></param>
/// <param name="jsonText"></param>
/// <param name="statusCode"></param>
/// <returns></returns>
public static HttpResponse FromJson(this HttpResponse response, string jsonText, string statusCode = "200")
{
response.SetContent(jsonText);
response.Content_Type = "text/json";
return response.FromSuccess(statusCode);
}
/// <summary>
/// 从文本
/// </summary>
/// <param name="response"></param>
/// <param name="statusCode"></param>
/// <param name="text"></param>
/// <returns></returns>
public static HttpResponse FromText(this HttpResponse response, string text, string statusCode = "200")
{
response.SetContent(text);
response.Content_Type = "text/plain";
return response.FromSuccess(statusCode);
}
/// <summary>
/// 返回成功
/// </summary>
/// <param name="response"></param>
/// <param name="statusCode"></param>
/// <returns></returns>
public static HttpResponse FromSuccess(this HttpResponse response, string statusCode = "200")
{
response.StatusCode = statusCode;
response.SetHeader(HttpHeaders.Server, $"RRQMSocket.Http {HttpResponse.ServerVersion}");
response.SetHeader(HttpHeaders.Date, DateTime.Now.ToGMTString("r"));
return response;
}
}
}

View File

@@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license procotol 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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,70 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<ApplicationIcon>RRQM.ico</ApplicationIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
<Version>5.6.0</Version>
<Company>若汝棋茗</Company>
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
<Description>介绍这是一个能够简单解析HTTP的扩展库能够为RRQMSocket扩展解析HTTP的能力。
RRQMSocket is an extension library that can easily parse HTTP. The RRQMSocket extension has the ability to parse HTTP.
更新说明:
无更新内容。
APIhttps://gitee.com/RRQM_OS/RRQM/wikis/pages</Description>
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
<PackageIconUrl></PackageIconUrl>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PackageIcon>RRQM.png</PackageIcon>
<Authors>若汝棋茗</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageTags>HTTP;IOCP</PackageTags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.Http.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.Http.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
<DocumentationFile>bin\Debug\net45\RRQMSocket.Http.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
<DocumentationFile>bin\Release\net45\RRQMSocket.Http.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.Http.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.Http.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="RRQM.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="RRQMSocket" Version="5.6.0" />
</ItemGroup>
</Project>

View File

@@ -1,61 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// 适用于XmlRpc的标记
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class JsonRpcAttribute : RPCAttribute
{
/// <summary>
/// 构造函数
/// </summary>
public JsonRpcAttribute()
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="memberKey">指定键</param>
public JsonRpcAttribute(string memberKey) : this(memberKey, MethodFlags.None)
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="methodFlags"></param>
public JsonRpcAttribute(MethodFlags methodFlags) : this(null, methodFlags)
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="memberKey"></param>
/// <param name="methodFlags"></param>
public JsonRpcAttribute(string memberKey, MethodFlags methodFlags) : base(methodFlags)
{
this.MemberKey = memberKey;
}
/// <summary>
/// 注册键
/// </summary>
public string MemberKey { get; private set; }
}
}

View File

@@ -1,70 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// 服务映射图
/// </summary>
public class ActionMap : IEnumerable<KeyValuePair<string, MethodInstance>>
{
internal ActionMap()
{
this.actionMap = new Dictionary<string, MethodInstance>();
}
private Dictionary<string, MethodInstance> actionMap;
internal void Add(string actionKey, MethodInstance methodInstance)
{
this.actionMap.Add(actionKey, methodInstance);
}
/// <summary>
/// 服务键集合
/// </summary>
public IEnumerable<string> ActionKeys { get { return this.actionMap.Keys; } }
/// <summary>
/// 通过routeUrl获取函数实例
/// </summary>
/// <param name="actionKey"></param>
/// <param name="methodInstance"></param>
/// <returns></returns>
public bool TryGet(string actionKey, out MethodInstance methodInstance)
{
if (this.actionMap.ContainsKey(actionKey))
{
methodInstance = this.actionMap[actionKey];
return true;
}
methodInstance = null;
return false;
}
/// <summary>
/// 返回迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<KeyValuePair<string, MethodInstance>> GetEnumerator()
{
return this.actionMap.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.actionMap.GetEnumerator();
}
}
}

View File

@@ -1,40 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.RPC.JsonRpc
{
#pragma warning disable CS1591
/// <summary>
/// JsonRpc响应器
/// </summary>
public class JsonResponseContext
{
public string jsonrpc;
public object result;
public error error;
public string id;
}
/// <summary>
/// 错误
/// </summary>
public class error
{
public int code;
public string message;
}
}

View File

@@ -1,31 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.XREF.Newtonsoft.Json.Linq;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpc调用器
/// </summary>
public class JsonRpcContext:IRpcContext
{
#pragma warning disable
public string jsonrpc;
public string method;
public object[] parameters;
public JToken @params;
public string id;
public bool needResponse;
#pragma warning restore
}
}

View File

@@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpc调用上下文
/// </summary>
public class JsonRpcServerCallContext : IServerCallContext
{
internal ICaller caller;
internal JsonRpcContext context;
internal MethodInstance methodInstance;
internal string jsonString;
internal JsonRpcProtocolType protocolType;
internal MethodInvoker methodInvoker;
/// <summary>
/// Json字符串
/// </summary>
public string JsonString
{
get { return jsonString; }
}
/// <summary>
/// 协议类型
/// </summary>
public JsonRpcProtocolType ProtocolType
{
get { return protocolType; }
set { protocolType = value; }
}
#pragma warning disable CS1591
public ICaller Caller => this.caller;
public IRpcContext Context => this.context;
public MethodInstance MethodInstance => this.methodInstance;
public MethodInvoker MethodInvoker => this.methodInvoker;
}
}

View File

@@ -1,22 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Run;
namespace RRQMSocket.RPC.JsonRpc
{
internal class JsonRpcWaitContext : WaitResult
{
internal object Return;
internal error error;
}
}

View File

@@ -1,54 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Dependency;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpcClient配置
/// </summary>
public class JsonRpcClientConfig : TcpClientConfig
{
/// <summary>
/// 协议类型
/// </summary>
public JsonRpcProtocolType ProtocolType
{
get { return (JsonRpcProtocolType)GetValue(ProtocolTypeProperty); }
set { SetValue(ProtocolTypeProperty, value); }
}
/// <summary>
/// 协议类型,
/// 所需类型<see cref="JsonRpcProtocolType"/>
/// </summary>
public static readonly DependencyProperty ProtocolTypeProperty =
DependencyProperty.Register("ProtocolType", typeof(JsonRpcProtocolType), typeof(JsonRpcClientConfig), JsonRpcProtocolType.Tcp);
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return (int)GetValue(MaxPackageSizeProperty); }
set { SetValue(MaxPackageSizeProperty, value); }
}
/// <summary>
/// 最大数据包长度,所需类型<see cref="int"/>
/// </summary>
public static readonly DependencyProperty MaxPackageSizeProperty =
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(JsonRpcClientConfig), 1024);
}
}

View File

@@ -1,72 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Dependency;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpcParser配置
/// </summary>
public class JsonRpcParserConfig : TcpServiceConfig
{
/// <summary>
/// 协议类型
/// </summary>
public JsonRpcProtocolType ProtocolType
{
get { return (JsonRpcProtocolType)GetValue(ProtocolTypeProperty); }
set { SetValue(ProtocolTypeProperty, value); }
}
/// <summary>
/// 协议类型,
/// 所需类型<see cref="JsonRpcProtocolType"/>
/// </summary>
public static readonly DependencyProperty ProtocolTypeProperty =
DependencyProperty.Register("ProtocolType", typeof(JsonRpcProtocolType), typeof(JsonRpcParserConfig), JsonRpcProtocolType.Tcp);
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return (int)GetValue(MaxPackageSizeProperty); }
set { SetValue(MaxPackageSizeProperty, value); }
}
/// <summary>
/// 最大数据包长度,所需类型<see cref="int"/>
/// </summary>
public static readonly DependencyProperty MaxPackageSizeProperty =
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(JsonRpcParserConfig), 1024);
/// <summary>
/// 调用类型
/// </summary>
public InvokeType InvokeType
{
get { return (InvokeType)GetValue(InvokeTypeProperty); }
set { SetValue(InvokeTypeProperty, value); }
}
/// <summary>
/// 调用类型,所需类型<see cref="RRQMSocket.RPC.InvokeType"/>
/// </summary>
public static readonly DependencyProperty InvokeTypeProperty =
DependencyProperty.Register("InvokeType", typeof(InvokeType), typeof(JsonRpcParserConfig), InvokeType.GlobalInstance);
}
}

View File

@@ -1,29 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpc协议类型
/// </summary>
public enum JsonRpcProtocolType : byte
{
/// <summary>
/// 普通TCP协议
/// </summary>
Tcp,
/// <summary>
/// Http协议
/// </summary>
Http
}
}

View File

@@ -1,22 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMSocket.RPC.RRQMRPC;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// Json客户端RPC接口
/// </summary>
public interface IJsonRpcClient : IRpcClient
{
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,70 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<ApplicationIcon>RRQM.ico</ApplicationIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
<Version>5.6.0</Version>
<Company>若汝棋茗</Company>
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
<Description>介绍这是一个扩展于RRQMSocket.RPC的JsonRpc组件可以通过该组件直接创建JsonRpc服务解析器让Web端、移动端可以跨语言调用RPC函数。功能支持JsonRpc全功能。
更新说明:
增加:上下文调用。
Demohttps://gitee.com/RRQM_OS/RRQMBox
APIhttps://gitee.com/RRQM_OS/RRQM/wikis/pages</Description>
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
<PackageIconUrl></PackageIconUrl>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PackageIcon>RRQM.png</PackageIcon>
<Authors>若汝棋茗</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageTags>JsonRpc;Socket;IOCP</PackageTags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.JsonRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.JsonRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
<DocumentationFile>bin\Debug\net45\RRQMSocket.JsonRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
<DocumentationFile>bin\Release\net45\RRQMSocket.JsonRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.JsonRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.JsonRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="RRQM.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="RRQMSocket.Http" Version="5.6.0" />
<PackageReference Include="RRQMSocket.RPC" Version="5.6.0" />
</ItemGroup>
</Project>

View File

@@ -1,386 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Exceptions;
using RRQMCore.Helper;
using RRQMCore.Run;
using RRQMCore.XREF.Newtonsoft.Json;
using RRQMCore.XREF.Newtonsoft.Json.Linq;
using RRQMSocket.Http;
using RRQMSocket.RPC.RRQMRPC;
using System;
using System.Text;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpc客户端
/// </summary>
public class JsonRpcClient : TcpClient, IJsonRpcClient
{
private int maxPackageSize;
private JsonRpcProtocolType protocolType;
private RRQMWaitHandle<WaitResult> waitHandle;
/// <summary>
/// 构造函数
/// </summary>
public JsonRpcClient()
{
waitHandle = new RRQMWaitHandle<WaitResult>();
}
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return maxPackageSize; }
}
/// <summary>
/// 协议类型
/// </summary>
public JsonRpcProtocolType ProtocolType
{
get { return protocolType; }
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <param name="types"></param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
/// <returns></returns>
public T Invoke<T>(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
{
JsonRpcWaitContext context = new JsonRpcWaitContext();
WaitData<WaitResult> waitData = this.waitHandle.GetWaitData(context);
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
if (invokeOption == null)
{
invokeOption = InvokeOption.WaitInvoke;
}
try
{
JObject jobject = new JObject();
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
jobject.Add("method", JToken.FromObject(method));
jobject.Add("params", JToken.FromObject(parameters));
if (invokeOption.FeedbackType == FeedbackType.WaitInvoke)
{
jobject.Add("id", JToken.FromObject(context.Sign.ToString()));
}
else
{
jobject.Add("id", null);
}
switch (this.protocolType)
{
case JsonRpcProtocolType.Tcp:
{
byteBlock.Write(Encoding.UTF8.GetBytes(jobject.ToString(Formatting.None)));
break;
}
case JsonRpcProtocolType.Http:
{
HttpRequest httpRequest = new HttpRequest();
httpRequest.Method = "POST";
httpRequest.FromJson(jobject.ToString(Formatting.None));
httpRequest.Build(byteBlock);
}
break;
}
switch (invokeOption.FeedbackType)
{
case FeedbackType.OnlySend:
{
this.SendAsync(byteBlock);
}
break;
case FeedbackType.WaitSend:
case FeedbackType.WaitInvoke:
{
this.Send(byteBlock);
}
break;
default:
break;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
byteBlock.Dispose();
}
switch (invokeOption.FeedbackType)
{
case FeedbackType.OnlySend:
case FeedbackType.WaitSend:
{
this.waitHandle.Destroy(waitData);
return default;
}
case FeedbackType.WaitInvoke:
{
waitData.Wait(invokeOption.Timeout);
JsonRpcWaitContext resultContext = (JsonRpcWaitContext)waitData.WaitResult;
this.waitHandle.Destroy(waitData);
if (resultContext.Status == 0)
{
throw new RRQMTimeoutException("等待结果超时");
}
if (resultContext.error != null)
{
throw new RRQMRPCException(resultContext.error.message);
}
try
{
if (resultContext.Return==null)
{
return default;
}
if (typeof(T).IsPrimitive || typeof(T) == typeof(string))
{
return (T)resultContext.Return.ToString().ParseToType(typeof(T));
}
return JsonConvert.DeserializeObject<T>(resultContext.Return.ToString());
}
catch (Exception ex)
{
throw ex;
}
}
default:
return default;
}
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <param name="types"></param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
public void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
{
JsonRpcWaitContext context = new JsonRpcWaitContext();
WaitData<WaitResult> waitData = this.waitHandle.GetWaitData(context);
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
if (invokeOption == null)
{
invokeOption = InvokeOption.WaitInvoke;
}
try
{
JObject jobject = new JObject();
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
jobject.Add("method", JToken.FromObject(method));
jobject.Add("params", JToken.FromObject(parameters));
if (invokeOption.FeedbackType == FeedbackType.WaitInvoke)
{
jobject.Add("id", JToken.FromObject(context.Sign.ToString()));
}
else
{
jobject.Add("id", null);
}
switch (this.protocolType)
{
case JsonRpcProtocolType.Tcp:
{
byteBlock.Write(Encoding.UTF8.GetBytes(jobject.ToString(Formatting.None)));
break;
}
case JsonRpcProtocolType.Http:
{
HttpRequest httpRequest = new HttpRequest();
httpRequest.Method = "POST";
httpRequest.FromJson(jobject.ToString(Formatting.None));
httpRequest.Build(byteBlock);
}
break;
}
switch (invokeOption.FeedbackType)
{
case FeedbackType.OnlySend:
{
this.SendAsync(byteBlock);
}
break;
case FeedbackType.WaitSend:
case FeedbackType.WaitInvoke:
{
this.Send(byteBlock);
}
break;
default:
break;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
byteBlock.Dispose();
}
switch (invokeOption.FeedbackType)
{
case FeedbackType.OnlySend:
case FeedbackType.WaitSend:
{
this.waitHandle.Destroy(waitData);
return;
}
case FeedbackType.WaitInvoke:
{
waitData.Wait(invokeOption.Timeout);
JsonRpcWaitContext resultContext = (JsonRpcWaitContext)waitData.WaitResult;
this.waitHandle.Destroy(waitData);
if (resultContext.Status == 0)
{
throw new RRQMTimeoutException("等待结果超时");
}
if (resultContext.error != null)
{
throw new RRQMRPCException(resultContext.error.message);
}
return;
}
default:
return;
}
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
public void Invoke(string method, InvokeOption invokeOption, params object[] parameters)
{
this.Invoke(method, invokeOption, ref parameters, null);
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
/// <returns></returns>
public T Invoke<T>(string method, InvokeOption invokeOption, params object[] parameters)
{
return this.Invoke<T>(method, invokeOption, ref parameters, null);
}
/// <summary>
/// 处理数据
/// </summary>
/// <param name="byteBlock"></param>
/// <param name="obj"></param>
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
{
switch (this.protocolType)
{
case JsonRpcProtocolType.Tcp:
{
string jsonString = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
JsonResponseContext responseContext = (JsonResponseContext)JsonConvert.DeserializeObject(jsonString, typeof(JsonResponseContext));
if (responseContext != null)
{
JsonRpcWaitContext waitContext = new JsonRpcWaitContext();
waitContext.Status = 1;
waitContext.Sign = int.Parse(responseContext.id);
waitContext.error = responseContext.error;
waitContext.Return = responseContext.result;
this.waitHandle.SetRun(waitContext);
}
break;
}
case JsonRpcProtocolType.Http:
{
HttpResponse httpResponse = (HttpResponse)obj;
JsonResponseContext responseContext = (JsonResponseContext)JsonConvert.DeserializeObject(httpResponse.Body, typeof(JsonResponseContext));
if (responseContext != null)
{
JsonRpcWaitContext waitContext = new JsonRpcWaitContext();
waitContext.Status = 1;
waitContext.Sign = int.Parse(responseContext.id);
waitContext.error = responseContext.error;
waitContext.Return = responseContext.result;
this.waitHandle.SetRun(waitContext);
}
break;
}
}
}
/// <summary>
/// 载入配置
/// </summary>
/// <param name="clientConfig"></param>
protected override void LoadConfig(TcpClientConfig clientConfig)
{
base.LoadConfig(clientConfig);
this.maxPackageSize = (int)clientConfig.GetValue(JsonRpcClientConfig.MaxPackageSizeProperty);
this.protocolType = (JsonRpcProtocolType)clientConfig.GetValue(JsonRpcClientConfig.ProtocolTypeProperty);
switch (this.protocolType)
{
case JsonRpcProtocolType.Tcp:
base.SetDataHandlingAdapter(new TerminatorDataHandlingAdapter(this.maxPackageSize, "\r\n"));
break;
case JsonRpcProtocolType.Http:
base.SetDataHandlingAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Client));
break;
}
}
}
}

View File

@@ -1,531 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Log;
using RRQMCore.XREF.Newtonsoft.Json;
using RRQMCore.XREF.Newtonsoft.Json.Linq;
using RRQMSocket.Http;
using System;
using System.Collections.Concurrent;
using System.Text;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpcParser解析器
/// </summary>
public class JsonRpcParser : TcpService<JsonRpcSocketClient>, IRPCParser
{
private ActionMap actionMap;
private MethodMap methodMap;
private JsonRpcProtocolType protocolType;
/// <summary>
/// 构造函数
/// </summary>
public JsonRpcParser()
{
this.idTypeInstance = new ConcurrentDictionary<string, ConcurrentDictionary<Type, IServerProvider>>();
this.actionMap = new ActionMap();
}
/// <summary>
/// 函数键映射图
/// </summary>
public ActionMap ActionMap { get { return this.actionMap; } }
private int maxPackageSize;
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return maxPackageSize; }
}
/// <summary>
/// 函数映射
/// </summary>
public MethodMap MethodMap
{
get { return methodMap; }
}
/// <summary>
/// 协议类型
/// </summary>
public JsonRpcProtocolType ProtocolType
{
get { return protocolType; }
}
/// <summary>
/// 所属服务器
/// </summary>
public RPCService RPCService { get; private set; }
private InvokeType invokeType;
/// <summary>
/// 调用类型
/// </summary>
public InvokeType InvokeType
{
get { return invokeType; }
}
/// <summary>
/// 执行函数
/// </summary>
public Action<IRPCParser, MethodInvoker, MethodInstance> RRQMExecuteMethod { get; private set; }
/// <summary>
/// 结束调用
/// </summary>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance)
{
ISocketClient socketClient = (ISocketClient)methodInvoker.Caller;
error error = new error();
switch (methodInvoker.Status)
{
case InvokeStatus.Success:
{
error = null;
break;
}
case InvokeStatus.UnFound:
{
error.code = -32601;
error.message = "函数未找到";
break;
}
case InvokeStatus.UnEnable:
{
error.code = -32601;
error.message = "函数已被禁用";
break;
}
case InvokeStatus.Abort:
{
error.code = -32601;
error.message = "函数已被中断执行";
break;
}
case InvokeStatus.InvocationException:
{
error.code = -32603;
error.message = "函数内部异常";
break;
}
case InvokeStatus.Exception:
{
error.code = -32602;
error.message = methodInvoker.StatusMessage;
break;
}
}
JsonRpcContext jsonRpcContext = (JsonRpcContext)methodInvoker.Flag;
if (jsonRpcContext.needResponse)
{
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
this.BuildResponseByteBlock(byteBlock, methodInvoker, jsonRpcContext.id, methodInvoker.ReturnParameter, error);
if (socketClient.Online)
{
try
{
string s = Encoding.UTF8.GetString(byteBlock.ToArray());
socketClient.Send(byteBlock);
}
catch (Exception ex)
{
this.Logger.Debug(LogType.Error, this, ex.Message);
}
finally
{
byteBlock.Dispose();
}
}
}
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
/// <param name="methodInstances"></param>
public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances)
{
foreach (var methodInstance in methodInstances)
{
foreach (var att in methodInstance.RPCAttributes)
{
if (att is JsonRpcAttribute attribute)
{
if (methodInstance.IsByRef)
{
throw new RRQMRPCException($"JsonRpc服务中不允许有out及ref关键字服务{methodInstance.Method.Name}");
}
string actionKey = string.IsNullOrEmpty(attribute.MemberKey) ? methodInstance.Method.Name : attribute.MemberKey;
try
{
this.actionMap.Add(actionKey, methodInstance);
}
catch
{
throw new RRQMRPCException($"函数键为{actionKey}的方法已注册。");
}
}
}
}
}
/// <summary>
/// 取消注册服务
/// </summary>
/// <param name="provider"></param>
/// <param name="methodInstances"></param>
public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances)
{
}
/// <summary>
/// 设置执行委托
/// </summary>
/// <param name="executeMethod"></param>
public void SetExecuteMethod(Action<IRPCParser, MethodInvoker, MethodInstance> executeMethod)
{
this.RRQMExecuteMethod = executeMethod;
}
/// <summary>
/// 设置地图映射
/// </summary>
/// <param name="methodMap"></param>
public void SetMethodMap(MethodMap methodMap)
{
this.methodMap = methodMap;
}
/// <summary>
/// 设置服务
/// </summary>
/// <param name="service"></param>
public void SetRPCService(RPCService service)
{
this.RPCService = service;
}
/// <summary>
/// 构建请求内容
/// </summary>
/// <param name="methodInvoker"></param>
/// <param name="jsonString">数据</param>
/// <param name="methodInstance">调用服务实例</param>
/// <param name="jsonRpcContext"></param>
/// <returns></returns>
protected virtual void BuildRequestContext(MethodInvoker methodInvoker, string jsonString, out MethodInstance methodInstance, out JsonRpcContext jsonRpcContext)
{
try
{
jsonRpcContext = JsonConvert.DeserializeObject<JsonRpcContext>(jsonString);
if (jsonRpcContext.id != null)
{
jsonRpcContext.needResponse = true;
}
}
catch (Exception ex)
{
jsonRpcContext = new JsonRpcContext();
jsonRpcContext.needResponse = true;
throw ex;
}
if (this.actionMap.TryGet(jsonRpcContext.method, out methodInstance))
{
if (jsonRpcContext.@params == null)
{
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
if (methodInstance.ParameterNames.Length > 1)
{
throw new RRQMRPCException("调用参数计数不匹配");
}
else
{
JsonRpcServerCallContext jsonRpcServerCallContext = new JsonRpcServerCallContext();
jsonRpcServerCallContext.caller = methodInvoker.Caller;
jsonRpcServerCallContext.methodInvoker = methodInvoker;
jsonRpcServerCallContext.context = jsonRpcContext;
jsonRpcServerCallContext.jsonString = jsonString;
jsonRpcServerCallContext.methodInstance = methodInstance;
jsonRpcServerCallContext.protocolType = this.protocolType;
jsonRpcContext.parameters = new object[] { jsonRpcServerCallContext };
}
}
else
{
if (methodInstance.ParameterNames.Length != 0)
{
throw new RRQMRPCException("调用参数计数不匹配");
}
}
return;
}
if (jsonRpcContext.@params.GetType() != typeof(JArray))
{
JObject obj = (JObject)jsonRpcContext.@params;
jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length];
//内联
int i = 0;
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
JsonRpcServerCallContext jsonRpcServerCallContext = new JsonRpcServerCallContext();
jsonRpcServerCallContext.caller = methodInvoker.Caller;
jsonRpcServerCallContext.methodInvoker = methodInvoker;
jsonRpcServerCallContext.context = jsonRpcContext;
jsonRpcServerCallContext.jsonString = jsonString;
jsonRpcServerCallContext.methodInstance = methodInstance;
jsonRpcServerCallContext.protocolType = this.protocolType;
jsonRpcContext.parameters[0] = jsonRpcServerCallContext;
i = 1;
}
for (; i < methodInstance.ParameterNames.Length; i++)
{
if (obj.TryGetValue(methodInstance.ParameterNames[i], out JToken jToken))
{
Type type = methodInstance.ParameterTypes[i];
jsonRpcContext.parameters[i] = jToken.ToObject(type);
}
else if (methodInstance.Parameters[i].HasDefaultValue)
{
jsonRpcContext.parameters[i] = methodInstance.Parameters[i].DefaultValue;
}
else
{
throw new RRQMRPCException("调用参数计数不匹配");
}
}
}
else
{
JArray array = (JArray)jsonRpcContext.@params;
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
if (array.Count != methodInstance.ParameterNames.Length - 1)
{
throw new RRQMRPCException("调用参数计数不匹配");
}
jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length];
JsonRpcServerCallContext jsonRpcServerCallContext = new JsonRpcServerCallContext();
jsonRpcServerCallContext.caller = methodInvoker.Caller;
jsonRpcServerCallContext.methodInvoker = methodInvoker;
jsonRpcServerCallContext.context = jsonRpcContext;
jsonRpcServerCallContext.jsonString = jsonString;
jsonRpcServerCallContext.methodInstance = methodInstance;
jsonRpcServerCallContext.protocolType = this.protocolType;
jsonRpcContext.parameters[0] = jsonRpcServerCallContext;
for (int i = 0; i < array.Count; i++)
{
jsonRpcContext.parameters[i + 1] = jsonRpcContext.@params[i].ToObject(methodInstance.ParameterTypes[i + 1]);
}
}
else
{
if (array.Count != methodInstance.ParameterNames.Length)
{
throw new RRQMRPCException("调用参数计数不匹配");
}
jsonRpcContext.parameters = new object[methodInstance.ParameterNames.Length];
for (int i = 0; i < array.Count; i++)
{
jsonRpcContext.parameters[i] = jsonRpcContext.@params[i].ToObject(methodInstance.ParameterTypes[i]);
}
}
}
}
else
{
methodInstance = null;
}
}
/// <summary>
/// 构建响应数据
/// </summary>
/// <param name="responseByteBlock"></param>
/// <param name="methodInvoker"></param>
/// <param name="id"></param>
/// <param name="result"></param>
/// <param name="error"></param>
protected virtual void BuildResponseByteBlock(ByteBlock responseByteBlock, MethodInvoker methodInvoker, string id, object result, error error)
{
JObject jobject = new JObject();
if (error == null)
{
//成功
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
if (result != null)
{
if (result.GetType().FullName == "Newtonsoft.Json.Linq.JObject")
{
jobject.Add("result", JToken.Parse(((dynamic)result).ToString(0)));
}
else
{
jobject.Add("result", JToken.FromObject(result));
}
}
else
{
jobject.Add("result", null);
}
jobject.Add("id", id == null ? null : JToken.FromObject(id));
}
else
{
jobject.Add("jsonrpc", JToken.FromObject("2.0"));
jobject.Add("error", JToken.FromObject(error));
jobject.Add("id", id == null ? null : JToken.FromObject(id));
}
switch (this.protocolType)
{
case JsonRpcProtocolType.Tcp:
{
responseByteBlock.Write(Encoding.UTF8.GetBytes(jobject.ToString(Formatting.None)));
break;
}
case JsonRpcProtocolType.Http:
{
HttpResponse httpResponse = new HttpResponse();
httpResponse.FromJson(jobject.ToString(Formatting.None));
httpResponse.Build(responseByteBlock);
break;
}
}
}
/// <summary>
/// 载入配置
/// </summary>
/// <param name="serviceConfig"></param>
protected override void LoadConfig(ServiceConfig serviceConfig)
{
base.LoadConfig(serviceConfig);
this.protocolType = (JsonRpcProtocolType)serviceConfig.GetValue(JsonRpcParserConfig.ProtocolTypeProperty);
this.maxPackageSize = (int)serviceConfig.GetValue(JsonRpcParserConfig.MaxPackageSizeProperty);
this.invokeType = (InvokeType)serviceConfig.GetValue(JsonRpcParserConfig.InvokeTypeProperty);
}
/// <summary>
/// 创建SocketCliect
/// </summary>
/// <param name="socketClient"></param>
/// <param name="createOption"></param>
protected override void OnCreateSocketCliect(JsonRpcSocketClient socketClient, CreateOption createOption)
{
socketClient.OnReceived = this.OnReceived;
switch (this.protocolType)
{
case JsonRpcProtocolType.Tcp:
socketClient.SetAdapter(new TerminatorDataHandlingAdapter(this.maxPackageSize, "\r\n"));
break;
case JsonRpcProtocolType.Http:
socketClient.SetAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Server));
break;
}
}
private readonly ConcurrentDictionary<string, ConcurrentDictionary<Type, IServerProvider>> idTypeInstance;
private void OnReceived(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj)
{
MethodInvoker methodInvoker = new MethodInvoker();
methodInvoker.Caller = (JsonRpcSocketClient)socketClient;
methodInvoker.InvokeType = this.invokeType;
MethodInstance methodInstance = null;
JsonRpcContext context = null;
try
{
string jsonString = null;
switch (this.protocolType)
{
case JsonRpcProtocolType.Tcp:
{
jsonString = Encoding.UTF8.GetString(byteBlock.Buffer, 0, byteBlock.Len);
break;
}
case JsonRpcProtocolType.Http:
{
HttpRequest httpRequest = (HttpRequest)obj;
jsonString = httpRequest.Body;
methodInvoker.Flag = httpRequest;
break;
}
}
this.BuildRequestContext(methodInvoker, jsonString, out methodInstance, out context);
if (methodInstance == null)
{
methodInvoker.Status = InvokeStatus.UnFound;
}
else if (methodInstance.IsEnable)
{
methodInvoker.Parameters = context.parameters;
if (this.invokeType == InvokeType.CustomInstance)
{
ConcurrentDictionary<Type, IServerProvider> typeInstance;
if (!this.idTypeInstance.TryGetValue(socketClient.ID, out typeInstance))
{
typeInstance = new ConcurrentDictionary<Type, IServerProvider>();
this.idTypeInstance.TryAdd(socketClient.ID, typeInstance);
}
IServerProvider instance;
if (!typeInstance.TryGetValue(methodInstance.ProviderType, out instance))
{
instance = (IServerProvider)Activator.CreateInstance(methodInstance.ProviderType);
typeInstance.TryAdd(methodInstance.ProviderType, instance);
}
methodInvoker.CustomServerProvider = instance;
}
}
else
{
methodInvoker.Status = InvokeStatus.UnEnable;
}
}
catch (Exception ex)
{
methodInvoker.Status = InvokeStatus.Exception;
methodInvoker.StatusMessage = ex.Message;
}
methodInvoker.Flag = context;
this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance);
}
}
}

View File

@@ -1,40 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RRQMSocket.RPC.JsonRpc
{
/// <summary>
/// JsonRpc辅助类
/// </summary>
public class JsonRpcSocketClient : SimpleSocketClient,ICaller
{
/// <summary>
/// 禁用适配器赋值
/// </summary>
/// <param name="adapter"></param>
public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter)
{
throw new RRQMException($"{nameof(JsonRpcSocketClient)}不允许设置适配器。");
}
internal void SetAdapter(DataHandlingAdapter adapter)
{
base.SetDataHandlingAdapter(adapter);
}
}
}

View File

@@ -1,43 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// 适用于WebApi的路由标记
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class RouteAttribute : RPCAttribute
{
/// <summary>
/// 构造函数
/// </summary>
public RouteAttribute()
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="template"></param>
public RouteAttribute(string template)
{
this.Template = template;
}
/// <summary>
/// 路由模板
/// </summary>
public string Template { get; private set; }
}
}

View File

@@ -1,30 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// 结果状态
/// </summary>
public class ActionResult
{
/// <summary>
/// 状态类型
/// </summary>
public InvokeStatus Status { get; set; }
/// <summary>
/// 消息
/// </summary>
public string Message { get; set; }
}
}

View File

@@ -1,21 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// ControllerBase
/// </summary>
public abstract class ControllerBase : ServerProvider
{
}
}

View File

@@ -1,70 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// 路由映射图
/// </summary>
public class RouteMap : IEnumerable<KeyValuePair<string, MethodInstance>>
{
internal RouteMap()
{
this.routeMap = new Dictionary<string, MethodInstance>();
}
private Dictionary<string, MethodInstance> routeMap;
internal void Add(string routeUrl, MethodInstance methodInstance)
{
this.routeMap.Add(routeUrl, methodInstance);
}
/// <summary>
/// 路由路径集合
/// </summary>
public IEnumerable<string> Urls { get { return this.routeMap.Keys; } }
/// <summary>
/// 通过routeUrl获取函数实例
/// </summary>
/// <param name="routeUrl"></param>
/// <param name="methodInstance"></param>
/// <returns></returns>
public bool TryGet(string routeUrl, out MethodInstance methodInstance)
{
if (this.routeMap.ContainsKey(routeUrl))
{
methodInstance = this.routeMap[routeUrl];
return true;
}
methodInstance = null;
return false;
}
/// <summary>
/// 返回迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<KeyValuePair<string, MethodInstance>> GetEnumerator()
{
return this.routeMap.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.routeMap.GetEnumerator();
}
}
}

View File

@@ -1,53 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Dependency;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// WebApiParser配置
/// </summary>
public class WebApiParserConfig : TcpServiceConfig
{
/// <summary>
/// 数据转化器
/// </summary>
public ApiDataConverter ApiDataConverter
{
get { return (ApiDataConverter)GetValue(ApiDataConverterProperty); }
set { SetValue(ApiDataConverterProperty, value); }
}
/// <summary>
/// 数据转化器
/// 所需类型<see cref="RRQMSocket.RPC.WebApi.ApiDataConverter"/>
/// </summary>
public static readonly DependencyProperty ApiDataConverterProperty =
DependencyProperty.Register("ApiDataConverter", typeof(ApiDataConverter), typeof(WebApiParserConfig), new JsonDataConverter());
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return (int)GetValue(MaxPackageSizeProperty); }
set { SetValue(MaxPackageSizeProperty, value); }
}
/// <summary>
/// 最大数据包长度,所需类型<see cref="int"/>
/// </summary>
public static readonly DependencyProperty MaxPackageSizeProperty =
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(WebApiParserConfig), 1024);
}
}

View File

@@ -1,37 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMSocket.Http;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// Api结果转化器
/// </summary>
public abstract class ApiDataConverter
{
/// <summary>
/// 在调用完成时转换结果
/// </summary>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
/// <returns></returns>
public abstract HttpResponse OnResult(MethodInvoker methodInvoker, MethodInstance methodInstance);
/// <summary>
/// 在调用时
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
public abstract void OnPost(HttpRequest httpRequest, ref MethodInvoker methodInvoker, MethodInstance methodInstance);
}
}

View File

@@ -1,128 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Helper;
using RRQMCore.XREF.Newtonsoft.Json;
using RRQMSocket.Http;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// Json数据转换器
/// </summary>
public class JsonDataConverter : ApiDataConverter
{
/// <summary>
/// OnPost
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
public override void OnPost(HttpRequest httpRequest, ref MethodInvoker methodInvoker, MethodInstance methodInstance)
{
switch (httpRequest.Content_Type)
{
case "application/x-www-form-urlencoded":
{
if (httpRequest.Params != null)
{
for (int i = 0; i < methodInstance.Parameters.Length; i++)
{
if (httpRequest.Params.TryGetValue(methodInstance.ParameterNames[i], out string value))
{
methodInvoker.Parameters[i] = value.ParseToType(methodInstance.ParameterTypes[i]);
}
else
{
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
}
}
}
break;
}
case "application/json":
{
if (methodInstance.Parameters.Length > 0)
{
for (int i = 0; i < methodInstance.Parameters.Length; i++)
{
if (i == 0)
{
methodInvoker.Parameters[i] = JsonConvert.DeserializeObject(httpRequest.Body, methodInstance.ParameterTypes[0]);
}
else
{
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
}
}
}
break;
}
}
}
/// <summary>
/// 在调用完成时转换结果
/// </summary>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
/// <returns></returns>
public override HttpResponse OnResult(MethodInvoker methodInvoker, MethodInstance methodInstance)
{
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
HttpResponse httpResponse = new HttpResponse();
switch (methodInvoker.Status)
{
case InvokeStatus.Success:
{
if (methodInvoker.ReturnParameter != null)
{
httpResponse.FromJson(JsonConvert.SerializeObject(methodInvoker.ReturnParameter));
break;
}
else
{
httpResponse.FromText(string.Empty);
}
break;
}
case InvokeStatus.UnFound:
{
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromJson(jsonString, "404");
break;
}
case InvokeStatus.UnEnable:
{
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromJson(jsonString, "405");
break;
}
case InvokeStatus.Abort:
{
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromJson(jsonString, "403");
break;
}
case InvokeStatus.InvocationException:
case InvokeStatus.Exception:
{
string jsonString = JsonConvert.SerializeObject(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromJson(jsonString, "422");
break;
}
}
return httpResponse;
}
}
}

View File

@@ -1,129 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Helper;
using RRQMCore.Serialization;
using RRQMSocket.Http;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// Xml结果转换器
/// </summary>
public class XmlDataConverter : ApiDataConverter
{
/// <summary>
/// OnPost
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
public override void OnPost(HttpRequest httpRequest, ref MethodInvoker methodInvoker, MethodInstance methodInstance)
{
switch (httpRequest.Content_Type)
{
case "application/x-www-form-urlencoded":
{
if (httpRequest.Params != null)
{
for (int i = 0; i < methodInstance.Parameters.Length; i++)
{
if (httpRequest.Params.TryGetValue(methodInstance.ParameterNames[i], out string value))
{
methodInvoker.Parameters[i] = value.ParseToType(methodInstance.ParameterTypes[i]);
}
else
{
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
}
}
}
break;
}
case "application/xml":
{
if (methodInstance.Parameters.Length > 0)
{
for (int i = 0; i < methodInstance.Parameters.Length; i++)
{
if (i == 0)
{
methodInvoker.Parameters[i] = SerializeConvert.XmlDeserializeFromBytes(
httpRequest.Encoding.GetBytes(httpRequest.Body), methodInstance.ParameterTypes[0]);
}
else
{
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
}
}
}
break;
}
}
}
/// <summary>
/// 在调用完成时转换结果
/// </summary>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
/// <returns></returns>
public override HttpResponse OnResult(MethodInvoker methodInvoker, MethodInstance methodInstance)
{
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
HttpResponse httpResponse = new HttpResponse();
switch (methodInvoker.Status)
{
case InvokeStatus.Success:
{
if (methodInvoker.ReturnParameter != null)
{
httpResponse.FromXML(SerializeConvert.XmlSerializeToString(methodInvoker.ReturnParameter));
break;
}
else
{
httpResponse.FromText(string.Empty);
}
break;
}
case InvokeStatus.UnFound:
{
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromXML(xmlString, "404");
break;
}
case InvokeStatus.UnEnable:
{
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromXML(xmlString, "405");
break;
}
case InvokeStatus.Abort:
{
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromXML(xmlString, "403");
break;
}
case InvokeStatus.InvocationException:
case InvokeStatus.Exception:
{
string xmlString = SerializeConvert.XmlSerializeToString(new ActionResult() { Status = methodInvoker.Status, Message = methodInvoker.StatusMessage });
httpResponse.FromXML(xmlString, "422");
break;
}
}
return httpResponse;
}
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,70 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<ApplicationIcon>RRQM.ico</ApplicationIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
<Version>5.6.0</Version>
<Company>若汝棋茗</Company>
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
<Description>介绍这是一个扩展于RRQMSocket.RPC的WebApi组件可以通过该组件直接创建WebApi服务解析器让Web端、移动端可以跨语言调用RPC函数。功能支持路由、Get传参、Post传参等。
更新说明:
修改为稳定版。
Demohttps://gitee.com/RRQM_OS/RRQMBox
APIhttps://gitee.com/RRQM_OS/RRQM/wikis/pages </Description>
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
<PackageIconUrl></PackageIconUrl>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PackageIcon>RRQM.png</PackageIcon>
<Authors>若汝棋茗</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageTags>WebApi,RPC,IOCP</PackageTags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
<DocumentationFile>bin\Debug\net45\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
<DocumentationFile>bin\Release\net45\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.RPC.WebApi.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="RRQM.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="RRQMSocket.Http" Version="5.6.0" />
<PackageReference Include="RRQMSocket.RPC" Version="5.6.0" />
</ItemGroup>
</Project>

View File

@@ -1,282 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Helper;
using RRQMCore.Log;
using RRQMSocket.Http;
using System;
using System.Net.Sockets;
using System.Reflection;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// WebApi解析器
/// </summary>
public class WebApiParser : TcpService<WebApiSocketClient>, IRPCParser
{
private RouteMap routeMap;
/// <summary>
/// 构造函数
/// </summary>
public WebApiParser()
{
this.routeMap = new RouteMap();
}
/// <summary>
/// 数据转化器
/// </summary>
public ApiDataConverter ApiDataConverter { get; private set; }
private int maxPackageSize;
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return maxPackageSize; }
}
/// <summary>
/// 函数映射
/// </summary>
public MethodMap MethodMap { get; private set; }
/// <summary>
/// 获取路由映射图
/// </summary>
public RouteMap RouteMap { get { return this.routeMap; } }
/// <summary>
/// 所属服务器
/// </summary>
public RPCService RPCService { get; private set; }
/// <summary>
/// 执行函数
/// </summary>
public Action<IRPCParser, MethodInvoker, MethodInstance> RRQMExecuteMethod { get; private set; }
/// <summary>
/// 结束调用
/// </summary>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance)
{
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
SimpleSocketClient socketClient = (SimpleSocketClient)methodInvoker.Caller;
HttpResponse httpResponse = this.ApiDataConverter.OnResult(methodInvoker, methodInstance);
httpResponse.ProtocolVersion = httpRequest.ProtocolVersion;
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
try
{
httpResponse.Build(byteBlock);
socketClient.Send(byteBlock);
}
finally
{
byteBlock.Dispose();
}
if (!httpRequest.KeepAlive)
{
socketClient.Shutdown(SocketShutdown.Both);
}
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
/// <param name="methodInstances"></param>
public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances)
{
foreach (var methodInstance in methodInstances)
{
if ((typeof(ControllerBase).IsAssignableFrom(methodInstance.Provider.GetType())))
{
string controllerName;
RouteAttribute classAtt = methodInstance.Provider.GetType().GetCustomAttribute<RouteAttribute>(false);
if (classAtt == null || string.IsNullOrEmpty(classAtt.Template))
{
controllerName = methodInstance.Provider.GetType().Name;
}
else
{
controllerName = classAtt.Template.Replace("[controller]", methodInstance.Provider.GetType().Name);
}
foreach (var att in methodInstance.RPCAttributes)
{
if (att is RouteAttribute attribute)
{
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
throw new RRQMRPCException("WebApi调用不支持上下文调用");
}
if (methodInstance.IsByRef)
{
throw new RRQMRPCException("WebApi服务中不允许有out及ref关键字");
}
string actionUrl;
if (controllerName.Contains("[action]"))
{
actionUrl = controllerName.Replace("[action]", methodInstance.Method.Name);
}
else
{
if (string.IsNullOrEmpty(attribute.Template))
{
actionUrl = $"{controllerName}/{methodInstance.Method.Name}";
}
else
{
actionUrl = $"{controllerName}/{attribute.Template.Replace("[action]", methodInstance.Method.Name)}";
}
}
this.routeMap.Add(actionUrl, methodInstance);
}
}
}
}
}
/// <summary>
/// 取消注册服务
/// </summary>
/// <param name="provider"></param>
/// <param name="methodInstances"></param>
public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances)
{
}
/// <summary>
/// 设置执行委托
/// </summary>
/// <param name="executeMethod"></param>
public void SetExecuteMethod(Action<IRPCParser, MethodInvoker, MethodInstance> executeMethod)
{
this.RRQMExecuteMethod = executeMethod;
}
/// <summary>
/// 设置地图映射
/// </summary>
/// <param name="methodMap"></param>
public void SetMethodMap(MethodMap methodMap)
{
this.MethodMap = methodMap;
}
/// <summary>
/// 设置服务
/// </summary>
/// <param name="service"></param>
public void SetRPCService(RPCService service)
{
this.RPCService = service;
}
/// <summary>
/// 载入配置
/// </summary>
/// <param name="serviceConfig"></param>
protected override void LoadConfig(ServiceConfig serviceConfig)
{
base.LoadConfig(serviceConfig);
this.ApiDataConverter = (ApiDataConverter)serviceConfig.GetValue(WebApiParserConfig.ApiDataConverterProperty);
this.maxPackageSize = (int)serviceConfig.GetValue(WebApiParserConfig.MaxPackageSizeProperty);
}
/// <summary>
/// 在初次接收时
/// </summary>
/// <param name="socketClient"></param>
/// <param name="createOption"></param>
protected override void OnCreateSocketCliect(WebApiSocketClient socketClient, CreateOption createOption)
{
socketClient.OnReceived = this.OnReceived;
socketClient.SetAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Server));
}
private void OnReceived(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj)
{
HttpRequest httpRequest = (HttpRequest)obj;
MethodInvoker methodInvoker = new MethodInvoker();
methodInvoker.Caller = (WebApiSocketClient)socketClient;
methodInvoker.Flag = httpRequest;
if (this.routeMap.TryGet(httpRequest.RelativeURL, out MethodInstance methodInstance))
{
if (methodInstance.IsEnable)
{
try
{
methodInvoker.Parameters = new object[methodInstance.Parameters.Length];
switch (httpRequest.Method)
{
case "GET":
{
if (httpRequest.Query != null)
{
for (int i = 0; i < methodInstance.Parameters.Length; i++)
{
if (httpRequest.Query.TryGetValue(methodInstance.ParameterNames[i], out string value))
{
methodInvoker.Parameters[i] = value.ParseToType(methodInstance.ParameterTypes[i]);
}
else
{
methodInvoker.Parameters[i] = methodInstance.ParameterTypes[i].GetDefault();
}
}
}
break;
}
case "POST":
{
this.ApiDataConverter.OnPost(httpRequest, ref methodInvoker, methodInstance);
break;
}
}
}
catch (Exception ex)
{
methodInvoker.Status = InvokeStatus.Exception;
methodInvoker.StatusMessage = ex.Message;
this.Logger.Debug(LogType.Error, this, ex.Message, ex);
}
}
else
{
methodInvoker.Status = InvokeStatus.UnEnable;
}
}
else
{
methodInvoker.Status = InvokeStatus.UnFound;
}
this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance);
}
}
}

View File

@@ -1,40 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RRQMSocket.RPC.WebApi
{
/// <summary>
/// WebApiSocket辅助类
/// </summary>
public class WebApiSocketClient : SimpleSocketClient,ICaller
{
/// <summary>
/// 禁用适配器赋值
/// </summary>
/// <param name="adapter"></param>
public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter)
{
throw new RRQMException($"{nameof(WebApiSocketClient)}不允许设置适配器。");
}
internal void SetAdapter(DataHandlingAdapter adapter)
{
base.SetDataHandlingAdapter(adapter);
}
}
}

View File

@@ -1,43 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace RRQMSocket.RPC.XmlRpc
{
/// <summary>
/// 适用于XmlRpc的标记
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class XmlRpcAttribute : RPCAttribute
{
/// <summary>
/// 构造函数
/// </summary>
public XmlRpcAttribute()
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="actionKey"></param>
public XmlRpcAttribute(string actionKey)
{
this.ActionKey = actionKey;
}
/// <summary>
/// 服务唯一标识
/// </summary>
public string ActionKey { get; private set; }
}
}

View File

@@ -1,70 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
namespace RRQMSocket.RPC.XmlRpc
{
/// <summary>
/// 服务映射图
/// </summary>
public class ActionMap : IEnumerable<KeyValuePair<string, MethodInstance>>
{
internal ActionMap()
{
this.actionMap = new Dictionary<string, MethodInstance>();
}
private Dictionary<string, MethodInstance> actionMap;
internal void Add(string actionKey, MethodInstance methodInstance)
{
this.actionMap.Add(actionKey, methodInstance);
}
/// <summary>
/// 服务键集合
/// </summary>
public IEnumerable<string> ActionKeys { get { return this.actionMap.Keys; } }
/// <summary>
/// 通过routeUrl获取函数实例
/// </summary>
/// <param name="actionKey"></param>
/// <param name="methodInstance"></param>
/// <returns></returns>
public bool TryGet(string actionKey, out MethodInstance methodInstance)
{
if (this.actionMap.ContainsKey(actionKey))
{
methodInstance = this.actionMap[actionKey];
return true;
}
methodInstance = null;
return false;
}
/// <summary>
/// 返回迭代器
/// </summary>
/// <returns></returns>
public IEnumerator<KeyValuePair<string, MethodInstance>> GetEnumerator()
{
return this.actionMap.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.actionMap.GetEnumerator();
}
}
}

View File

@@ -1,270 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Helper;
using RRQMSocket.Http;
using System;
using System.Collections;
using System.Reflection;
using System.Text;
using System.Xml;
namespace RRQMSocket.RPC.XmlRpc
{
internal static class XmlDataTool
{
public static object GetValue(XmlNode valueNode, Type type)
{
if (valueNode == null)
{
return type.GetDefault();
}
switch (valueNode.Name)
{
case "boolean":
{
return bool.Parse(valueNode.InnerText);
}
case "i4":
case "int":
{
return int.Parse(valueNode.InnerText);
}
case "double":
{
return double.Parse(valueNode.InnerText);
}
case "dateTime.iso8601":
{
return DateTime.Parse(valueNode.InnerText);
}
case "base64":
{
return valueNode.InnerText;
}
case "struct":
{
object instance = Activator.CreateInstance(type);
foreach (XmlNode memberNode in valueNode.ChildNodes)
{
string name = memberNode.SelectSingleNode("name").InnerText;
PropertyInfo property = type.GetProperty(name);
property.SetValue(instance, GetValue(memberNode.SelectSingleNode("value").FirstChild, property.PropertyType));
}
return instance;
}
case "arrays":
case "array":
{
if (type.GetElementType() != null)
{
XmlNode dataNode = valueNode.SelectSingleNode("data");
Array array = Array.CreateInstance(type.GetElementType(), dataNode.ChildNodes.Count);
int index = 0;
foreach (XmlNode arrayValueNode in dataNode.ChildNodes)
{
array.SetValue(GetValue(arrayValueNode.FirstChild, type.GetElementType()), index);
index++;
}
return array;
}
else if (type.GetGenericArguments().Length == 1)
{
XmlNode dataNode = valueNode.SelectSingleNode("data");
IList array = (IList)Activator.CreateInstance(type);
foreach (XmlNode arrayValueNode in dataNode.ChildNodes)
{
array.Add(GetValue(arrayValueNode.FirstChild, type.GetGenericArguments()[0]));
}
return array;
}
return type.GetDefault();
}
default:
case "string":
{
return valueNode.InnerText;
}
}
}
public static void CreateRequest(ByteBlock byteBlock, string host, string method, object[] parameters)
{
XmlDocument xml = new XmlDocument();
XmlDeclaration xmlDecl = xml.CreateXmlDeclaration("1.0", string.Empty, string.Empty);
xml.AppendChild(xmlDecl);
XmlElement xmlElement = xml.CreateElement("methodCall");
xml.AppendChild(xmlElement);
XmlElement methodNameElement = xml.CreateElement("methodName");
methodNameElement.InnerText = method;
xmlElement.AppendChild(methodNameElement);
XmlElement paramsElement = xml.CreateElement("params");
xmlElement.AppendChild(paramsElement);
foreach (var param in parameters)
{
XmlElement paramElement = xml.CreateElement("param");
paramsElement.AppendChild(paramElement);
XmlElement valueElement = xml.CreateElement("value");
paramElement.AppendChild(valueElement);
CreateParam(xml, valueElement, param);
}
ByteBlock xmlBlock = BytePool.Default.GetByteBlock(byteBlock.Capacity);
xml.Save(xmlBlock);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("POST / HTTP/1.1");
stringBuilder.AppendLine("Content-Type: text/xml");
stringBuilder.AppendLine($"Host: {host}");
stringBuilder.AppendLine("User-Agent: RRQMXmlRpc");
stringBuilder.AppendLine($"Content-Length: {xmlBlock.Length}");
//stringBuilder.AppendLine("Connection: Close");
stringBuilder.AppendLine("Connection: keep-alive");
stringBuilder.AppendLine();
try
{
byteBlock.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString()));
byteBlock.Write(xmlBlock.Buffer, 0, xmlBlock.Len);
}
finally
{
xmlBlock.Dispose();
}
}
public static void CreateParam(XmlDocument xml, XmlNode xmlNode, object value)
{
if (value == null)
{
return;
}
if (value is int)
{
XmlElement valueElement = xml.CreateElement("i4");
valueElement.InnerText = value.ToString();
xmlNode.AppendChild(valueElement);
}
else if (value is bool)
{
XmlElement valueElement = xml.CreateElement("boolean");
valueElement.InnerText = (value).ToString();
xmlNode.AppendChild(valueElement);
}
else if (value is double)
{
XmlElement valueElement = xml.CreateElement("double");
valueElement.InnerText = ((double)value).ToString();
xmlNode.AppendChild(valueElement);
}
else if (value is string)
{
XmlElement valueElement = xml.CreateElement("string");
valueElement.InnerText = value.ToString();
xmlNode.AppendChild(valueElement);
}
else if (value is DateTime)
{
XmlElement valueElement = xml.CreateElement("dateTime.iso8601");
valueElement.InnerText = ((DateTime)value).ToString();
xmlNode.AppendChild(valueElement);
}
else if (value is byte[])
{
XmlElement valueElement = xml.CreateElement("base64");
string str = Convert.ToBase64String((byte[])value);
valueElement.InnerText = str;
xmlNode.AppendChild(valueElement);
}
else if (typeof(IList).IsAssignableFrom(value.GetType()))
{
IList array = (IList)value;
XmlElement arrayElement;
arrayElement = xml.CreateElement("array");
xmlNode.AppendChild(arrayElement);
XmlElement dataElememt = xml.CreateElement("data");
arrayElement.AppendChild(dataElememt);
foreach (var item in array)
{
XmlElement valueElement = xml.CreateElement("value");
dataElememt.AppendChild(valueElement);
CreateParam(xml, valueElement, item);
}
}
else
{
XmlElement valueElement = xml.CreateElement("struct");
xmlNode.AppendChild(valueElement);
PropertyInfo[] propertyInfos = value.GetType().GetProperties();
foreach (var propertyInfo in propertyInfos)
{
XmlElement memberElement = xml.CreateElement("member");
valueElement.AppendChild(memberElement);
XmlElement nameElement = xml.CreateElement("name");
nameElement.InnerText = propertyInfo.Name;
memberElement.AppendChild(nameElement);
XmlElement oValueElement = xml.CreateElement("value");
memberElement.AppendChild(oValueElement);
object oValue = propertyInfo.GetValue(value);
CreateParam(xml, oValueElement, oValue);
}
}
}
public static void CreatResponse(HttpResponse httpResponse, object value)
{
XmlDocument xml = new XmlDocument();
XmlDeclaration xmlDecl = xml.CreateXmlDeclaration("1.0", string.Empty, string.Empty);
xml.AppendChild(xmlDecl);
XmlElement xmlElement = xml.CreateElement("methodResponse");
xml.AppendChild(xmlElement);
XmlElement paramsElement = xml.CreateElement("params");
xmlElement.AppendChild(paramsElement);
XmlElement paramElement = xml.CreateElement("param");
paramsElement.AppendChild(paramElement);
XmlElement valueElement = xml.CreateElement("value");
paramElement.AppendChild(valueElement);
CreateParam(xml, valueElement, value);
ByteBlock xmlBlock = BytePool.Default.GetByteBlock(1024 * 4);
xml.Save(xmlBlock);
string xmlString = Encoding.UTF8.GetString(xmlBlock.Buffer, 0, xmlBlock.Len);
httpResponse.FromXML(xmlString);
xmlBlock.Dispose();
}
}
}

View File

@@ -1,54 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Dependency;
namespace RRQMSocket.RPC.XmlRpc
{
/// <summary>
/// XmlRpcClient配置
/// </summary>
public class XmlRpcClientConfig : TcpClientConfig
{
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return (int)GetValue(MaxPackageSizeProperty); }
set { SetValue(MaxPackageSizeProperty, value); }
}
/// <summary>
/// 最大数据包长度,所需类型<see cref="int"/>
/// </summary>
public static readonly DependencyProperty MaxPackageSizeProperty =
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(XmlRpcClientConfig), 1024);
/// <summary>
/// 等待超时时间(秒)
/// </summary>
public int Timeout
{
get { return (int)GetValue(TimeoutProperty); }
set { SetValue(TimeoutProperty, value); }
}
/// <summary>
/// 等待超时时间(秒),
/// 所需类型<see cref="int"/>
/// </summary>
public static readonly DependencyProperty TimeoutProperty =
DependencyProperty.Register("Timeout", typeof(int), typeof(XmlRpcClientConfig), 5);
}
}

View File

@@ -1,38 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Dependency;
namespace RRQMSocket.RPC.XmlRpc
{
/// <summary>
/// XmlRpcParser配置
/// </summary>
public class XmlRpcParserConfig : TcpServiceConfig
{
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return (int)GetValue(MaxPackageSizeProperty); }
set { SetValue(MaxPackageSizeProperty, value); }
}
/// <summary>
/// 最大数据包长度,所需类型<see cref="int"/>
/// </summary>
public static readonly DependencyProperty MaxPackageSizeProperty =
DependencyProperty.Register("MaxPackageSize", typeof(int), typeof(XmlRpcParserConfig), 1024);
}
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,70 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<ApplicationIcon>RRQM.ico</ApplicationIcon>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>RRQM.pfx</AssemblyOriginatorKeyFile>
<Version>5.6.0</Version>
<Company>若汝棋茗</Company>
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
<Description>介绍这是一个扩展于RRQMSocket.RPC的XmlRpc组件可以通过该组件直接创建XmlRpc服务解析器让Web端、移动端可以跨语言调用RPC函数。功能支持XmlRpc全功能。
更新说明:
同步更新。
Demohttps://gitee.com/RRQM_OS/RRQMBox
APIhttps://gitee.com/RRQM_OS/RRQM/wikis/pages </Description>
<PackageProjectUrl>https://gitee.com/dotnetchina/RRQMSocket</PackageProjectUrl>
<PackageIconUrl></PackageIconUrl>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PackageIcon>RRQM.png</PackageIcon>
<Authors>若汝棋茗</Authors>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageTags>RPC;XmlRpc;Socket,IOCP</PackageTags>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
<DocumentationFile>bin\Debug\net45\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
<DocumentationFile>bin\Release\net45\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.RPC.XmlRpc.xml</DocumentationFile>
<OutputPath></OutputPath>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="RRQM.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="RRQMSocket.Http" Version="5.6.0" />
<PackageReference Include="RRQMSocket.RPC" Version="5.6.0" />
</ItemGroup>
</Project>

View File

@@ -1,188 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Exceptions;
using RRQMCore.Run;
using RRQMSocket.Http;
using RRQMSocket.RPC.RRQMRPC;
using System;
using System.Xml;
namespace RRQMSocket.RPC.XmlRpc
{
/// <summary>
/// XmlRpc客户端
/// </summary>
public class XmlRpcClient : TcpClient, IRpcClient
{
/// <summary>
/// 构造函数
/// </summary>
public XmlRpcClient()
{
singleWaitHandle = new WaitData<HttpResponse>();
}
private int maxPackageSize;
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return maxPackageSize; }
}
private WaitData<HttpResponse> singleWaitHandle;
private int timeout;
/// <summary>
/// 载入配置
/// </summary>
/// <param name="clientConfig"></param>
protected override void LoadConfig(TcpClientConfig clientConfig)
{
base.LoadConfig(clientConfig);
this.timeout = (int)clientConfig.GetValue(XmlRpcClientConfig.TimeoutProperty);
this.maxPackageSize = (int)clientConfig.GetValue(XmlRpcClientConfig.MaxPackageSizeProperty);
this.SetDataHandlingAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Client));
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <param name="types"></param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
/// <returns></returns>
public T Invoke<T>(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
{
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
HttpResponse response;
try
{
XmlDataTool.CreateRequest(byteBlock, this.Name, method, parameters);
response = this.WaitSend(byteBlock);
if (response.StatusCode != "200")
{
throw new RRQMException("调用错误");
}
XmlDocument xml = new XmlDocument();
xml.LoadXml(response.Body);
XmlNode paramNode = xml.SelectSingleNode("methodResponse/params/param");
if (paramNode != null)
{
return (T)XmlDataTool.GetValue(paramNode.FirstChild.FirstChild, typeof(T));
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
byteBlock.Dispose();
}
return default;
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <param name="types"></param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
public void Invoke(string method, InvokeOption invokeOption, ref object[] parameters, Type[] types)
{
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
HttpResponse response;
try
{
XmlDataTool.CreateRequest(byteBlock, this.Name, method, parameters);
response = this.WaitSend(byteBlock);
if (response.StatusCode != "200")
{
throw new RRQMException("调用错误");
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
byteBlock.Dispose();
}
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
public void Invoke(string method, InvokeOption invokeOption, params object[] parameters)
{
this.Invoke(method, invokeOption, ref parameters, null);
}
/// <summary>
/// RPC调用
/// </summary>
/// <param name="method">方法名</param>
/// <param name="invokeOption">调用配置</param>
/// <param name="parameters">参数</param>
/// <exception cref="RRQMTimeoutException"></exception>
/// <exception cref="RRQMRPCInvokeException"></exception>
/// <exception cref="RRQMException"></exception>
/// <returns></returns>
public T Invoke<T>(string method, InvokeOption invokeOption, params object[] parameters)
{
return this.Invoke<T>(method, invokeOption, ref parameters, null);
}
/// <summary>
/// 处理数据
/// </summary>
/// <param name="byteBlock"></param>
/// <param name="obj"></param>
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
{
this.singleWaitHandle.Set((HttpResponse)obj);
}
private HttpResponse WaitSend(ByteBlock byteBlock)
{
lock (locker)
{
this.Send(byteBlock.Buffer, 0, byteBlock.Len);
if (this.singleWaitHandle.Wait(1000 * this.timeout))
{
return this.singleWaitHandle.WaitResult;
}
throw new RRQMTimeoutException("超时接收");
}
}
}
}

View File

@@ -1,235 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
using RRQMCore.Log;
using RRQMSocket.Http;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Xml;
namespace RRQMSocket.RPC.XmlRpc
{
/// <summary>
/// XmlRpc解析器
/// </summary>
public class XmlRpcParser : TcpService<XmlRpcSocketClient>, IRPCParser
{
private ActionMap actionMap;
/// <summary>
/// 构造函数
/// </summary>
public XmlRpcParser()
{
this.actionMap = new ActionMap();
}
/// <summary>
/// 服务键映射图
/// </summary>
public ActionMap ActionMap { get { return this.actionMap; } }
private int maxPackageSize;
/// <summary>
/// 最大数据包长度
/// </summary>
public int MaxPackageSize
{
get { return maxPackageSize; }
}
/// <summary>
/// 函数映射
/// </summary>
public MethodMap MethodMap { get; private set; }
/// <summary>
/// 所属服务器
/// </summary>
public RPCService RPCService { get; private set; }
/// <summary>
/// 执行函数
/// </summary>
public Action<IRPCParser, MethodInvoker, MethodInstance> RRQMExecuteMethod { get; private set; }
/// <summary>
/// 结束调用
/// </summary>
/// <param name="methodInvoker"></param>
/// <param name="methodInstance"></param>
public void OnEndInvoke(MethodInvoker methodInvoker, MethodInstance methodInstance)
{
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
SimpleSocketClient socketClient = (SimpleSocketClient)methodInvoker.Caller;
HttpResponse httpResponse = new HttpResponse();
httpResponse.ProtocolVersion = httpRequest.ProtocolVersion;
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
XmlDataTool.CreatResponse(httpResponse, methodInvoker.ReturnParameter);
try
{
httpResponse.Build(byteBlock);
socketClient.Send(byteBlock);
}
finally
{
byteBlock.Dispose();
}
if (!httpRequest.KeepAlive)
{
socketClient.Shutdown(SocketShutdown.Both);
}
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="provider"></param>
/// <param name="methodInstances"></param>
public void OnRegisterServer(IServerProvider provider, MethodInstance[] methodInstances)
{
foreach (var methodInstance in methodInstances)
{
foreach (var att in methodInstance.RPCAttributes)
{
if (att is XmlRpcAttribute attribute)
{
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
throw new RRQMRPCException("XmlRpc不支持上下文调用");
}
if (methodInstance.IsByRef)
{
throw new RRQMRPCException("XmlRpc服务中不允许有out及ref关键字");
}
string actionKey = string.IsNullOrEmpty(attribute.ActionKey) ? $"{methodInstance.Method.Name}" : attribute.ActionKey;
this.actionMap.Add(actionKey, methodInstance);
}
}
}
}
/// <summary>
/// 取消注册服务
/// </summary>
/// <param name="provider"></param>
/// <param name="methodInstances"></param>
public void OnUnregisterServer(IServerProvider provider, MethodInstance[] methodInstances)
{
}
/// <summary>
/// 载入配置
/// </summary>
/// <param name="serviceConfig"></param>
protected override void LoadConfig(ServiceConfig serviceConfig)
{
base.LoadConfig(serviceConfig);
this.maxPackageSize = (int)serviceConfig.GetValue(XmlRpcParserConfig.MaxPackageSizeProperty);
}
/// <summary>
/// 设置执行委托
/// </summary>
/// <param name="executeMethod"></param>
public void SetExecuteMethod(Action<IRPCParser, MethodInvoker, MethodInstance> executeMethod)
{
this.RRQMExecuteMethod = executeMethod;
}
/// <summary>
/// 设置地图映射
/// </summary>
/// <param name="methodMap"></param>
public void SetMethodMap(MethodMap methodMap)
{
this.MethodMap = methodMap;
}
/// <summary>
/// 设置服务
/// </summary>
/// <param name="service"></param>
public void SetRPCService(RPCService service)
{
this.RPCService = service;
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="socketClient"></param>
/// <param name="createOption"></param>
protected override void OnCreateSocketCliect(XmlRpcSocketClient socketClient, CreateOption createOption)
{
socketClient.OnReceived = this.OnReceived;
socketClient.SetAdapter(new HttpDataHandlingAdapter(this.maxPackageSize, HttpType.Server));
}
private void OnReceived(SimpleSocketClient socketClient, ByteBlock byteBlock, object obj)
{
HttpRequest httpRequest = (HttpRequest)obj;
MethodInvoker methodInvoker = new MethodInvoker();
methodInvoker.Caller = (XmlRpcSocketClient)socketClient;
methodInvoker.Flag = httpRequest;
XmlDocument xml = new XmlDocument();
xml.LoadXml(httpRequest.Body);
XmlNode methodName = xml.SelectSingleNode("methodCall/methodName");
string actionKey = methodName.InnerText;
if (this.actionMap.TryGet(actionKey, out MethodInstance methodInstance))
{
if (methodInstance.IsEnable)
{
try
{
List<object> ps = new List<object>();
XmlNode paramsNode = xml.SelectSingleNode("methodCall/params");
int index = 0;
foreach (XmlNode paramNode in paramsNode.ChildNodes)
{
XmlNode valueNode = paramNode.FirstChild.FirstChild;
ps.Add(XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index]));
index++;
}
methodInvoker.Parameters = ps.ToArray();
}
catch (Exception ex)
{
methodInvoker.Status = InvokeStatus.Exception;
methodInvoker.StatusMessage = ex.Message;
this.Logger.Debug(LogType.Error, this, ex.Message, ex);
}
}
else
{
methodInvoker.Status = InvokeStatus.UnEnable;
}
}
else
{
methodInvoker.Status = InvokeStatus.UnFound;
}
this.RRQMExecuteMethod.Invoke(this, methodInvoker, methodInstance);
}
}
}

View File

@@ -1,40 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RRQMSocket.RPC.XmlRpc
{
/// <summary>
/// XmlRpc辅助类
/// </summary>
public class XmlRpcSocketClient: SimpleSocketClient,ICaller
{
/// <summary>
/// 禁用适配器赋值
/// </summary>
/// <param name="adapter"></param>
public sealed override void SetDataHandlingAdapter(DataHandlingAdapter adapter)
{
throw new RRQMException($"{nameof(XmlRpcSocketClient)}不允许设置适配器。");
}
internal void SetAdapter(DataHandlingAdapter adapter)
{
base.SetDataHandlingAdapter(adapter);
}
}
}

View File

@@ -1,23 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore.ByteManager;
namespace RRQMSocket.RPC
{
/// <summary>
/// 收到字节数据
/// </summary>
/// <param name="sender"></param>
/// <param name="procotol"></param>
/// <param name="byteBlock"></param>
public delegate void RRQMReceivedProcotolEventHandler(object sender, short? procotol, ByteBlock byteBlock);
}

View File

@@ -1,49 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
namespace RRQMSocket.RPC
{
/// <summary>
/// RPC方法属性基类
/// </summary>
public abstract class RPCAttribute : Attribute
{
/// <summary>
/// 构造函数
/// </summary>
public RPCAttribute()
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="methodFlags"></param>
public RPCAttribute(MethodFlags methodFlags)
{
this.methodFlags = methodFlags;
}
private MethodFlags methodFlags = MethodFlags.None;
/// <summary>
/// 函数标识
/// </summary>
public MethodFlags MethodFlags
{
get { return methodFlags; }
}
}
}

View File

@@ -1,133 +0,0 @@
using RRQMCore;
using RRQMCore.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace RRQMSocket.RPC
{
/// <summary>
/// 工具
/// </summary>
internal static class GlobalTools
{
private static int nullReturnNullParameters = 100000000;
private static int nullReturnExistParameters = 300000000;
private static int ExistReturnNullParameters = 500000000;
private static int ExistReturnExistParameters = 700000000;
internal static MethodInstance[] GetMethodInstances(IServerProvider serverProvider, bool isSetToken)
{
List<MethodInstance> instances = new List<MethodInstance>();
MethodInfo[] methodInfos = serverProvider.GetType().GetMethods();
foreach (MethodInfo method in methodInfos)
{
if (method.IsGenericMethod)
{
continue;
}
IEnumerable<RPCAttribute> attributes = method.GetCustomAttributes<RPCAttribute>(true);
if (attributes.Count() > 0)
{
MethodInstance methodInstance = new MethodInstance();
methodInstance.Provider = serverProvider;
methodInstance.ProviderType = serverProvider.GetType();
methodInstance.Method = method;
methodInstance.RPCAttributes = attributes.ToArray();
methodInstance.IsEnable = true;
methodInstance.Parameters = method.GetParameters();
foreach (var item in attributes)
{
methodInstance.MethodFlags |= item.MethodFlags;
}
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext))
{
if (methodInstance.Parameters.Length==0||!typeof(IServerCallContext).IsAssignableFrom(methodInstance.Parameters[0].ParameterType) )
{
throw new RRQMRPCException($"函数:{method},标识包含{MethodFlags.IncludeCallContext}时,必须包含{nameof(IServerCallContext)}或其派生类参数,且为第一参数。");
}
}
List<string> names = new List<string>();
foreach (var parameterInfo in methodInstance.Parameters)
{
names.Add(parameterInfo.Name);
}
methodInstance.ParameterNames = names.ToArray();
if (typeof(Task).IsAssignableFrom(method.ReturnType))
{
methodInstance.Async = true;
}
ParameterInfo[] parameters = method.GetParameters();
List<Type> types = new List<Type>();
foreach (var parameter in parameters)
{
types.Add(parameter.ParameterType.GetRefOutType());
if (parameter.ParameterType.IsByRef)
{
methodInstance.IsByRef = true;
}
}
methodInstance.ParameterTypes = types.ToArray();
if (method.ReturnType == typeof(void) || method.ReturnType == typeof(Task))
{
methodInstance.ReturnType = null;
if (isSetToken)
{
if (parameters.Length == 0)
{
methodInstance.MethodToken = ++nullReturnNullParameters;
}
else
{
methodInstance.MethodToken = ++nullReturnExistParameters;
}
}
}
else
{
if (methodInstance.Async)
{
Type[] ts = method.ReturnType.GetGenericArguments();
if (ts.Length == 1)
{
methodInstance.ReturnType = ts[0];
}
else
{
methodInstance.ReturnType = null;
}
}
else
{
methodInstance.ReturnType = method.ReturnType;
}
if (isSetToken)
{
if (parameters.Length == 0)
{
methodInstance.MethodToken = ++ExistReturnNullParameters;
}
else
{
methodInstance.MethodToken = ++ExistReturnExistParameters;
}
}
}
instances.Add(methodInstance);
}
}
return instances.ToArray();
}
}
}

View File

@@ -1,103 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using System;
using System.Linq;
using System.Reflection;
namespace RRQMSocket.RPC
{
/// <summary>
/// RPC函数实例
/// </summary>
public class MethodInstance
{
/// <summary>
/// 执行此RPC的实例
/// </summary>
public IServerProvider Provider { get; internal set; }
/// <summary>
/// 实例类型
/// </summary>
public Type ProviderType { get; internal set; }
/// <summary>
/// RPC函数
/// </summary>
public MethodInfo Method { get; internal set; }
/// <summary>
/// RPC属性集合
/// </summary>
public RPCAttribute[] RPCAttributes { get; internal set; }
/// <summary>
/// 方法唯一令箭
/// </summary>
public int MethodToken { get; internal set; }
/// <summary>
/// 返回值类型无返回值时为Null
/// </summary>
public Type ReturnType { get; internal set; }
/// <summary>
/// 参数类型集合已处理out及ref无参数时为空集合
/// </summary>
public Type[] ParameterTypes { get; internal set; }
/// <summary>
/// 参数集合
/// </summary>
public ParameterInfo[] Parameters { get; internal set; }
/// <summary>
/// 参数名集合
/// </summary>
public string[] ParameterNames { get; internal set; }
/// <summary>
/// 是否异步执行
/// </summary>
public bool Async { get; internal set; }
/// <summary>
/// 是否有引用类型
/// </summary>
public bool IsByRef { get; internal set; }
/// <summary>
/// 是否可用
/// </summary>
public bool IsEnable { get; internal set; }
/// <summary>
/// 函数标识
/// </summary>
public MethodFlags MethodFlags { get; internal set; }
/// <summary>
/// 获取指定类型属性标签
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T GetAttribute<T>()
{
object attribute = this.RPCAttributes.FirstOrDefault((a) => { return a.GetType() == typeof(T); });
if (attribute == null)
{
return default;
}
return (T)attribute;
}
}
}

View File

@@ -1,60 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
namespace RRQMSocket.RPC
{
/// <summary>
/// 函数调用信使
/// </summary>
public class MethodInvoker
{
/// <summary>
/// 返回值
/// </summary>
public object ReturnParameter;
/// <summary>
/// 参数值集合
/// </summary>
public object[] Parameters;
/// <summary>
/// 调用状态
/// </summary>
public InvokeStatus Status;
/// <summary>
/// 调用类型
/// </summary>
public InvokeType InvokeType;
/// <summary>
/// 自定义调用实例
/// </summary>
public IServerProvider CustomServerProvider;
/// <summary>
/// 状态消息
/// </summary>
public string StatusMessage;
/// <summary>
/// 可以传递其他类型的数据容器
/// </summary>
public object Flag;
/// <summary>
/// 此函数执行者
/// </summary>
public ICaller Caller;
}
}

View File

@@ -1,81 +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
// 交流QQ群234762506
// 感谢您的下载和使用
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
using RRQMCore;
using RRQMSocket.RPC.RRQMRPC;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace RRQMSocket.RPC
{
/// <summary>
/// 函数映射图
/// </summary>
public class MethodMap
{
internal MethodMap()
{
this.methodMap = new ConcurrentDictionary<int, MethodInstance>();
}
private ConcurrentDictionary<int, MethodInstance> methodMap;
internal void Add(MethodInstance methodInstance)
{
this.methodMap.TryAdd(methodInstance.MethodToken, methodInstance);
}
/// <summary>
/// 通过methodToken获取函数实例
/// </summary>
/// <param name="methodToken"></param>
/// <param name="methodInstance"></param>
/// <returns></returns>
public bool TryGet(int methodToken, out MethodInstance methodInstance)
{
return this.methodMap.TryGetValue(methodToken, out methodInstance);
}
internal bool RemoveServer(Type type, out IServerProvider serverProvider, out MethodInstance[] methodInstances)
{
serverProvider = null;
bool success = false;
List<MethodInstance> keys = new List<MethodInstance>();
foreach (var methodInstance in this.methodMap.Values)
{
if (methodInstance.Provider.GetType().FullName == type.FullName)
{
success = true;
serverProvider = methodInstance.Provider;
keys.Add(methodInstance);
}
}
foreach (var item in keys)
{
this.methodMap.TryRemove(item.MethodToken, out _);
}
methodInstances = keys.ToArray();
return success;
}
/// <summary>
/// 获取所有服务函数实例
/// </summary>
/// <returns></returns>
public MethodInstance[] GetAllMethodInstances()
{
return this.methodMap.Values.ToArray();
}
}
}

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