mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 18:06:45 +08:00
合并项目
This commit is contained in:
187
RRQMSocket.FileTransfer/Control/FileBaseTool.cs
Normal file
187
RRQMSocket.FileTransfer/Control/FileBaseTool.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Serialization;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
internal static class FileBaseTool
|
||||
{
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// 创建流文件
|
||||
/// </summary>
|
||||
/// <param name="blocks"></param>
|
||||
/// <param name="restart"></param>
|
||||
/// <returns></returns>
|
||||
internal static RRQMStream GetNewFileStream(ref ProgressBlockCollection blocks, bool restart)
|
||||
{
|
||||
RRQMStream stream;
|
||||
string path = blocks.FileInfo.FilePath + ".rrqm";
|
||||
byte[] buffer = new byte[1024 * 1024];
|
||||
|
||||
if (File.Exists(path) && !restart)
|
||||
{
|
||||
stream = new RRQMStream(path, FileMode.Open, FileAccess.ReadWrite);
|
||||
stream.Read(buffer, 0, buffer.Length);
|
||||
PBCollectionTemp readBlocks = SerializeConvert.RRQMBinaryDeserialize<PBCollectionTemp>(buffer);
|
||||
if (readBlocks.FileInfo.FileHash != null && blocks.FileInfo.FileHash != null && readBlocks.FileInfo.FileHash == blocks.FileInfo.FileHash)
|
||||
{
|
||||
blocks = readBlocks.ToPBCollection();
|
||||
stream.fileInfo = blocks.FileInfo;
|
||||
return stream;
|
||||
}
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
|
||||
byte[] dataBuffer = SerializeConvert.RRQMBinarySerialize(PBCollectionTemp.GetFromProgressBlockCollection(blocks), true);
|
||||
for (int i = 0; i < dataBuffer.Length; i++)
|
||||
{
|
||||
buffer[i] = dataBuffer[i];
|
||||
}
|
||||
|
||||
stream = new RRQMStream(path, FileMode.Create, FileAccess.ReadWrite);
|
||||
stream.fileInfo = blocks.FileInfo;
|
||||
stream.Position = 0;
|
||||
stream.Write(buffer, 0, buffer.Length);
|
||||
stream.Flush();
|
||||
return stream;
|
||||
}
|
||||
|
||||
internal static void SaveProgressBlockCollection(RRQMStream stream, ProgressBlockCollection blocks)
|
||||
{
|
||||
byte[] buffer = new byte[1024 * 1024];
|
||||
byte[] dataBuffer = SerializeConvert.RRQMBinarySerialize(PBCollectionTemp.GetFromProgressBlockCollection(blocks), true);
|
||||
for (int i = 0; i < dataBuffer.Length; i++)
|
||||
{
|
||||
buffer[i] = dataBuffer[i];
|
||||
}
|
||||
stream.Position = 0;
|
||||
stream.Write(buffer, 0, buffer.Length);
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
internal static bool WriteFile(RRQMStream stream, out string mes, long streamPosition, byte[] buffer, int offset, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (stream == null || !stream.CanWrite)
|
||||
{
|
||||
mes = "流已释放";
|
||||
return false;
|
||||
}
|
||||
stream.Position = streamPosition + 1024 * 1024;
|
||||
stream.Write(buffer, offset, length);
|
||||
stream.Flush();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void FileFinished(RRQMStream stream)
|
||||
{
|
||||
stream.Position = 1024 * 1024;
|
||||
using (FileStream fileStream = new FileStream(stream.fileInfo.FilePath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
byte[] buffer = new byte[1024 * 10];
|
||||
while (true)
|
||||
{
|
||||
int r = stream.Read(buffer, 0, buffer.Length);
|
||||
if (r == 0)
|
||||
{
|
||||
stream.Dispose();
|
||||
break;
|
||||
}
|
||||
fileStream.Write(buffer, 0, r);
|
||||
}
|
||||
}
|
||||
if (File.Exists(stream.fileInfo.FilePath + ".rrqm"))
|
||||
{
|
||||
File.Delete(stream.fileInfo.FilePath + ".rrqm");
|
||||
}
|
||||
}
|
||||
|
||||
internal static ProgressBlockCollection GetProgressBlockCollection(FileInfo fileInfo, bool breakpointResume)
|
||||
{
|
||||
ProgressBlockCollection blocks = new ProgressBlockCollection();
|
||||
blocks.FileInfo = new FileInfo();
|
||||
blocks.FileInfo.Copy(fileInfo);
|
||||
long position = 0;
|
||||
if (breakpointResume && fileInfo.FileLength >= 100)
|
||||
{
|
||||
long blockLength = (long)(fileInfo.FileLength / 100.0);
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
FileProgressBlock block = new FileProgressBlock();
|
||||
block.Index = i;
|
||||
block.FileHash = fileInfo.FileHash;
|
||||
block.Finished = false;
|
||||
block.StreamPosition = position;
|
||||
block.UnitLength = i != 99 ? blockLength : fileInfo.FileLength - i * blockLength;
|
||||
blocks.Add(block);
|
||||
position += blockLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FileProgressBlock block = new FileProgressBlock();
|
||||
block.Index = 0;
|
||||
block.FileHash = fileInfo.FileHash;
|
||||
block.Finished = false;
|
||||
block.StreamPosition = position;
|
||||
block.UnitLength = fileInfo.FileLength;
|
||||
blocks.Add(block);
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
internal static bool ReadFileBytes(string path, long beginPosition, ByteBlock byteBlock, int offset, int length)
|
||||
{
|
||||
FileStream fileStream = TransferFileStreamDic.GetFileStream(path);
|
||||
|
||||
fileStream.Position = beginPosition;
|
||||
|
||||
if (byteBlock.Buffer.Length < length + offset)
|
||||
{
|
||||
byteBlock.SetBuffer(new byte[length + offset]);
|
||||
}
|
||||
|
||||
int r = fileStream.Read(byteBlock.Buffer, offset, length);
|
||||
if (r == length)
|
||||
{
|
||||
byteBlock.Position = offset + length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
35
RRQMSocket.FileTransfer/Control/FileBlock.cs
Normal file
35
RRQMSocket.FileTransfer/Control/FileBlock.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 StreamPosition { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件哈希值
|
||||
/// </summary>
|
||||
public string FileHash { get; internal set; }
|
||||
}
|
||||
}
|
||||
58
RRQMSocket.FileTransfer/Control/FileInfo.cs
Normal file
58
RRQMSocket.FileTransfer/Control/FileInfo.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 FileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件大小
|
||||
/// </summary>
|
||||
public long FileLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件哈希值
|
||||
/// </summary>
|
||||
public string FileHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件标志
|
||||
/// </summary>
|
||||
public string Flag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 复制
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
public void Copy(FileInfo fileInfo)
|
||||
{
|
||||
this.Flag = fileInfo.Flag;
|
||||
this.FileHash = fileInfo.FileHash;
|
||||
this.FileLength = fileInfo.FileLength;
|
||||
this.FileName = fileInfo.FileName;
|
||||
this.FilePath = fileInfo.FilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.FileTransfer/Control/FileProgressBlock.cs
Normal file
30
RRQMSocket.FileTransfer/Control/FileProgressBlock.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 FileProgressBlock : FileBlock
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件块长度
|
||||
/// </summary>
|
||||
public long UnitLength { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 完成
|
||||
/// </summary>
|
||||
public bool Finished { get; internal set; }
|
||||
}
|
||||
}
|
||||
20
RRQMSocket.FileTransfer/Control/FileWaitResult.cs
Normal file
20
RRQMSocket.FileTransfer/Control/FileWaitResult.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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; }
|
||||
}
|
||||
}
|
||||
64
RRQMSocket.FileTransfer/Control/PBCollectionTemp.cs
Normal file
64
RRQMSocket.FileTransfer/Control/PBCollectionTemp.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 FileInfo FileInfo { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 块集合
|
||||
/// </summary>
|
||||
public List<FileProgressBlock> 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.FileInfo = progressBlocks.FileInfo;
|
||||
collectionTemp.Blocks = new List<FileProgressBlock>();
|
||||
collectionTemp.Blocks.AddRange(progressBlocks);
|
||||
return collectionTemp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换为ProgressBlockCollection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ProgressBlockCollection ToPBCollection()
|
||||
{
|
||||
ProgressBlockCollection progressBlocks = new ProgressBlockCollection();
|
||||
progressBlocks.FileInfo = this.FileInfo;
|
||||
if (this.Blocks != null)
|
||||
{
|
||||
progressBlocks.AddRange(this.Blocks);
|
||||
}
|
||||
return progressBlocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
RRQMSocket.FileTransfer/Control/ProgressBlockCollection.cs
Normal file
67
RRQMSocket.FileTransfer/Control/ProgressBlockCollection.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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<FileProgressBlock>
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息
|
||||
/// </summary>
|
||||
public FileInfo FileInfo { get; internal set; }
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
RRQMSocket.FileTransfer/Control/RRQMStream.cs
Normal file
24
RRQMSocket.FileTransfer/Control/RRQMStream.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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
|
||||
{
|
||||
internal class RRQMStream : FileStream
|
||||
{
|
||||
internal RRQMStream(string path, FileMode mode, FileAccess access) : base(path, mode, access)
|
||||
{
|
||||
}
|
||||
|
||||
internal FileInfo fileInfo;
|
||||
}
|
||||
}
|
||||
93
RRQMSocket.FileTransfer/Control/ReadOnlyList.cs
Normal file
93
RRQMSocket.FileTransfer/Control/ReadOnlyList.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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]; } }
|
||||
}
|
||||
}
|
||||
22
RRQMSocket.FileTransfer/Control/Speed.cs
Normal file
22
RRQMSocket.FileTransfer/Control/Speed.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
}
|
||||
}
|
||||
92
RRQMSocket.FileTransfer/Control/TransferCollection.cs
Normal file
92
RRQMSocket.FileTransfer/Control/TransferCollection.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
189
RRQMSocket.FileTransfer/Control/TransferFileHashDictionary.cs
Normal file
189
RRQMSocket.FileTransfer/Control/TransferFileHashDictionary.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Collections.Concurrent;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件Hash暂存字典
|
||||
/// </summary>
|
||||
public static class TransferFileHashDictionary
|
||||
{
|
||||
private static ConcurrentDictionary<string, FileInfo> filePathAndInfo = new ConcurrentDictionary<string, FileInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// 字典存储文件Hash的最大数量,默认为5000
|
||||
/// </summary>
|
||||
public static int MaxCount { get; set; } = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// 添加文件信息
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public static void AddFile(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
fileInfo.FilePath = filePath;
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(filePath);
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
}
|
||||
AddFile(fileInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加文件信息
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
public static void AddFile(FileInfo fileInfo)
|
||||
{
|
||||
if (fileInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
filePathAndInfo.AddOrUpdate(fileInfo.FilePath, fileInfo, (key, oldValue) =>
|
||||
{
|
||||
return fileInfo;
|
||||
});
|
||||
|
||||
if (filePathAndInfo.Count > MaxCount)
|
||||
{
|
||||
foreach (var item in filePathAndInfo.Keys)
|
||||
{
|
||||
FileInfo info;
|
||||
if (filePathAndInfo.TryRemove(item, out info))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除全部
|
||||
/// </summary>
|
||||
public static void ClearDictionary()
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
filePathAndInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Remove(string filePath)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return filePathAndInfo.TryRemove(filePath, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfo(string filePath, out FileInfo fileInfo, bool breakpointResume)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (filePathAndInfo.ContainsKey(filePath))
|
||||
{
|
||||
fileInfo = filePathAndInfo[filePath];
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
if (fileInfo.FileLength == stream.Length)
|
||||
{
|
||||
if (breakpointResume && fileInfo.FileHash == null)
|
||||
{
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
AddFile(fileInfo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过FileHash获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="fileHash"></param>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfoFromHash(string fileHash, out FileInfo fileInfo)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (fileHash == null)
|
||||
{
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var item in filePathAndInfo.Values)
|
||||
{
|
||||
if (item.FileHash == fileHash)
|
||||
{
|
||||
if (File.Exists(item.FilePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(item.FilePath))
|
||||
{
|
||||
if (item.FileLength == stream.Length)
|
||||
{
|
||||
fileInfo = item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
RRQMSocket.FileTransfer/Control/TransferFileStreamDic.cs
Normal file
38
RRQMSocket.FileTransfer/Control/TransferFileStreamDic.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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
|
||||
{
|
||||
internal static class TransferFileStreamDic
|
||||
{
|
||||
private static ConcurrentDictionary<string, FileStream> readOrWriteStreamDic = new ConcurrentDictionary<string, FileStream>();
|
||||
|
||||
internal static FileStream GetFileStream(string path)
|
||||
{
|
||||
return readOrWriteStreamDic.GetOrAdd(path, (v) =>
|
||||
{
|
||||
return File.OpenRead(path);
|
||||
});
|
||||
}
|
||||
|
||||
internal static void DisposeFileStream(string path)
|
||||
{
|
||||
FileStream stream;
|
||||
if (readOrWriteStreamDic.TryRemove(path, out stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
RRQMSocket.FileTransfer/Control/TransferSetting.cs
Normal file
36
RRQMSocket.FileTransfer/Control/TransferSetting.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
internal class TransferSetting
|
||||
{
|
||||
internal bool breakpointResume;
|
||||
internal int bufferLength;
|
||||
|
||||
internal void Serialize(ByteBlock byteBlock)
|
||||
{
|
||||
byteBlock.Write(Convert.ToByte(breakpointResume));
|
||||
byteBlock.Write(BitConverter.GetBytes(bufferLength));
|
||||
}
|
||||
|
||||
internal static TransferSetting Deserialize(byte[] buffer, int offset)
|
||||
{
|
||||
TransferSetting transferSetting = new TransferSetting();
|
||||
transferSetting.breakpointResume = BitConverter.ToBoolean(buffer, offset);
|
||||
transferSetting.bufferLength = BitConverter.ToInt32(buffer, offset + 1);
|
||||
return transferSetting;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
RRQMSocket.FileTransfer/Control/UrlFileInfo.cs
Normal file
118
RRQMSocket.FileTransfer/Control/UrlFileInfo.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息类
|
||||
/// </summary>
|
||||
public class UrlFileInfo : FileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public UrlFileInfo()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public UrlFileInfo(string path)
|
||||
{
|
||||
this.FilePath = path;
|
||||
this.FileName = Path.GetFileName(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成下载请求必要信息
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="restart"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo CreatDownload(string path, bool restart = false)
|
||||
{
|
||||
UrlFileInfo fileInfo = new UrlFileInfo();
|
||||
fileInfo.FilePath = path;
|
||||
fileInfo.Restart = restart;
|
||||
fileInfo.FileName = Path.GetFileName(path);
|
||||
fileInfo.TransferType = TransferType.Download;
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成上传请求必要信息
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="restart"></param>
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo CreatUpload(string path, bool restart = false, bool breakpointResume = false)
|
||||
{
|
||||
UrlFileInfo fileInfo = new UrlFileInfo();
|
||||
fileInfo.TransferType = TransferType.Upload;
|
||||
using (FileStream stream = File.OpenRead(path))
|
||||
{
|
||||
fileInfo.Restart = restart;
|
||||
fileInfo.FilePath = path;
|
||||
if (breakpointResume)
|
||||
{
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
}
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(path);
|
||||
}
|
||||
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新开始
|
||||
/// </summary>
|
||||
public bool Restart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 超时时间,默认30秒
|
||||
/// </summary>
|
||||
public int Timeout { get; set; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// 请求传输类型
|
||||
/// </summary>
|
||||
public TransferType TransferType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 比较
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public bool Equals(UrlFileInfo fileInfo)
|
||||
{
|
||||
if (this.FileHash == fileInfo.FileHash)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (this.FilePath == fileInfo.FilePath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
RRQMSocket.FileTransfer/Delegate/DelegateCollection.cs
Normal file
22
RRQMSocket.FileTransfer/Delegate/DelegateCollection.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
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);
|
||||
}
|
||||
44
RRQMSocket.FileTransfer/Enum/TransferStatus.cs
Normal file
44
RRQMSocket.FileTransfer/Enum/TransferStatus.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.FileTransfer/Enum/TransferType.cs
Normal file
30
RRQMSocket.FileTransfer/Enum/TransferType.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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,
|
||||
}
|
||||
}
|
||||
26
RRQMSocket.FileTransfer/EventArgs/FileEventArgs.cs
Normal file
26
RRQMSocket.FileTransfer/EventArgs/FileEventArgs.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Event;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件事件
|
||||
/// </summary>
|
||||
public class FileEventArgs : RRQMEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息
|
||||
/// </summary>
|
||||
public FileInfo FileInfo { get; internal set; }
|
||||
}
|
||||
}
|
||||
24
RRQMSocket.FileTransfer/EventArgs/FileOperationEventArgs.cs
Normal file
24
RRQMSocket.FileTransfer/EventArgs/FileOperationEventArgs.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 : FilePathEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否允许操作
|
||||
/// </summary>
|
||||
public bool IsPermitOperation { get; set; }
|
||||
}
|
||||
}
|
||||
25
RRQMSocket.FileTransfer/EventArgs/FilePathEventArgs.cs
Normal file
25
RRQMSocket.FileTransfer/EventArgs/FilePathEventArgs.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 FilePathEventArgs : TransferFileMessageArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置目标文件的最终路径,包含文件名及文件扩展名
|
||||
/// </summary>
|
||||
public string TargetPath { get; set; }
|
||||
}
|
||||
}
|
||||
34
RRQMSocket.FileTransfer/EventArgs/ReceiveFileArgs.cs
Normal file
34
RRQMSocket.FileTransfer/EventArgs/ReceiveFileArgs.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 TransferFileArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 已接收的流位置
|
||||
/// </summary>
|
||||
public long StreamPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收的文件信息(不要手动更改里面任何内容)
|
||||
/// </summary>
|
||||
public FileInfo FileInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件进度
|
||||
/// </summary>
|
||||
public float TransferProgressValue { get; set; }
|
||||
}
|
||||
}
|
||||
29
RRQMSocket.FileTransfer/EventArgs/TransferFileMessageArgs.cs
Normal file
29
RRQMSocket.FileTransfer/EventArgs/TransferFileMessageArgs.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 : FileEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 错误信息
|
||||
/// </summary>
|
||||
public string Message { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传输类型
|
||||
/// </summary>
|
||||
public TransferType TransferType { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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) { }
|
||||
}
|
||||
}
|
||||
45
RRQMSocket.FileTransfer/Interface/IFileClient.cs
Normal file
45
RRQMSocket.FileTransfer/Interface/IFileClient.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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>
|
||||
FileInfo TransferFileInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输进度
|
||||
/// </summary>
|
||||
float TransferProgress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输速度
|
||||
/// </summary>
|
||||
long TransferSpeed { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输状态
|
||||
/// </summary>
|
||||
TransferStatus TransferStatus { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输文件包
|
||||
/// </summary>
|
||||
ProgressBlockCollection FileBlocks { get; }
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.FileTransfer/Interface/IFileService.cs
Normal file
30
RRQMSocket.FileTransfer/Interface/IFileService.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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; }
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.FileTransfer/LICENSE
Normal file
201
RRQMSocket.FileTransfer/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
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.
|
||||
BIN
RRQMSocket.FileTransfer/RRQM.ico
Normal file
BIN
RRQMSocket.FileTransfer/RRQM.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.FileTransfer/RRQM.png
Normal file
BIN
RRQMSocket.FileTransfer/RRQM.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
72
RRQMSocket.FileTransfer/RRQMSocket.FileTransfer.csproj
Normal file
72
RRQMSocket.FileTransfer/RRQMSocket.FileTransfer.csproj
Normal file
@@ -0,0 +1,72 @@
|
||||
<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>1.0.2.0</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>介绍:RRQMSocket.FileTransfer是一个轻量级文件传输框架,您可以用它传输任意大小的文件,它可以完美支持断点续传、快速上传、传输限速等。在实时测试中,它的传输速率可达500Mb/s。
|
||||
|
||||
RRQMSocket.FileTransfer is a lightweight FileTransfer framework, you can use it to transfer files of any size, it can be perfect support breakpoint continuation, fast upload, transfer speed limit, etc.In real time tests, it was able to transmit at a rate of up to 500Mb/s.
|
||||
|
||||
API:https://gitee.com/dotnetchina/RRQMSocket/wikis/pages
|
||||
Demo:https://gitee.com/RRQM_OS/RRQMSocket.FileTransfer.Demo
|
||||
</Description>
|
||||
<PackageProjectUrl>https://gitee.com/RRQM_OS/RRQMSocket.FileTransfer</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" Version="4.0.15" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
1284
RRQMSocket.FileTransfer/Socket/FileClient.cs
Normal file
1284
RRQMSocket.FileTransfer/Socket/FileClient.cs
Normal file
File diff suppressed because it is too large
Load Diff
167
RRQMSocket.FileTransfer/Socket/FileService.cs
Normal file
167
RRQMSocket.FileTransfer/Socket/FileService.cs
Normal file
@@ -0,0 +1,167 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 FileService : TokenTcpService<FileSocketClient>, IFileService
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public FileService()
|
||||
{
|
||||
this.BufferLength = 1024 * 64;
|
||||
}
|
||||
|
||||
#region 属性
|
||||
|
||||
/// <summary>
|
||||
/// 获取下载速度
|
||||
/// </summary>
|
||||
public long DownloadSpeed
|
||||
{
|
||||
get
|
||||
{
|
||||
this.downloadSpeed = Speed.downloadSpeed;
|
||||
Speed.downloadSpeed = 0;
|
||||
return this.downloadSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取上传速度
|
||||
/// </summary>
|
||||
public long UploadSpeed
|
||||
{
|
||||
get
|
||||
{
|
||||
this.uploadSpeed = Speed.uploadSpeed;
|
||||
Speed.uploadSpeed = 0;
|
||||
return this.uploadSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持断点续传
|
||||
/// </summary>
|
||||
public bool BreakpointResume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大下载速度
|
||||
/// </summary>
|
||||
public long MaxDownloadSpeed { get; set; } = 1024 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// 最大上传速度
|
||||
/// </summary>
|
||||
public long MaxUploadSpeed { get; set; } = 1024 * 1024;
|
||||
|
||||
#endregion 属性
|
||||
|
||||
#region 字段
|
||||
|
||||
private long downloadSpeed;
|
||||
private long uploadSpeed;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
#region 事件
|
||||
|
||||
/// <summary>
|
||||
/// 当接收到系统信息的时候
|
||||
/// </summary>
|
||||
public event RRQMMessageEventHandler ReceiveSystemMes;
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件之前
|
||||
/// </summary>
|
||||
public event RRQMFileOperationEventHandler BeforeFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 当文件传输完成时
|
||||
/// </summary>
|
||||
public event RRQMTransferFileMessageEventHandler FinishedFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 收到字节数组并返回
|
||||
/// </summary>
|
||||
public event RRQMBytesEventHandler ReceivedBytesThenReturn;
|
||||
|
||||
/// <summary>
|
||||
/// 请求删除文件
|
||||
/// </summary>
|
||||
public event RRQMFileOperationEventHandler RequestDeleteFile;
|
||||
|
||||
/// <summary>
|
||||
/// 请求文件信息
|
||||
/// </summary>
|
||||
public event RRQMFileOperationEventHandler RequestFileInfo;
|
||||
|
||||
#endregion 事件
|
||||
|
||||
/// <summary>
|
||||
/// 创建完成FileSocketClient
|
||||
/// </summary>
|
||||
/// <param name="tcpSocketClient"></param>
|
||||
/// <param name="creatOption"></param>
|
||||
protected override void OnCreatSocketCliect(FileSocketClient tcpSocketClient, CreatOption creatOption)
|
||||
{
|
||||
tcpSocketClient.breakpointResume = this.BreakpointResume;
|
||||
tcpSocketClient.MaxDownloadSpeed = this.MaxDownloadSpeed;
|
||||
tcpSocketClient.MaxUploadSpeed = this.MaxUploadSpeed;
|
||||
if (creatOption.NewCreat)
|
||||
{
|
||||
tcpSocketClient.DataHandlingAdapter = new FixedHeaderDataHandlingAdapter();
|
||||
tcpSocketClient.BeforeFileTransfer = this.OnBeforeFileTransfer;
|
||||
tcpSocketClient.FinishedFileTransfer = this.OnFinishedFileTransfer;
|
||||
tcpSocketClient.ReceiveSystemMes = this.OnReceiveSystemMes;
|
||||
tcpSocketClient.ReceivedBytesThenReturn = this.OnReceivedBytesThenReturn;
|
||||
tcpSocketClient.RequestDeleteFile = this.OnRequestDeleteFile;
|
||||
tcpSocketClient.RequestFileInfo = this.OnRequestFileInfo;
|
||||
}
|
||||
tcpSocketClient.AgreementHelper = new RRQMAgreementHelper(tcpSocketClient);
|
||||
}
|
||||
|
||||
private void OnBeforeFileTransfer(object sender, FileOperationEventArgs e)
|
||||
{
|
||||
this.BeforeFileTransfer?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OnFinishedFileTransfer(object sender, TransferFileMessageArgs e)
|
||||
{
|
||||
this.FinishedFileTransfer?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OnReceiveSystemMes(object sender, MesEventArgs e)
|
||||
{
|
||||
this.ReceiveSystemMes?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OnReceivedBytesThenReturn(object sender, BytesEventArgs e)
|
||||
{
|
||||
this.ReceivedBytesThenReturn?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OnRequestDeleteFile(object sender, FileOperationEventArgs e)
|
||||
{
|
||||
this.RequestDeleteFile?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OnRequestFileInfo(object sender, FileOperationEventArgs e)
|
||||
{
|
||||
this.RequestFileInfo?.Invoke(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
893
RRQMSocket.FileTransfer/Socket/FileSocketClient.cs
Normal file
893
RRQMSocket.FileTransfer/Socket/FileSocketClient.cs
Normal file
@@ -0,0 +1,893 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.IO;
|
||||
using RRQMCore.Log;
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 已接收的客户端
|
||||
/// </summary>
|
||||
public sealed class FileSocketClient : TcpSocketClient, IFileService, IFileClient
|
||||
{
|
||||
#region 属性
|
||||
|
||||
private long maxDownloadSpeed = 1024 * 1024;
|
||||
|
||||
private long maxUploadSpeed = 1024 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输状态
|
||||
/// </summary>
|
||||
public TransferStatus TransferStatus { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输文件包
|
||||
/// </summary>
|
||||
public ProgressBlockCollection FileBlocks { get { return fileBlocks == null ? null : fileBlocks; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输文件信息
|
||||
/// </summary>
|
||||
public FileInfo TransferFileInfo { get { return fileBlocks == null ? null : fileBlocks.FileInfo; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输进度
|
||||
/// </summary>
|
||||
public float TransferProgress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fileBlocks == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (fileBlocks.FileInfo != null)
|
||||
{
|
||||
this.progress = fileBlocks.FileInfo.FileLength > 0 ? (float)position / fileBlocks.FileInfo.FileLength : 0;//计算下载完成进度
|
||||
}
|
||||
else
|
||||
{
|
||||
this.progress = 0;
|
||||
}
|
||||
return progress <= 1 ? progress : 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输速度
|
||||
/// </summary>
|
||||
public long TransferSpeed
|
||||
{
|
||||
get
|
||||
{
|
||||
this.speed = tempLength;
|
||||
tempLength = 0;
|
||||
return speed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每秒最大下载速度(Byte),不可小于1024
|
||||
/// </summary>
|
||||
public long MaxDownloadSpeed
|
||||
{
|
||||
get { return maxDownloadSpeed; }
|
||||
set
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
value = 1024;
|
||||
}
|
||||
maxDownloadSpeed = value;
|
||||
MaxSpeedChanged(maxDownloadSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每秒最大上传速度(Byte),不可小于1024
|
||||
/// </summary>
|
||||
public long MaxUploadSpeed
|
||||
{
|
||||
get { return maxUploadSpeed; }
|
||||
set
|
||||
{
|
||||
if (value < 1024)
|
||||
{
|
||||
value = 1024;
|
||||
}
|
||||
maxUploadSpeed = value;
|
||||
MaxSpeedChanged(maxUploadSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion 属性
|
||||
|
||||
#region 字段
|
||||
|
||||
internal RRQMAgreementHelper AgreementHelper;
|
||||
internal bool breakpointResume;
|
||||
private bool bufferLengthChanged;
|
||||
private long dataTransferLength;
|
||||
private long speed;
|
||||
private long tempLength;
|
||||
private float progress;
|
||||
private long position;
|
||||
private Stopwatch stopwatch = new Stopwatch();
|
||||
private long timeTick;
|
||||
private ProgressBlockCollection fileBlocks;
|
||||
private RRQMStream uploadFileStream;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
#region 事件
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件之前
|
||||
/// </summary>
|
||||
internal RRQMFileOperationEventHandler BeforeFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 当文件传输完成时
|
||||
/// </summary>
|
||||
internal RRQMTransferFileMessageEventHandler FinishedFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 当接收到系统信息的时候
|
||||
/// </summary>
|
||||
internal RRQMMessageEventHandler ReceiveSystemMes;
|
||||
|
||||
/// <summary>
|
||||
/// 收到字节数组并返回
|
||||
/// </summary>
|
||||
internal RRQMBytesEventHandler ReceivedBytesThenReturn;
|
||||
|
||||
/// <summary>
|
||||
/// 请求删除文件
|
||||
/// </summary>
|
||||
internal RRQMFileOperationEventHandler RequestDeleteFile;
|
||||
|
||||
/// <summary>
|
||||
/// 请求文件信息
|
||||
/// </summary>
|
||||
internal RRQMFileOperationEventHandler RequestFileInfo;
|
||||
|
||||
#endregion 事件
|
||||
|
||||
private void MaxSpeedChanged(long speed)
|
||||
{
|
||||
if (speed < 1024 * 1024)
|
||||
{
|
||||
this.BufferLength = 1024 * 10;
|
||||
}
|
||||
else if (speed < 1024 * 1024 * 10)
|
||||
{
|
||||
this.BufferLength = 1024 * 64;
|
||||
}
|
||||
else if (speed < 1024 * 1024 * 50)
|
||||
{
|
||||
this.BufferLength = 1024 * 512;
|
||||
}
|
||||
else if (speed < 1024 * 1024 * 100)
|
||||
{
|
||||
this.BufferLength = 1024 * 1024;
|
||||
}
|
||||
else if (speed < 1024 * 1024 * 200)
|
||||
{
|
||||
this.BufferLength = 1024 * 1024 * 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.BufferLength = 1024 * 1024 * 10;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region 协议函数
|
||||
|
||||
private void RequestDownload(ByteBlock byteBlock, UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.FileInfo = urlFileInfo;
|
||||
args.IsPermitOperation = true;
|
||||
args.TargetPath = args.FileInfo.FilePath;
|
||||
args.TransferType = TransferType.Download;
|
||||
this.BeforeFileTransfer?.Invoke(this, args);
|
||||
|
||||
string filePath = args.TargetPath;
|
||||
FileWaitResult waitResult = new FileWaitResult();
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
waitResult.Message = string.Format("服务器拒绝下载--文件:“{0}”", filePath);
|
||||
waitResult.Status = 2;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
}
|
||||
else if (!File.Exists(urlFileInfo.FilePath))
|
||||
{
|
||||
waitResult.Message = string.Format("文件:“{0}”不存在", filePath);
|
||||
waitResult.Status = 2;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.TransferStatus = TransferStatus.Download;
|
||||
waitResult.Message = null;
|
||||
waitResult.Status = 1;
|
||||
FileInfo fileInfo;
|
||||
|
||||
if (!TransferFileHashDictionary.GetFileInfo(filePath, out fileInfo, breakpointResume))
|
||||
{
|
||||
fileInfo = new FileInfo();
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
fileInfo.FilePath = filePath;
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(filePath);
|
||||
if (this.breakpointResume)
|
||||
{
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
}
|
||||
TransferFileHashDictionary.AddFile(fileInfo);
|
||||
}
|
||||
}
|
||||
urlFileInfo.Copy(fileInfo);
|
||||
fileBlocks = FileBaseTool.GetProgressBlockCollection(urlFileInfo, this.breakpointResume);
|
||||
waitResult.PBCollectionTemp = PBCollectionTemp.GetFromProgressBlockCollection(fileBlocks);
|
||||
}
|
||||
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(waitResult, true));
|
||||
}
|
||||
|
||||
private void RequestUpload(ByteBlock byteBlock, PBCollectionTemp requestBlocks, bool restart)
|
||||
{
|
||||
FileWaitResult waitResult = new FileWaitResult();
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.FileInfo = requestBlocks.FileInfo;
|
||||
args.TargetPath = requestBlocks.FileInfo.FileName;
|
||||
args.IsPermitOperation = true;
|
||||
this.BeforeFileTransfer?.Invoke(this, args);//触发 接收文件事件
|
||||
requestBlocks.FileInfo.FilePath = args.TargetPath;
|
||||
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = "服务器拒绝下载";
|
||||
}
|
||||
else if (FileControler.FileIsOpen(requestBlocks.FileInfo.FilePath))
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = "该文件已被打开,或许正在由其他客户端上传";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.TransferStatus = TransferStatus.Upload;
|
||||
|
||||
restart = this.breakpointResume ? restart : true;
|
||||
if (!restart)
|
||||
{
|
||||
FileInfo fileInfo;
|
||||
if (TransferFileHashDictionary.GetFileInfoFromHash(requestBlocks.FileInfo.FileHash, out fileInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (fileInfo.FilePath != requestBlocks.FileInfo.FilePath)
|
||||
{
|
||||
File.Copy(fileInfo.FilePath, requestBlocks.FileInfo.FilePath);
|
||||
}
|
||||
this.fileBlocks = FileBaseTool.GetProgressBlockCollection(fileInfo, this.breakpointResume);
|
||||
foreach (var item in this.fileBlocks)
|
||||
{
|
||||
item.Finished = true;
|
||||
}
|
||||
waitResult.Status = 3;
|
||||
waitResult.Message = null;
|
||||
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(waitResult, true));
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
ProgressBlockCollection blocks = requestBlocks.ToPBCollection();
|
||||
uploadFileStream = FileBaseTool.GetNewFileStream(ref blocks, restart);
|
||||
blocks.FileInfo.FilePath = requestBlocks.FileInfo.FilePath;
|
||||
this.fileBlocks = blocks;
|
||||
waitResult.Status = 1;
|
||||
waitResult.Message = null;
|
||||
waitResult.PBCollectionTemp = PBCollectionTemp.GetFromProgressBlockCollection(blocks);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = ex.Message;
|
||||
waitResult.PBCollectionTemp = null;
|
||||
}
|
||||
}
|
||||
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(waitResult, true));
|
||||
}
|
||||
|
||||
private void DownloadBlockData(ByteBlock byteBlock, byte[] buffer)
|
||||
{
|
||||
if (this.TransferStatus != TransferStatus.Download)
|
||||
{
|
||||
byteBlock.Write(0);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
long position = BitConverter.ToInt64(buffer, 4);
|
||||
long requestLength = BitConverter.ToInt64(buffer, 12);
|
||||
if (FileBaseTool.ReadFileBytes(fileBlocks.FileInfo.FilePath, position, byteBlock, 1, (int)requestLength))
|
||||
{
|
||||
Speed.downloadSpeed += requestLength;
|
||||
this.position = position + requestLength;
|
||||
this.tempLength += requestLength;
|
||||
this.dataTransferLength += requestLength;
|
||||
if (this.bufferLengthChanged)
|
||||
{
|
||||
byteBlock.Buffer[0] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Buffer[0] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Buffer[0] = 2;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadFinished(ByteBlock byteBlock)
|
||||
{
|
||||
TransferFileStreamDic.DisposeFileStream(this.fileBlocks.FileInfo.FilePath);
|
||||
byteBlock.Write(1);
|
||||
FilePathEventArgs args = new FilePathEventArgs();
|
||||
args.FileInfo = this.fileBlocks.FileInfo;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
args.TransferType = TransferType.Download;
|
||||
args.TargetPath = args.FileInfo.FilePath;
|
||||
this.FinishedFileTransfer?.Invoke(this, args);
|
||||
this.fileBlocks = null;
|
||||
}
|
||||
|
||||
private void UploadBlockData(ByteBlock byteBlock, ByteBlock receivedbyteBlock)
|
||||
{
|
||||
if (this.TransferStatus != TransferStatus.Upload)
|
||||
{
|
||||
byteBlock.Write(4);
|
||||
return;
|
||||
}
|
||||
byte status = receivedbyteBlock.Buffer[4];
|
||||
int index = BitConverter.ToInt32(receivedbyteBlock.Buffer, 5);
|
||||
long position = BitConverter.ToInt64(receivedbyteBlock.Buffer, 9);
|
||||
long submitLength = BitConverter.ToInt64(receivedbyteBlock.Buffer, 17);
|
||||
|
||||
string mes;
|
||||
if (FileBaseTool.WriteFile(this.uploadFileStream, out mes, position, receivedbyteBlock.Buffer, 25, (int)submitLength))
|
||||
{
|
||||
this.position = position + submitLength;
|
||||
this.tempLength += submitLength;
|
||||
this.dataTransferLength += submitLength;
|
||||
Speed.uploadSpeed += submitLength;
|
||||
|
||||
if (this.bufferLengthChanged)
|
||||
{
|
||||
byteBlock.Write(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write(1);
|
||||
}
|
||||
|
||||
if (status == 1)
|
||||
{
|
||||
FileProgressBlock fileProgress = this.fileBlocks.FirstOrDefault(a => a.Index == index);
|
||||
fileProgress.Finished = true;
|
||||
FileBaseTool.SaveProgressBlockCollection(this.uploadFileStream, this.fileBlocks);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write(2);
|
||||
Logger.Debug(LogType.Error, this, "上传文件写入错误:" + mes);
|
||||
}
|
||||
}
|
||||
|
||||
private void UploadFinished(ByteBlock byteBlock)
|
||||
{
|
||||
TransferFileHashDictionary.AddFile(this.TransferFileInfo);
|
||||
if (this.uploadFileStream != null)
|
||||
{
|
||||
FileBaseTool.FileFinished(this.uploadFileStream);
|
||||
this.uploadFileStream = null;
|
||||
}
|
||||
if (this.fileBlocks != null)
|
||||
{
|
||||
TransferFileHashDictionary.AddFile(this.fileBlocks.FileInfo);
|
||||
FilePathEventArgs args = new FilePathEventArgs();
|
||||
args.FileInfo = this.fileBlocks.FileInfo;
|
||||
args.TargetPath = args.FileInfo.FilePath;
|
||||
args.TransferType = TransferType.Upload;
|
||||
this.FinishedFileTransfer?.Invoke(this, args);
|
||||
|
||||
this.fileBlocks = null;
|
||||
}
|
||||
|
||||
byteBlock.Write(1);
|
||||
}
|
||||
|
||||
private void StopUpload(ByteBlock byteBlock)
|
||||
{
|
||||
FileBaseTool.SaveProgressBlockCollection(this.uploadFileStream, this.fileBlocks);
|
||||
this.uploadFileStream.Close();
|
||||
this.uploadFileStream.Dispose();
|
||||
this.uploadFileStream = null;
|
||||
byteBlock.Write(1);
|
||||
}
|
||||
|
||||
private void ReturnBytes(ByteBlock byteBlock, ByteBlock receivedByteBlock, int length)
|
||||
{
|
||||
BytesEventArgs args = new BytesEventArgs();
|
||||
byte[] buffer = new byte[length];
|
||||
byteBlock.Position = 4;
|
||||
receivedByteBlock.Read(buffer, 0, buffer.Length);
|
||||
args.ReceivedDataBytes = buffer;
|
||||
ReceivedBytesThenReturn?.Invoke(this, args);
|
||||
byteBlock.Write(1);
|
||||
if (args.ReturnDataBytes != null)
|
||||
{
|
||||
byteBlock.Write(args.ReturnDataBytes);
|
||||
}
|
||||
}
|
||||
|
||||
private void RDeleteFile(ByteBlock byteBlock, UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.FileInfo = new FileInfo();
|
||||
args.FileInfo.Copy(urlFileInfo);
|
||||
args.TargetPath = urlFileInfo.FilePath;
|
||||
this.RequestDeleteFile?.Invoke(this, args);
|
||||
|
||||
string filePath = args.TargetPath;
|
||||
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
byteBlock.Write(3);
|
||||
}
|
||||
else if (!File.Exists(filePath))
|
||||
{
|
||||
byteBlock.Write(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(filePath);
|
||||
byteBlock.Write(1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
byteBlock.Write(4);
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RFileInfo(ByteBlock byteBlock, UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.FileInfo = new FileInfo();
|
||||
args.FileInfo.Copy(urlFileInfo);
|
||||
args.TargetPath = args.FileInfo.FilePath;
|
||||
this.RequestFileInfo?.Invoke(this, args);
|
||||
string filePath = args.TargetPath;
|
||||
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
byteBlock.Write(3);
|
||||
}
|
||||
else if (!File.Exists(filePath))
|
||||
{
|
||||
byteBlock.Write(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
using (Stream stream = File.Open(filePath, FileMode.Open))
|
||||
{
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(filePath);
|
||||
fileInfo.FilePath = filePath;
|
||||
}
|
||||
byteBlock.Write(1);
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(fileInfo, true));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
byteBlock.Write(4);
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SystemMessage(string mes)
|
||||
{
|
||||
ReceiveSystemMes?.Invoke(this, new MesEventArgs(mes));
|
||||
}
|
||||
|
||||
#endregion 协议函数
|
||||
|
||||
/// <summary>
|
||||
/// 当BufferLength改变值的时候
|
||||
/// </summary>
|
||||
protected override void OnBufferLengthChanged()
|
||||
{
|
||||
bufferLengthChanged = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间帧
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private long GetNowTick()
|
||||
{
|
||||
long tick = (long)(DateTime.Now.Ticks / 10000000.0);
|
||||
return tick;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节流
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <exception cref="RRQMNotConnectedException"></exception>
|
||||
/// <exception cref="RRQMOverlengthException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public override void Send(byte[] buffer, int offset, int length)
|
||||
{
|
||||
throw new RRQMException("不允许发送自由数据");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息
|
||||
/// </summary>
|
||||
/// <param name="mes"></param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void SendSystemMes(string mes)
|
||||
{
|
||||
if (mes == null || mes == string.Empty)
|
||||
{
|
||||
throw new RRQMException("消息不可为空");
|
||||
}
|
||||
byte[] datas = Encoding.UTF8.GetBytes(mes);
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(datas.Length + 12);
|
||||
try
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(1000));
|
||||
byteBlock.Write(BitConverter.GetBytes(1000));
|
||||
byteBlock.Write(BitConverter.GetBytes(1000));
|
||||
byteBlock.Write(datas);
|
||||
AgreementHelper.SocketSend(1000, byteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RRQMException(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理已接收到的数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="obj"></param>
|
||||
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
|
||||
{
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
int r = (int)byteBlock.Position;
|
||||
int agreement = BitConverter.ToInt32(buffer, 0);
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
switch (agreement)
|
||||
{
|
||||
case 1000:
|
||||
{
|
||||
try
|
||||
{
|
||||
string mes = Encoding.UTF8.GetString(byteBlock.Buffer, 4, r - 4);
|
||||
SystemMessage(mes);
|
||||
returnByteBlock.Write(1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1001:
|
||||
{
|
||||
try
|
||||
{
|
||||
UrlFileInfo fileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(buffer, 4);
|
||||
RequestDownload(returnByteBlock, fileInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1002:
|
||||
{
|
||||
try
|
||||
{
|
||||
DownloadBlockData(returnByteBlock, buffer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1003://停止下载
|
||||
{
|
||||
try
|
||||
{
|
||||
this.fileBlocks = null;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
returnByteBlock.Write(1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1004:
|
||||
{
|
||||
try
|
||||
{
|
||||
DownloadFinished(returnByteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1010:
|
||||
{
|
||||
try
|
||||
{
|
||||
bool restart = BitConverter.ToBoolean(byteBlock.Buffer, 4);
|
||||
PBCollectionTemp blocks = SerializeConvert.RRQMBinaryDeserialize<PBCollectionTemp>(byteBlock.Buffer, 5);
|
||||
RequestUpload(returnByteBlock, blocks, restart);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1011:
|
||||
{
|
||||
try
|
||||
{
|
||||
UploadBlockData(returnByteBlock, byteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1012:
|
||||
{
|
||||
try
|
||||
{
|
||||
UploadFinished(returnByteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1013:
|
||||
{
|
||||
try
|
||||
{
|
||||
StopUpload(returnByteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1014:
|
||||
{
|
||||
try
|
||||
{
|
||||
ReturnBytes(returnByteBlock, byteBlock, r - 4);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1020:
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.TransferStatus == TransferStatus.Download)
|
||||
{
|
||||
this.MaxSpeedChanged(this.maxDownloadSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.MaxSpeedChanged(this.maxUploadSpeed);
|
||||
}
|
||||
TransferSetting transferSetting = new TransferSetting();
|
||||
transferSetting.breakpointResume = this.breakpointResume;
|
||||
transferSetting.bufferLength = this.BufferLength;
|
||||
transferSetting.Serialize(returnByteBlock);
|
||||
this.bufferLengthChanged = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1021:
|
||||
{
|
||||
try
|
||||
{
|
||||
UrlFileInfo urlFileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(byteBlock.Buffer, 4);
|
||||
this.RDeleteFile(returnByteBlock, urlFileInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1022:
|
||||
{
|
||||
try
|
||||
{
|
||||
UrlFileInfo fileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(byteBlock.Buffer, 4);
|
||||
this.RFileInfo(returnByteBlock, fileInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.AgreementHelper.SocketSend(returnByteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public override void Recreate()
|
||||
{
|
||||
base.Recreate();
|
||||
this.maxDownloadSpeed = 1024 * 1024;
|
||||
this.maxUploadSpeed = 1024 * 1024;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
if (uploadFileStream != null)
|
||||
{
|
||||
uploadFileStream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
RRQMSocket.Http/Control/BaseHeader.cs
Normal file
143
RRQMSocket.Http/Control/BaseHeader.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Http基础头部
|
||||
/// </summary>
|
||||
public class BaseHeader : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器版本
|
||||
/// </summary>
|
||||
public static readonly string ServerVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
|
||||
/// <summary>
|
||||
/// 请求体流数据
|
||||
/// </summary>
|
||||
public ByteBlock Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求体字符数据
|
||||
/// </summary>
|
||||
public string BodyString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编码方式
|
||||
/// </summary>
|
||||
public Encoding Encoding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容类型
|
||||
/// </summary>
|
||||
public string Content_Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容长度
|
||||
/// </summary>
|
||||
public int Content_Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容编码
|
||||
/// </summary>
|
||||
public string Content_Encoding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容语言
|
||||
/// </summary>
|
||||
public string ContentLanguage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求头集合
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Headers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP协议版本
|
||||
/// </summary>
|
||||
public string ProtocolVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 协议名称
|
||||
/// </summary>
|
||||
public string Protocols { get; set; }
|
||||
|
||||
/// <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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放所占资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.Body != null)
|
||||
{
|
||||
this.Body.Dispose();
|
||||
this.Body = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
219
RRQMSocket.Http/Control/HttpRequest.cs
Normal file
219
RRQMSocket.Http/Control/HttpRequest.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using RRQMCore.Helper;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// HTTP请求定义
|
||||
/// </summary>
|
||||
public class HttpRequest : BaseHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// url参数
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Query { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表单参数
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Forms { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// request 参数
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Parmas { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// URL参数
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Params { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP请求方式
|
||||
/// </summary>
|
||||
public string Method { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// HTTP(S)地址
|
||||
/// </summary>
|
||||
public string URL { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取时候保持连接
|
||||
/// </summary>
|
||||
public bool KeepAlive { get; private set; }
|
||||
|
||||
/// <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
|
||||
var first = Regex.Split(rows[0], @"(\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]);
|
||||
if (first.Length > 2)
|
||||
{
|
||||
string[] ps = first[2].Split('/');
|
||||
if (ps.Length == 2)
|
||||
{
|
||||
this.Protocols = ps[0];
|
||||
this.ProtocolVersion = ps[1];
|
||||
}
|
||||
}
|
||||
|
||||
//Request Headers
|
||||
this.Headers = GetRequestHeaders(rows);
|
||||
|
||||
string contentLength = this.GetHeader(RequestHeaders.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(RequestHeaders.Connection) == "keep-alive")
|
||||
{
|
||||
this.KeepAlive = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.KeepAlive = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.KeepAlive = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取头值
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
public string GetHeader(RequestHeaders header)
|
||||
{
|
||||
return GetHeaderByKey(header);
|
||||
}
|
||||
|
||||
/// <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(RequestHeaders 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>
|
||||
public void Build()
|
||||
{
|
||||
this.BodyString = this.Body == null ? null : Encoding.UTF8.GetString(this.Body.Buffer, 0, (int)this.Body.Length);
|
||||
if (this.Method == "POST")
|
||||
{
|
||||
var contentType = GetHeader(RequestHeaders.ContentType);
|
||||
var isUrlencoded = contentType == @"application/x-www-form-urlencoded";
|
||||
|
||||
if (isUrlencoded) this.Params = GetRequestParameters(this.BodyString);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetRequestHeaders(IEnumerable<string> rows)
|
||||
{
|
||||
if (rows == null || rows.Count() <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Dictionary<string, string> header = new Dictionary<string, string>();
|
||||
foreach (var item in rows)
|
||||
{
|
||||
string[] kv = item.SplitFirst(':');
|
||||
if (kv.Length == 2)
|
||||
{
|
||||
header.Add(kv[0], kv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 传递标识
|
||||
/// </summary>
|
||||
public object Flag { get; set; }
|
||||
}
|
||||
}
|
||||
152
RRQMSocket.Http/Control/HttpResponse.cs
Normal file
152
RRQMSocket.Http/Control/HttpResponse.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Text;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Http响应
|
||||
/// </summary>
|
||||
public class HttpResponse : BaseHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public HttpResponse()
|
||||
{
|
||||
this.Headers = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 状态码
|
||||
/// </summary>
|
||||
public string StatusCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 内容
|
||||
/// </summary>
|
||||
public byte[] Content { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置内容
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="encoding"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse SetContent(byte[] content, Encoding encoding = null)
|
||||
{
|
||||
this.Content = content;
|
||||
this.Encoding = encoding != null ? encoding : Encoding.UTF8;
|
||||
this.Content_Length = content.Length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置内容
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="encoding"></param>
|
||||
/// <returns></returns>
|
||||
public HttpResponse SetContent(string content, Encoding encoding = null)
|
||||
{
|
||||
//初始化内容
|
||||
encoding = encoding != null ? encoding : Encoding.UTF8;
|
||||
return SetContent(encoding.GetBytes(content), encoding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取头数据
|
||||
/// </summary>
|
||||
/// <param name="header"></param>
|
||||
/// <returns></returns>
|
||||
public string GetHeader(ResponseHeader header)
|
||||
{
|
||||
return GetHeaderByKey(header);
|
||||
}
|
||||
|
||||
/// <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(ResponseHeader 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/1.1 {StatusCode}");
|
||||
if (!string.IsNullOrEmpty(this.Content_Type))
|
||||
stringBuilder.AppendLine("Content-Type: " + this.Content_Type);
|
||||
if (this.Content_Length > 0)
|
||||
stringBuilder.AppendLine("Content-Length: " + this.Content_Length);
|
||||
foreach (var headerkey in this.Headers.Keys)
|
||||
{
|
||||
stringBuilder.Append($"{headerkey}: ");
|
||||
stringBuilder.AppendLine(this.Headers[headerkey]);
|
||||
}
|
||||
stringBuilder.AppendLine($"Server: RRQMSocket.Http {ServerVersion}");
|
||||
stringBuilder.AppendLine("Date: " + DateTime.Now.ToGMTString("r"));
|
||||
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 void Build(ByteBlock byteBlock)
|
||||
{
|
||||
BuildHeader(byteBlock);
|
||||
BuildContent(byteBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
134
RRQMSocket.Http/DataAdapter/HttpDataHandlingAdapter.cs
Normal file
134
RRQMSocket.Http/DataAdapter/HttpDataHandlingAdapter.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 System.Text;
|
||||
|
||||
namespace RRQMSocket.Http
|
||||
{
|
||||
/// <summary>
|
||||
/// Http数据处理适配器
|
||||
/// </summary>
|
||||
public class HttpDataHandlingAdapter : DataHandlingAdapter
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="maxSize"></param>
|
||||
public HttpDataHandlingAdapter(int maxSize)
|
||||
{
|
||||
this.MaxSize = maxSize;
|
||||
this.terminatorCode = Encoding.UTF8.GetBytes("\r\n\r\n");
|
||||
}
|
||||
|
||||
private byte[] terminatorCode;
|
||||
|
||||
/// <summary>
|
||||
/// 允许的最大长度
|
||||
/// </summary>
|
||||
public int MaxSize { get; private set; }
|
||||
|
||||
private ByteBlock tempByteBlock;
|
||||
|
||||
private HttpRequest httpRequest;
|
||||
|
||||
/// <summary>
|
||||
/// 预处理
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
protected override void PreviewReceived(ByteBlock byteBlock)
|
||||
{
|
||||
string s = Encoding.UTF8.GetString(byteBlock.Buffer, 0, (int)byteBlock.Length);
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
int r = (int)byteBlock.Position;
|
||||
if (this.tempByteBlock != null)
|
||||
{
|
||||
this.tempByteBlock.Write(buffer, 0, r);
|
||||
buffer = this.tempByteBlock.Buffer;
|
||||
r = (int)this.tempByteBlock.Position;
|
||||
}
|
||||
|
||||
if (this.httpRequest == null)
|
||||
{
|
||||
int index = buffer.IndexOfFirst(0, r, this.terminatorCode);
|
||||
if (index > 0)
|
||||
{
|
||||
this.httpRequest = new HttpRequest();
|
||||
this.httpRequest.ReadHeaders(buffer, 0, r);
|
||||
|
||||
if (this.httpRequest.Content_Length > 0)
|
||||
{
|
||||
this.httpRequest.Body = this.BytePool.GetByteBlock(this.httpRequest.Content_Length);
|
||||
this.httpRequest.Body.Write(buffer, index + 1, r - (index + 1));
|
||||
if (this.httpRequest.Body.Length == this.httpRequest.Content_Length)
|
||||
{
|
||||
this.PreviewHandle(this.httpRequest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PreviewHandle(this.httpRequest);
|
||||
}
|
||||
}
|
||||
else if (r > 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(r * 2);
|
||||
this.tempByteBlock.Write(buffer, 0, r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r >= this.httpRequest.Content_Length - this.httpRequest.Body.Length)
|
||||
{
|
||||
this.httpRequest.Body.Write(buffer, 0, this.httpRequest.Content_Length - (int)this.httpRequest.Body.Length);
|
||||
this.PreviewHandle(this.httpRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void PreviewHandle(HttpRequest httpRequest)
|
||||
{
|
||||
this.httpRequest = null;
|
||||
try
|
||||
{
|
||||
httpRequest.Build();
|
||||
this.GoReceived(null, httpRequest);
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpRequest.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预处理
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
protected override void PreviewSend(byte[] buffer, int offset, int length)
|
||||
{
|
||||
this.GoSend(buffer, offset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
267
RRQMSocket.Http/Enum/RequestHeaders.cs
Normal file
267
RRQMSocket.Http/Enum/RequestHeaders.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 RequestHeaders
|
||||
{
|
||||
/// <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,
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.Http/Enum/ResponseHeader.cs
Normal file
201
RRQMSocket.Http/Enum/ResponseHeader.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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 ResponseHeader
|
||||
{
|
||||
/// <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 标头,指定指示的标头字段在消息(使用分块传输编码方法进行编码)的尾部显示。
|
||||
/// </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>
|
||||
/// Range 标头,指定客户端请求返回的响应的单个或多个子范围来代替整个响应。
|
||||
/// </summary>
|
||||
[Description("Range")]
|
||||
ContentRange = 17,
|
||||
|
||||
/// <summary>
|
||||
/// Expires 标头,指定日期和时间,在此之后伴随的正文数据应视为陈旧的。
|
||||
/// </summary>
|
||||
[Description("Expires")]
|
||||
Expires = 18,
|
||||
|
||||
/// <summary>
|
||||
/// Last-Modified 标头,指定上次修改伴随的正文数据的日期和时间。
|
||||
/// </summary>
|
||||
[Description("Last-Modified")]
|
||||
LastModified = 19,
|
||||
|
||||
/// <summary>
|
||||
/// Accept-Ranges 标头,指定服务器接受的范围。
|
||||
/// </summary>
|
||||
[Description("Accept-Ranges")]
|
||||
AcceptRanges = 20,
|
||||
|
||||
/// <summary>
|
||||
/// Age 标头,指定自起始服务器生成响应以来的时间长度(以秒为单位)。
|
||||
/// </summary>
|
||||
[Description("Age")]
|
||||
Age = 21,
|
||||
|
||||
/// <summary>
|
||||
/// Etag 标头,指定请求的变量的当前值。
|
||||
/// </summary>
|
||||
[Description("Etag")]
|
||||
ETag = 22,
|
||||
|
||||
/// <summary>
|
||||
/// Location 标头,指定为获取请求的资源而将客户端重定向到的 URI。
|
||||
/// </summary>
|
||||
[Description("Location")]
|
||||
Location = 23,
|
||||
|
||||
/// <summary>
|
||||
/// Proxy-Authenticate 标头,指定客户端必须对代理验证其自身。
|
||||
/// </summary>
|
||||
[Description("Proxy-Authenticate")]
|
||||
ProxyAuthenticate = 24,
|
||||
|
||||
/// <summary>
|
||||
/// Retry-After 标头,指定某个时间(以秒为单位)或日期和时间,在此时间之后客户端可以重试其请求。
|
||||
/// </summary>
|
||||
[Description("Retry-After")]
|
||||
RetryAfter = 25,
|
||||
|
||||
/// <summary>
|
||||
/// Server 标头,指定关于起始服务器代理的信息。
|
||||
/// </summary>
|
||||
[Description("Server")]
|
||||
Server = 26,
|
||||
|
||||
/// <summary>
|
||||
/// Set-Cookie 标头,指定提供给客户端的 Cookie 数据。
|
||||
/// </summary>
|
||||
[Description("Set-Cookie")]
|
||||
SetCookie = 27,
|
||||
|
||||
/// <summary>
|
||||
/// Vary 标头,指定用于确定缓存的响应是否为新响应的请求标头。
|
||||
/// </summary>
|
||||
[Description("Vary")]
|
||||
Vary = 28,
|
||||
|
||||
/// <summary>
|
||||
/// WWW-Authenticate 标头,指定客户端必须对服务器验证其自身。
|
||||
/// </summary>
|
||||
[Description("WWW-Authenticate")]
|
||||
WwwAuthenticate = 29,
|
||||
}
|
||||
}
|
||||
72
RRQMSocket.Http/Helper/EnumHelper.cs
Normal file
72
RRQMSocket.Http/Helper/EnumHelper.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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);
|
||||
}
|
||||
}
|
||||
}
|
||||
85
RRQMSocket.Http/Helper/ResponseHelper.cs
Normal file
85
RRQMSocket.Http/Helper/ResponseHelper.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.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);
|
||||
response.StatusCode = "200";
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Xml格式
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="xmlText"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponse FromXML(this HttpResponse response, string xmlText)
|
||||
{
|
||||
response.SetContent(xmlText);
|
||||
response.Content_Type = "text/xml";
|
||||
response.StatusCode = "200";
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Json
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="jsonText"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponse FromJson(this HttpResponse response, string jsonText)
|
||||
{
|
||||
response.SetContent(jsonText);
|
||||
response.Content_Type = "text/json";
|
||||
response.StatusCode = "200";
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从文本
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
/// <param name="text"></param>
|
||||
/// <returns></returns>
|
||||
public static HttpResponse FromText(this HttpResponse response, string text)
|
||||
{
|
||||
response.SetContent(text);
|
||||
response.Content_Type = "text/plain";
|
||||
response.StatusCode = "200";
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.Http/LICENSE
Normal file
201
RRQMSocket.Http/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
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.
|
||||
BIN
RRQMSocket.Http/RRQM.ico
Normal file
BIN
RRQMSocket.Http/RRQM.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.Http/RRQM.png
Normal file
BIN
RRQMSocket.Http/RRQM.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
65
RRQMSocket.Http/RRQMSocket.Http.csproj
Normal file
65
RRQMSocket.Http/RRQMSocket.Http.csproj
Normal file
@@ -0,0 +1,65 @@
|
||||
<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>1.0.1</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>介绍:这是一个能够简单解析HTTP的扩展库,能够为RRQMSocket扩展解析HTTP的能力。
|
||||
|
||||
API:https://gitee.com/dotnetchina/RRQMSocket/wikis/pages </Description>
|
||||
<PackageProjectUrl>https://gitee.com/RRQM_OS/RRQMSocket.Http</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="4.0.15" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
27
RRQMSocket.RPC/Global/Attribute/RPCMethodAttribute.cs
Normal file
27
RRQMSocket.RPC/Global/Attribute/RPCMethodAttribute.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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>
|
||||
[AttributeUsage(AttributeTargets.Method,AllowMultiple = true,Inherited =true)]
|
||||
public abstract class RPCMethodAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否异步执行
|
||||
/// </summary>
|
||||
public bool Async { get; set; }
|
||||
}
|
||||
}
|
||||
60
RRQMSocket.RPC/Global/Control/InvokeStatus.cs
Normal file
60
RRQMSocket.RPC/Global/Control/InvokeStatus.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 调用状态
|
||||
/// </summary>
|
||||
public enum InvokeStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 就绪
|
||||
/// </summary>
|
||||
Ready,
|
||||
|
||||
/// <summary>
|
||||
/// 未找到服务
|
||||
/// </summary>
|
||||
UnFound,
|
||||
|
||||
/// <summary>
|
||||
/// 不可用
|
||||
/// </summary>
|
||||
UnEnable,
|
||||
|
||||
/// <summary>
|
||||
/// 成功调用
|
||||
/// </summary>
|
||||
Success,
|
||||
|
||||
/// <summary>
|
||||
/// 终止执行
|
||||
/// </summary>
|
||||
Abort,
|
||||
|
||||
/// <summary>
|
||||
/// 调用内部异常
|
||||
/// </summary>
|
||||
InvocationException,
|
||||
|
||||
/// <summary>
|
||||
/// 其他异常
|
||||
/// </summary>
|
||||
Exception
|
||||
}
|
||||
}
|
||||
72
RRQMSocket.RPC/Global/Control/MethodInstance.cs
Normal file
72
RRQMSocket.RPC/Global/Control/MethodInstance.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Reflection;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC函数实例
|
||||
/// </summary>
|
||||
public class MethodInstance
|
||||
{
|
||||
/// <summary>
|
||||
/// 执行此RPC的实例
|
||||
/// </summary>
|
||||
public ServerProvider Provider { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// RPC函数
|
||||
/// </summary>
|
||||
public MethodInfo Method { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// RPC属性集合
|
||||
/// </summary>
|
||||
public RPCMethodAttribute[] 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 bool Async { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否有引用类型
|
||||
/// </summary>
|
||||
public bool IsByRef { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否可用
|
||||
/// </summary>
|
||||
public bool IsEnable { get; internal set; }
|
||||
}
|
||||
}
|
||||
50
RRQMSocket.RPC/Global/Control/MethodInvoker.cs
Normal file
50
RRQMSocket.RPC/Global/Control/MethodInvoker.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 函数调用信使
|
||||
/// </summary>
|
||||
public class MethodInvoker
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回值
|
||||
/// </summary>
|
||||
public object ReturnParameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数值集合
|
||||
/// </summary>
|
||||
public object[] Parameters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取调用状态
|
||||
/// </summary>
|
||||
public InvokeStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态消息
|
||||
/// </summary>
|
||||
public string StatusMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可以传递其他类型的数据容器
|
||||
/// </summary>
|
||||
public object Flag { get; set; }
|
||||
}
|
||||
}
|
||||
54
RRQMSocket.RPC/Global/Control/MethodMap.cs
Normal file
54
RRQMSocket.RPC/Global/Control/MethodMap.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 函数映射图
|
||||
/// </summary>
|
||||
public class MethodMap
|
||||
{
|
||||
internal MethodMap()
|
||||
{
|
||||
this.methodMap = new Dictionary<int, MethodInstance>();
|
||||
}
|
||||
private Dictionary<int, MethodInstance> methodMap;
|
||||
|
||||
internal void Add(MethodInstance methodInstance)
|
||||
{
|
||||
this.methodMap.Add(methodInstance.MethodToken, methodInstance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过methodToken获取函数实例
|
||||
/// </summary>
|
||||
/// <param name="methodToken"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryGet(int methodToken, out MethodInstance methodInstance)
|
||||
{
|
||||
if (this.methodMap.ContainsKey(methodToken))
|
||||
{
|
||||
methodInstance = this.methodMap[methodToken];
|
||||
return true;
|
||||
}
|
||||
methodInstance = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
RRQMSocket.RPC/Global/Control/RPCParserCollection.cs
Normal file
78
RRQMSocket.RPC/Global/Control/RPCParserCollection.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPCParser集合
|
||||
/// </summary>
|
||||
[DebuggerDisplay("Count")]
|
||||
public class RPCParserCollection : IEnumerable<RPCParser>
|
||||
{
|
||||
private Dictionary<string, RPCParser> parsers = new Dictionary<string, RPCParser>();
|
||||
|
||||
/// <summary>
|
||||
/// 数量
|
||||
/// </summary>
|
||||
public int Count { get { return parsers.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取IRPCParser
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public RPCParser this[string key] { get { return this.GetRPCParser(key); } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取IRPCParser
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public RPCParser GetRPCParser(string key)
|
||||
{
|
||||
if (this.parsers.ContainsKey(key))
|
||||
{
|
||||
return this.parsers[key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal void Add(string key, RPCParser parser)
|
||||
{
|
||||
if (this.parsers.Values.Contains(parser))
|
||||
{
|
||||
throw new RRQMRPCException("重复添加解析器");
|
||||
}
|
||||
|
||||
this.parsers.Add(key, parser);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.parsers.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回枚举对象
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator<RPCParser> IEnumerable<RPCParser>.GetEnumerator()
|
||||
{
|
||||
return this.parsers.Values.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
81
RRQMSocket.RPC/Global/Control/ServerProvider.cs
Normal file
81
RRQMSocket.RPC/Global/Control/ServerProvider.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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>
|
||||
/// RPC范围类
|
||||
/// </summary>
|
||||
public abstract class ServerProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// 该服务所属的服务器
|
||||
/// </summary>
|
||||
public RPCService RPCService { get; internal set; }
|
||||
|
||||
internal void RPC(int index,RPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
RPCEnter(parser,methodInvoker,methodInstance);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
RPCError(parser, methodInvoker, methodInstance);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
RPCLeave(parser, methodInvoker, methodInstance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC即将进入,
|
||||
/// 若是想放弃本次执行,请抛出<see cref="RRQMAbandonRPCException"/>
|
||||
/// </summary>
|
||||
/// <param name="parser"></param>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected virtual void RPCEnter(RPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行RPC发生错误
|
||||
/// </summary>
|
||||
/// <param name="parser"></param>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected virtual void RPCError(RPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC方法执行完成
|
||||
/// </summary>
|
||||
/// <param name="parser"></param>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected virtual void RPCLeave(RPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
65
RRQMSocket.RPC/Global/Control/ServerProviderCollection.cs
Normal file
65
RRQMSocket.RPC/Global/Control/ServerProviderCollection.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Diagnostics;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务集合
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{Count}")]
|
||||
public class ServerProviderCollection : IEnumerable<ServerProvider>, IEnumerable
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务数量
|
||||
/// </summary>
|
||||
public int Count { get { return this.servers.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// 唯一程序集
|
||||
/// </summary>
|
||||
public Assembly SingleAssembly { get; private set; }
|
||||
|
||||
private List<ServerProvider> servers = new List<ServerProvider>();
|
||||
|
||||
internal void Add(ServerProvider serverProvider)
|
||||
{
|
||||
if (this.SingleAssembly == null)
|
||||
{
|
||||
this.SingleAssembly = serverProvider.GetType().Assembly;
|
||||
}
|
||||
else if (SingleAssembly != serverProvider.GetType().Assembly)
|
||||
{
|
||||
throw new RRQMRPCException("所有的服务类必须声明在同一程序集内");
|
||||
}
|
||||
servers.Add(serverProvider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回枚举
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
IEnumerator<ServerProvider> IEnumerable<ServerProvider>.GetEnumerator()
|
||||
{
|
||||
return this.servers.GetEnumerator();
|
||||
}
|
||||
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.servers.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
52
RRQMSocket.RPC/Global/Exceptions/RRQMAbandonRPCException.cs
Normal file
52
RRQMSocket.RPC/Global/Exceptions/RRQMAbandonRPCException.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 放弃RPC执行
|
||||
/// </summary>
|
||||
|
||||
public class RRQMAbandonRPCException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="feedback">是否反馈信息</param>
|
||||
/// <param name="message">信息</param>
|
||||
public RRQMAbandonRPCException(bool feedback, string message) : base(message)
|
||||
{
|
||||
this.Feedback = feedback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="message">信息</param>
|
||||
public RRQMAbandonRPCException(string message) : this(true, message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RRQMAbandonRPCException() : this(true, null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否反馈信息
|
||||
/// </summary>
|
||||
public bool Feedback { get; private set; }
|
||||
}
|
||||
}
|
||||
52
RRQMSocket.RPC/Global/Exceptions/RRQMRPCException.cs
Normal file
52
RRQMSocket.RPC/Global/Exceptions/RRQMRPCException.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RPC
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// RPC异常
|
||||
/// </summary>
|
||||
|
||||
public class RRQMRPCException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RRQMRPCException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMRPCException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMRPCException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMRPCException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
48
RRQMSocket.RPC/Global/Exceptions/RRQMRPCInvokeException.cs
Normal file
48
RRQMSocket.RPC/Global/Exceptions/RRQMRPCInvokeException.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC调用异常
|
||||
/// </summary>
|
||||
|
||||
public class RRQMRPCInvokeException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RRQMRPCInvokeException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMRPCInvokeException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMRPCInvokeException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMRPCInvokeException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
81
RRQMSocket.RPC/Global/Parser/RPCParser.cs
Normal file
81
RRQMSocket.RPC/Global/Parser/RPCParser.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC解析器
|
||||
/// </summary>
|
||||
public abstract class RPCParser:IDisposable
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取函数映射图
|
||||
/// </summary>
|
||||
protected MethodMap MethodMap { get;private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包含此解析器的服务器实例
|
||||
/// </summary>
|
||||
public RPCService RPCService { get;internal set; }
|
||||
|
||||
internal Action<RPCParser, MethodInvoker,MethodInstance> RRQMExecuteMethod;
|
||||
|
||||
internal void RRQMInitializeServers(MethodInstance[] methodInstances)
|
||||
{
|
||||
InitializeServers(methodInstances);
|
||||
}
|
||||
|
||||
internal void RRQMEndInvokeMethod(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
EndInvokeMethod(methodInvoker, methodInstance);
|
||||
}
|
||||
|
||||
internal void RRQMSetMethodMap(MethodMap methodMap)
|
||||
{
|
||||
this.MethodMap = methodMap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化服务
|
||||
/// </summary>
|
||||
/// <param name="methodInstances"></param>
|
||||
protected abstract void InitializeServers(MethodInstance[] methodInstances);
|
||||
|
||||
/// <summary>
|
||||
/// 在函数调用完成后调用
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected abstract void EndInvokeMethod(MethodInvoker methodInvoker, MethodInstance methodInstance);
|
||||
|
||||
/// <summary>
|
||||
/// 执行函数
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected void ExecuteMethod(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
RRQMExecuteMethod?.Invoke(this, methodInvoker, methodInstance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public abstract void Dispose();
|
||||
}
|
||||
}
|
||||
299
RRQMSocket.RPC/Global/Server/RPCService.cs
Normal file
299
RRQMSocket.RPC/Global/Server/RPCService.cs
Normal file
@@ -0,0 +1,299 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using RRQMCore.Helper;
|
||||
|
||||
namespace RRQMSocket.RPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC服务器类
|
||||
/// </summary>
|
||||
public class RPCService : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RPCService()
|
||||
{
|
||||
this.ServerProviders = new ServerProviderCollection();
|
||||
this.RPCParsers = new RPCParserCollection();
|
||||
this.MethodMap = new MethodMap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取函数映射图实例
|
||||
/// </summary>
|
||||
public MethodMap MethodMap { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取RPC解析器集合
|
||||
/// </summary>
|
||||
public RPCParserCollection RPCParsers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加RPC解析器
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="parser"></param>
|
||||
public void AddRPCParser(string key, RPCParser parser)
|
||||
{
|
||||
this.RPCParsers.Add(key, parser);
|
||||
parser.RPCService = this;
|
||||
parser.RRQMExecuteMethod = PreviewExecuteMethod;
|
||||
parser.RRQMSetMethodMap(this.MethodMap);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取函数实例
|
||||
/// </summary>
|
||||
public MethodInstance[] MethodInstances { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取服务实例
|
||||
/// </summary>
|
||||
public ServerProviderCollection ServerProviders { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设置服务方法可用性
|
||||
/// </summary>
|
||||
/// <param name="methodToken">方法名</param>
|
||||
/// <param name="enable">可用性</param>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
public void SetMethodEnable(int methodToken, bool enable)
|
||||
{
|
||||
if (this.MethodMap.TryGet(methodToken, out MethodInstance methodInstance))
|
||||
{
|
||||
methodInstance.IsEnable = enable;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RRQMRPCException("未找到该方法");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册服务
|
||||
/// </summary>
|
||||
/// <param name="serverProvider"></param>
|
||||
public void RegistService(ServerProvider serverProvider)
|
||||
{
|
||||
serverProvider.RPCService = this;
|
||||
this.ServerProviders.Add(serverProvider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册所有服务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int RegistAllService()
|
||||
{
|
||||
Type[] types = (AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes()).Where(p => typeof(ServerProvider).IsAssignableFrom(p) && p.IsAbstract == false)).ToArray();
|
||||
|
||||
foreach (Type type in types)
|
||||
{
|
||||
ServerProvider serverProvider = Activator.CreateInstance(type) as ServerProvider;
|
||||
RegistService(serverProvider);
|
||||
}
|
||||
return types.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册服务
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns>返回T实例</returns>
|
||||
public ServerProvider RegistService<T>() where T : ServerProvider
|
||||
{
|
||||
ServerProvider serverProvider = (ServerProvider)Activator.CreateInstance(typeof(T));
|
||||
this.RegistService(serverProvider);
|
||||
return serverProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启RPC服务
|
||||
/// </summary>
|
||||
public void OpenRPCServer()
|
||||
{
|
||||
if (this.ServerProviders.Count == 0)
|
||||
{
|
||||
throw new RRQMRPCException("已注册服务数量为0");
|
||||
}
|
||||
|
||||
if (this.RPCParsers.Count == 0)
|
||||
{
|
||||
throw new RRQMRPCException("请至少添加一种RPC解析器");
|
||||
}
|
||||
|
||||
List<MethodInstance> methodInstances = new List<MethodInstance>();
|
||||
|
||||
int nullReturnNullParameters = 10000000;
|
||||
int nullReturnExistParameters = 30000000;
|
||||
int ExistReturnNullParameters = 50000000;
|
||||
int ExistReturnExistParameters = 70000000;
|
||||
|
||||
foreach (ServerProvider instance in this.ServerProviders)
|
||||
{
|
||||
|
||||
MethodInfo[] methodInfos = instance.GetType().GetMethods();
|
||||
foreach (MethodInfo method in methodInfos)
|
||||
{
|
||||
if (method.IsGenericMethod)
|
||||
{
|
||||
throw new RRQMRPCException("RPC方法中不支持泛型参数");
|
||||
}
|
||||
IEnumerable<RPCMethodAttribute> attributes = method.GetCustomAttributes<RPCMethodAttribute>(true);
|
||||
if (attributes.Count() > 0)
|
||||
{
|
||||
|
||||
MethodInstance methodInstance = new MethodInstance();
|
||||
methodInstance.Provider = instance;
|
||||
methodInstance.Method = method;
|
||||
methodInstance.RPCAttributes = attributes.ToArray();
|
||||
methodInstance.IsEnable = true;
|
||||
methodInstance.Parameters = method.GetParameters();
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
if (attribute.Async)
|
||||
{
|
||||
methodInstance.Async = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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))
|
||||
{
|
||||
methodInstance.ReturnType = null;
|
||||
|
||||
if (parameters.Length == 0)
|
||||
{
|
||||
methodInstance.MethodToken = ++nullReturnNullParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInstance.MethodToken = ++nullReturnExistParameters;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInstance.ReturnType = method.ReturnType;
|
||||
|
||||
if (parameters.Length == 0)
|
||||
{
|
||||
methodInstance.MethodToken = ++ExistReturnNullParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInstance.MethodToken = ++ExistReturnExistParameters;
|
||||
}
|
||||
}
|
||||
|
||||
methodInstances.Add(methodInstance);
|
||||
this.MethodMap.Add(methodInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.MethodInstances = methodInstances.ToArray();
|
||||
|
||||
foreach (var parser in this.RPCParsers)
|
||||
{
|
||||
parser.RRQMInitializeServers(this.MethodInstances);
|
||||
}
|
||||
}
|
||||
|
||||
private void PreviewExecuteMethod(RPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
if (methodInstance.Async)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
ExecuteMethod(parser,methodInvoker,methodInstance);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteMethod(parser, methodInvoker, methodInstance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ExecuteMethod(RPCParser parser, MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
if (methodInvoker.Status == InvokeStatus.Ready)
|
||||
{
|
||||
try
|
||||
{
|
||||
methodInstance.Provider.RPC(1,parser, methodInvoker, methodInstance);
|
||||
methodInvoker.ReturnParameter = methodInstance.Method.Invoke(methodInstance.Provider, methodInvoker.Parameters);
|
||||
methodInstance.Provider.RPC(3,parser, methodInvoker, methodInstance);
|
||||
methodInvoker.Status = InvokeStatus.Success;
|
||||
}
|
||||
catch (RRQMAbandonRPCException e)
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.Abort;
|
||||
methodInvoker.StatusMessage = "函数被阻止执行,信息:" + e.Message;
|
||||
}
|
||||
catch (TargetInvocationException e)
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.InvocationException;
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
methodInvoker.StatusMessage = "函数内部发生异常,信息:" + e.InnerException.Message;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.StatusMessage = "函数内部发生异常,信息:未知";
|
||||
}
|
||||
methodInstance.Provider.RPC(1,parser, methodInvoker, methodInstance);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.Exception;
|
||||
methodInvoker.StatusMessage = e.Message;
|
||||
methodInstance.Provider.RPC(1,parser, methodInvoker, methodInstance);
|
||||
}
|
||||
}
|
||||
|
||||
parser.RRQMEndInvokeMethod(methodInvoker, methodInstance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var item in this.RPCParsers)
|
||||
{
|
||||
item.Dispose();
|
||||
}
|
||||
this.RPCParsers = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
201
RRQMSocket.RPC/LICENSE
Normal file
201
RRQMSocket.RPC/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
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.
|
||||
BIN
RRQMSocket.RPC/RRQM.ico
Normal file
BIN
RRQMSocket.RPC/RRQM.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 244 KiB |
BIN
RRQMSocket.RPC/RRQM.png
Normal file
BIN
RRQMSocket.RPC/RRQM.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 121 KiB |
58
RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCMethodAttribute.cs
Normal file
58
RRQMSocket.RPC/RRQMRPC/Attribute/RRQMRPCMethodAttribute.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC方法标记属性类
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method,AllowMultiple = false,Inherited =false)]
|
||||
public sealed class RRQMRPCMethodAttribute : RPCMethodAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RRQMRPCMethodAttribute() : this(null, SupportProtocol.TCP | SupportProtocol.UDP)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="methodKey">指定函数键</param>
|
||||
public RRQMRPCMethodAttribute(string methodKey) : this(methodKey, SupportProtocol.TCP | SupportProtocol.UDP)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="methodKey">指定函数键</param>
|
||||
/// <param name="sp">支持调用协议</param>
|
||||
public RRQMRPCMethodAttribute(string methodKey = null, SupportProtocol sp = SupportProtocol.TCP | SupportProtocol.UDP)
|
||||
{
|
||||
this.MethodKey = methodKey;
|
||||
this.SP = sp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册键
|
||||
/// </summary>
|
||||
public string MethodKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支持调用协议
|
||||
/// </summary>
|
||||
public SupportProtocol SP { get; private set; }
|
||||
}
|
||||
}
|
||||
349
RRQMSocket.RPC/RRQMRPC/Client/RPCClient.cs
Normal file
349
RRQMSocket.RPC/RRQMRPC/Client/RPCClient.cs
Normal file
@@ -0,0 +1,349 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Log;
|
||||
using RRQMCore.Pool;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 集群RPC客户端
|
||||
/// </summary>
|
||||
public sealed class RPCClient : IRPCClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RPCClient()
|
||||
{
|
||||
this.rpcJunctorPool = new ObjectPool<RpcJunctor>();
|
||||
this.Capacity = 10;
|
||||
this.BytePool = new BytePool();
|
||||
BinarySerializeConverter serializeConverter = new BinarySerializeConverter();
|
||||
this.SerializeConverter = serializeConverter;
|
||||
this.methodStore = new MethodStore();
|
||||
this.Logger = new Log();
|
||||
}
|
||||
|
||||
private string verifyToken;
|
||||
|
||||
/// <summary>
|
||||
/// 收到字节数组并返回
|
||||
/// </summary>
|
||||
public event RRQMBytesEventHandler ReceivedBytesThenReturn;
|
||||
|
||||
/// <summary>
|
||||
/// 收到ByteBlock时触发
|
||||
/// </summary>
|
||||
public event RRQMByteBlockEventHandler ReceivedByteBlock;
|
||||
|
||||
/// <summary>
|
||||
/// 序列化生成器
|
||||
/// </summary>
|
||||
public SerializeConverter SerializeConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 缓存容量
|
||||
/// </summary>
|
||||
public int Capacity { get { return this.rpcJunctorPool.Capacity; } set { this.rpcJunctorPool.Capacity = value; } }
|
||||
|
||||
private ILog logger;
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
public ILog Logger
|
||||
{
|
||||
get { return logger; }
|
||||
set
|
||||
{
|
||||
logger = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存池实例
|
||||
/// </summary>
|
||||
public BytePool BytePool { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取即将在下一次通信的客户端单体
|
||||
/// </summary>
|
||||
public RpcJunctor NextJunctor { get { return this.rpcJunctorPool.PreviewGetObject(); } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取即将在下一次通信的客户端单体的ID
|
||||
/// </summary>
|
||||
public string ID
|
||||
{
|
||||
get
|
||||
{
|
||||
RpcJunctor rpcJunctor = this.rpcJunctorPool.PreviewGetObject();
|
||||
if (rpcJunctor != null)
|
||||
{
|
||||
return rpcJunctor.ID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC连接池
|
||||
/// </summary>
|
||||
public ObjectPool<RpcJunctor> RpcJunctorPool { get { return rpcJunctorPool; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取RPC快捷调用实例字典
|
||||
/// </summary>
|
||||
public static ConcurrentDictionary<string, RPCClient> RPCCacheDic { get { return rpcDic; } }
|
||||
|
||||
private static ConcurrentDictionary<string, RPCClient> rpcDic = new ConcurrentDictionary<string, RPCClient>();
|
||||
private IPHost iPHost;
|
||||
private bool _disposed;
|
||||
private MethodStore methodStore;
|
||||
private RPCProxyInfo proxyFile;
|
||||
private ObjectPool<RpcJunctor> rpcJunctorPool;
|
||||
|
||||
/// <summary>
|
||||
/// 获取远程服务器RPC服务文件
|
||||
/// </summary>
|
||||
/// <param name="ipHost">IP和端口</param>
|
||||
/// <param name="verifyToken">连接验证</param>
|
||||
/// <param name="proxyToken">代理令箭</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
public RPCProxyInfo GetProxyInfo(string ipHost, string verifyToken = null, string proxyToken = null)
|
||||
{
|
||||
this.iPHost = new IPHost(ipHost);
|
||||
this.verifyToken = verifyToken;
|
||||
lock (this)
|
||||
{
|
||||
RpcJunctor rpcJunctor = this.GetRpcJunctor();
|
||||
this.proxyFile = rpcJunctor.GetProxyInfo(proxyToken);
|
||||
this.rpcJunctorPool.DestroyObject(rpcJunctor);
|
||||
return this.proxyFile;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化RPC
|
||||
/// </summary>
|
||||
/// <param name="ipHost"></param>
|
||||
/// <param name="verifyToken"></param>
|
||||
/// <param name="typeDic"></param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void InitializedRPC(string ipHost, string verifyToken = null, TypeInitializeDic typeDic = null)
|
||||
{
|
||||
this.iPHost = new IPHost(ipHost);
|
||||
this.verifyToken = verifyToken;
|
||||
RpcJunctor rpcJunctor = this.GetRpcJunctor();
|
||||
this.methodStore = rpcJunctor.GetMethodStore();
|
||||
|
||||
if (this.methodStore != null)
|
||||
{
|
||||
rpcJunctor.methodStore = this.methodStore;
|
||||
this.methodStore.InitializedType(typeDic);
|
||||
this.rpcJunctorPool.DestroyObject(rpcJunctor);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentNullException("函数映射为空");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns>服务器返回结果</returns>
|
||||
public T RPCInvoke<T>(string method, ref object[] parameters, InvokeOption invokeOption)
|
||||
{
|
||||
RpcJunctor rpcJunctor = this.GetRpcJunctor();
|
||||
try
|
||||
{
|
||||
return rpcJunctor.RPCInvoke<T>(method, ref parameters, invokeOption);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.rpcJunctorPool.DestroyObject(rpcJunctor);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">函数名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void RPCInvoke(string method, ref object[] parameters, InvokeOption invokeOption)
|
||||
{
|
||||
RpcJunctor rpcJunctor = this.GetRpcJunctor();
|
||||
try
|
||||
{
|
||||
rpcJunctor.RPCInvoke(method, ref parameters, invokeOption);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.rpcJunctorPool.DestroyObject(rpcJunctor);
|
||||
}
|
||||
}
|
||||
|
||||
private int tryCount;
|
||||
|
||||
private RpcJunctor GetRpcJunctor()
|
||||
{
|
||||
if (this._disposed)
|
||||
{
|
||||
throw new RRQMRPCException("无法利用已释放资源");
|
||||
}
|
||||
RpcJunctor rpcJunctor = this.rpcJunctorPool.PreviewGetObject();
|
||||
if (rpcJunctor == null)
|
||||
{
|
||||
if (this.rpcJunctorPool.FreeSize < this.Capacity)
|
||||
{
|
||||
rpcJunctor = new RpcJunctor(this.BytePool);
|
||||
rpcJunctor.VerifyToken = this.verifyToken;
|
||||
try
|
||||
{
|
||||
rpcJunctor.Connect(this.iPHost.AddressFamily, this.iPHost.EndPoint);
|
||||
rpcJunctor.ReceivedBytesThenReturn = this.OnReceivedBytesThenReturn;
|
||||
rpcJunctor.ReceivedByteBlock = this.OnReceivedByteBlock;
|
||||
rpcJunctor.Logger = this.logger;
|
||||
rpcJunctor.SerializeConverter = this.SerializeConverter;
|
||||
rpcJunctor.methodStore = this.methodStore;
|
||||
this.tryCount = 0;
|
||||
return rpcJunctor;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.logger.Debug(LogType.Error, rpcJunctor, $"连接异常:{ex.Message}");
|
||||
rpcJunctor.Dispose();
|
||||
if (++tryCount >= this.Capacity)
|
||||
{
|
||||
throw new RRQMRPCException("重试次数达到上线");
|
||||
}
|
||||
return GetRpcJunctor();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RRQMRPCNoFreeException("无空闲RPC连接器,请稍后重试");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rpcJunctor = this.rpcJunctorPool.GetObject();
|
||||
if (!rpcJunctor.Online)
|
||||
{
|
||||
rpcJunctor.Dispose();
|
||||
if (++tryCount >= this.Capacity)
|
||||
{
|
||||
throw new RRQMRPCException("重试次数达到上线");
|
||||
}
|
||||
return GetRpcJunctor();
|
||||
}
|
||||
tryCount = 0;
|
||||
return rpcJunctor;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReceivedBytesThenReturn(object sender, BytesEventArgs e)
|
||||
{
|
||||
this.ReceivedBytesThenReturn?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
private void OnReceivedByteBlock(object sender, ByteBlock e)
|
||||
{
|
||||
this.ReceivedByteBlock?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 快捷调用RPC
|
||||
/// </summary>
|
||||
/// <param name="host">IP及端口</param>
|
||||
/// <param name="methodKey">函数键</param>
|
||||
/// <param name="verifyToken">验证Token</param>
|
||||
/// <param name="invokeOption">调用设置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
public static void CallRPC(string host, string methodKey, string verifyToken = null, InvokeOption invokeOption = null, params object[] parameters)
|
||||
{
|
||||
RPCClient client;
|
||||
if (rpcDic.TryGetValue(host, out client))
|
||||
{
|
||||
client.RPCInvoke(methodKey, ref parameters, invokeOption);
|
||||
return;
|
||||
}
|
||||
client = new RPCClient();
|
||||
client.InitializedRPC(host, verifyToken);
|
||||
rpcDic.TryAdd(host, client);
|
||||
client.RPCInvoke(methodKey, ref parameters, invokeOption);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 快捷调用RPC
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="host">IP及端口</param>
|
||||
/// <param name="methodKey">函数键</param>
|
||||
/// <param name="verifyToken">验证Token</param>
|
||||
/// <param name="invokeOption">调用设置</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <returns></returns>
|
||||
public static T CallRPC<T>(string host, string methodKey, string verifyToken = null, InvokeOption invokeOption = null, params object[] parameters)
|
||||
{
|
||||
RPCClient client;
|
||||
if (rpcDic.TryGetValue(host, out client))
|
||||
{
|
||||
return client.RPCInvoke<T>(methodKey, ref parameters, invokeOption);
|
||||
}
|
||||
client = new RPCClient();
|
||||
client.InitializedRPC(host, verifyToken);
|
||||
rpcDic.TryAdd(host, client);
|
||||
return client.RPCInvoke<T>(methodKey, ref parameters, invokeOption);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放所占资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this._disposed = true;
|
||||
while (true)
|
||||
{
|
||||
RpcJunctor rpcJunctor = this.rpcJunctorPool.GetObject();
|
||||
if (rpcJunctor == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
rpcJunctor.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
454
RRQMSocket.RPC/RRQMRPC/Client/RpcJunctor.cs
Normal file
454
RRQMSocket.RPC/RRQMRPC/Client/RpcJunctor.cs
Normal file
@@ -0,0 +1,454 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Log;
|
||||
using RRQMCore.Pool;
|
||||
using RRQMCore.Run;
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC客户端连接器
|
||||
/// </summary>
|
||||
public sealed class RpcJunctor : TokenTcpClient, IPoolObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="bytePool"></param>
|
||||
public RpcJunctor(BytePool bytePool) : base(bytePool)
|
||||
{
|
||||
this.SerializeConverter = new BinarySerializeConverter();
|
||||
this.methodStore = new MethodStore();
|
||||
this.singleWaitData = new WaitData<WaitResult>();
|
||||
this.singleWaitData.WaitResult = new WaitResult();
|
||||
this.invokeWaitData = new WaitData<RPCContext>();
|
||||
this.invokeWaitData.WaitResult = new RPCContext();
|
||||
this.DataHandlingAdapter = new FixedHeaderDataHandlingAdapter();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收到字节数组并返回
|
||||
/// </summary>
|
||||
internal RRQMBytesEventHandler ReceivedBytesThenReturn;
|
||||
|
||||
/// <summary>
|
||||
/// 收到ByteBlock时触发
|
||||
/// </summary>
|
||||
internal RRQMByteBlockEventHandler ReceivedByteBlock;
|
||||
|
||||
/// <summary>
|
||||
/// 序列化生成器
|
||||
/// </summary>
|
||||
internal SerializeConverter SerializeConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否新创建
|
||||
/// </summary>
|
||||
public bool NewCreat { get; set; }
|
||||
|
||||
private WaitData<WaitResult> singleWaitData;
|
||||
private WaitData<RPCContext> invokeWaitData;
|
||||
internal MethodStore methodStore;
|
||||
private RPCProxyInfo proxyFile;
|
||||
private RRQMAgreementHelper agreementHelper;
|
||||
|
||||
/// <summary>
|
||||
/// 获取函数注册
|
||||
/// </summary>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
internal MethodStore GetMethodStore()
|
||||
{
|
||||
this.agreementHelper = new RRQMAgreementHelper(this);
|
||||
lock (locker)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.methodStore = null;
|
||||
agreementHelper.SocketSend(102);
|
||||
this.singleWaitData.Wait(1000 * 10);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMRPCException(e.Message);
|
||||
}
|
||||
return this.methodStore;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取远程服务器RPC服务文件
|
||||
/// </summary>
|
||||
/// <param name="proxyToken">代理令箭</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
public RPCProxyInfo GetProxyInfo(string proxyToken)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
agreementHelper.SocketSend(100, proxyToken);
|
||||
this.singleWaitData.Wait(1000 * 100);
|
||||
|
||||
if (this.proxyFile == null)
|
||||
{
|
||||
throw new RRQMTimeoutException("获取引用文件超时");
|
||||
}
|
||||
else if (this.proxyFile.Status == 2)
|
||||
{
|
||||
throw new RRQMRPCException(this.proxyFile.Message);
|
||||
}
|
||||
return this.proxyFile;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 链接
|
||||
/// </summary>
|
||||
/// <param name="addressFamily"></param>
|
||||
/// <param name="endPoint"></param>
|
||||
public override void Connect(AddressFamily addressFamily, EndPoint endPoint)
|
||||
{
|
||||
base.Connect(addressFamily, endPoint);
|
||||
this.agreementHelper = new RRQMAgreementHelper(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns>服务器返回结果</returns>
|
||||
public T RPCInvoke<T>(string method, ref object[] parameters, InvokeOption invokeOption)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
MethodItem methodItem = methodStore.GetMethodItem(method);
|
||||
|
||||
invokeWaitData.WaitResult.MethodToken = methodItem.MethodToken;
|
||||
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
if (invokeOption == null)
|
||||
{
|
||||
invokeOption = InvokeOption.CanFeedback;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
invokeWaitData.WaitResult.Feedback = 1;
|
||||
}
|
||||
List<byte[]> datas = new List<byte[]>();
|
||||
foreach (object parameter in parameters)
|
||||
{
|
||||
datas.Add(this.SerializeConverter.SerializeParameter(parameter));
|
||||
}
|
||||
invokeWaitData.WaitResult.ParametersBytes = datas;
|
||||
invokeWaitData.WaitResult.Serialize(byteBlock);
|
||||
|
||||
agreementHelper.SocketSend(101, byteBlock);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMException(e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
invokeWaitData.Wait(invokeOption.WaitTime * 1000);
|
||||
|
||||
RPCContext context = invokeWaitData.WaitResult;
|
||||
invokeWaitData.Dispose();
|
||||
if (context.Status == 0)
|
||||
{
|
||||
throw new RRQMTimeoutException("等待结果超时");
|
||||
}
|
||||
else if (context.Status == 2)
|
||||
{
|
||||
throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod");
|
||||
}
|
||||
else if (context.Status == 3)
|
||||
{
|
||||
throw new RRQMRPCException("该方法已被禁用");
|
||||
}
|
||||
else if (context.Status == 4)
|
||||
{
|
||||
throw new RRQMRPCException($"服务器已阻止本次行为,信息:{context.MethodToken}");
|
||||
}
|
||||
if (methodItem.IsOutOrRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializeConverter.DeserializeParameter(context.ParametersBytes[i], methodItem.ParameterTypes[i]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMException(e.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (T)this.SerializeConverter.DeserializeParameter(context.ReturnParameterBytes, methodItem.ReturnType);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMException(e.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">函数名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void RPCInvoke(string method, ref object[] parameters, InvokeOption invokeOption)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
MethodItem methodItem = this.methodStore.GetMethodItem(method);
|
||||
invokeWaitData.WaitResult.MethodToken = methodItem.MethodToken;
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
if (invokeOption == null)
|
||||
{
|
||||
invokeOption = InvokeOption.CanFeedback;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
invokeWaitData.WaitResult.Feedback = 1;
|
||||
}
|
||||
List<byte[]> datas = new List<byte[]>();
|
||||
foreach (object parameter in parameters)
|
||||
{
|
||||
datas.Add(this.SerializeConverter.SerializeParameter(parameter));
|
||||
}
|
||||
invokeWaitData.WaitResult.ParametersBytes = datas;
|
||||
invokeWaitData.WaitResult.Serialize(byteBlock);
|
||||
agreementHelper.SocketSend(101, byteBlock);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMException(e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
invokeWaitData.Wait(invokeOption.WaitTime * 1000);
|
||||
RPCContext context = invokeWaitData.WaitResult;
|
||||
invokeWaitData.Dispose();
|
||||
|
||||
if (context.Status == 0)
|
||||
{
|
||||
throw new RRQMTimeoutException("等待结果超时");
|
||||
}
|
||||
else if (context.Status == 2)
|
||||
{
|
||||
throw new RRQMRPCInvokeException("未找到该公共方法,或该方法未标记RRQMRPCMethod");
|
||||
}
|
||||
else if (context.Status == 3)
|
||||
{
|
||||
throw new RRQMRPCException("该方法已被禁用");
|
||||
}
|
||||
else if (context.Status == 4)
|
||||
{
|
||||
throw new RRQMRPCException($"服务器已阻止本次行为,信息:{context.MethodToken}");
|
||||
}
|
||||
if (methodItem.IsOutOrRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
parameters[i] = this.SerializeConverter.DeserializeParameter(context.ParametersBytes[i], methodItem.ParameterTypes[i]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMException(e.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invokeWaitData.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Agreement_110(byte[] buffer, int r)
|
||||
{
|
||||
WaitBytes waitBytes = SerializeConvert.RRQMBinaryDeserialize<WaitBytes>(buffer, 4);
|
||||
BytesEventArgs args = new BytesEventArgs();
|
||||
args.ReceivedDataBytes = waitBytes.Bytes;
|
||||
this.ReceivedBytesThenReturn?.Invoke(this, args);
|
||||
waitBytes.Bytes = args.ReturnDataBytes;
|
||||
|
||||
agreementHelper.SocketSend(110, SerializeConvert.RRQMBinarySerialize(waitBytes, true));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理已接收到的数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="obj"></param>
|
||||
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
|
||||
{
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
int r = (int)byteBlock.Length;
|
||||
int agreement = BitConverter.ToInt32(buffer, 0);
|
||||
switch (agreement)
|
||||
{
|
||||
case 100:/* 100表示获取RPC引用文件上传状态返回*/
|
||||
{
|
||||
try
|
||||
{
|
||||
proxyFile = SerializeConvert.RRQMBinaryDeserialize<RPCProxyInfo>(buffer, 4);
|
||||
this.singleWaitData.Set();
|
||||
}
|
||||
catch
|
||||
{
|
||||
proxyFile = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 101:/*函数调用返回数据对象*/
|
||||
{
|
||||
try
|
||||
{
|
||||
RPCContext result = RPCContext.Deserialize(buffer, 4);
|
||||
this.invokeWaitData.Set(result);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 101, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 102:/*连接初始化返回数据对象*/
|
||||
{
|
||||
try
|
||||
{
|
||||
List<MethodItem> methodItems = SerializeConvert.RRQMBinaryDeserialize<List<MethodItem>>(buffer, 4);
|
||||
this.methodStore = new MethodStore();
|
||||
foreach (var item in methodItems)
|
||||
{
|
||||
this.methodStore.AddMethodItem(item);
|
||||
}
|
||||
|
||||
this.singleWaitData.Set();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 110:/*反向函数调用返回*/
|
||||
{
|
||||
try
|
||||
{
|
||||
Agreement_110(buffer, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 110, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 111:/*收到服务器数据*/
|
||||
{
|
||||
ByteBlock block = this.BytePool.GetByteBlock(r - 4);
|
||||
try
|
||||
{
|
||||
block.Write(byteBlock.Buffer, 4, r - 4);
|
||||
ReceivedByteBlock?.Invoke(this, block);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 111, 错误详情:{e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
block.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初创建
|
||||
/// </summary>
|
||||
public void Create()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重复创建
|
||||
/// </summary>
|
||||
public void Recreate()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注销时
|
||||
/// </summary>
|
||||
public void Destroy()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
502
RRQMSocket.RPC/RRQMRPC/Client/UdpRPCClient.cs
Normal file
502
RRQMSocket.RPC/RRQMRPC/Client/UdpRPCClient.cs
Normal file
@@ -0,0 +1,502 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Log;
|
||||
using RRQMCore.Run;
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// UDP协议客户端
|
||||
/// </summary>
|
||||
public class UdpRPCClient : IRPCClient, IService
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public UdpRPCClient() : this(new BytePool(1024 * 1024 * 1000, 1024 * 1024 * 20))
|
||||
{
|
||||
}
|
||||
|
||||
private EndPoint remoteService;
|
||||
private MethodStore methodStore;
|
||||
private WaitData<WaitResult> singleWaitData;
|
||||
private RRQMUdpSession udpSession;
|
||||
private RPCProxyInfo proxyFile;
|
||||
private WaitResult waitResult;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="bytePool"></param>
|
||||
public UdpRPCClient(BytePool bytePool)
|
||||
{
|
||||
this.SerializeConverter = new BinarySerializeConverter();
|
||||
this.waitResult = new WaitResult();
|
||||
this.Logger = new Log();
|
||||
this.singleWaitData = new WaitData<WaitResult>();
|
||||
this.BytePool = bytePool;
|
||||
this.udpSession = new RRQMUdpSession();
|
||||
this.udpSession.OnReceivedData += this.UdpSession_OnReceivedData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收到字节数组并返回
|
||||
/// </summary>
|
||||
public event RRQMBytesEventHandler ReceivedBytesThenReturn;
|
||||
|
||||
/// <summary>
|
||||
/// 收到ByteBlock时触发
|
||||
/// </summary>
|
||||
public event RRQMByteBlockEventHandler ReceivedByteBlock;
|
||||
|
||||
/// <summary>
|
||||
/// 数据交互缓存池限制,Min:1k Byte,Max:10Mb Byte
|
||||
/// </summary>
|
||||
public int BufferLength { get => this.udpSession.BufferLength; set { this.udpSession.BufferLength = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// 序列化生成器
|
||||
/// </summary>
|
||||
public SerializeConverter SerializeConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存池实例
|
||||
/// </summary>
|
||||
public BytePool BytePool { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
public ILog Logger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 返回ID
|
||||
/// </summary>
|
||||
public string ID => null;
|
||||
|
||||
/// <summary>
|
||||
/// 绑定状态
|
||||
/// </summary>
|
||||
public bool IsBind => this.udpSession.IsBind;
|
||||
|
||||
/// <summary>
|
||||
/// 获取远程服务器RPC服务文件
|
||||
/// </summary>
|
||||
/// <param name="ipHost"></param>
|
||||
/// <param name="verifyToken"></param>
|
||||
/// <param name="proxyToken">代理令箭</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
public RPCProxyInfo GetProxyInfo(string ipHost, string verifyToken = null, string proxyToken = null)
|
||||
{
|
||||
this.remoteService = new IPHost(ipHost).EndPoint;
|
||||
int count = 0;
|
||||
while (count < 3)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
byte[] datas;
|
||||
if (proxyToken == null)
|
||||
{
|
||||
datas = new byte[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
datas = Encoding.UTF8.GetBytes(proxyToken);
|
||||
}
|
||||
this.UDPSend(100, datas, 0, datas.Length);
|
||||
this.singleWaitData.Wait(3);
|
||||
if (this.proxyFile != null)
|
||||
{
|
||||
return this.proxyFile;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化RPC
|
||||
/// </summary>
|
||||
/// <param name="ipHost"></param>
|
||||
/// <param name="verifyToken"></param>
|
||||
/// <param name="typeDic"></param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void InitializedRPC(string ipHost, string verifyToken = null, TypeInitializeDic typeDic = null)
|
||||
{
|
||||
if (this.udpSession.MainSocket == null)
|
||||
{
|
||||
throw new RRQMRPCException("UDP端需要先绑定本地监听端口");
|
||||
}
|
||||
this.remoteService = new IPHost(ipHost).EndPoint;
|
||||
int count = 0;
|
||||
while (count < 3)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.methodStore = null;
|
||||
this.UDPSend(102);
|
||||
this.singleWaitData.Wait(1000 * 3);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMRPCException(e.Message);
|
||||
}
|
||||
if (this.methodStore != null)
|
||||
{
|
||||
this.methodStore.InitializedType(typeDic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
throw new RRQMTimeoutException("连接初始化超时");
|
||||
}
|
||||
|
||||
private void Agreement_110(byte[] buffer, int r)
|
||||
{
|
||||
WaitBytes waitBytes = SerializeConvert.RRQMBinaryDeserialize<WaitBytes>(buffer, 4);
|
||||
BytesEventArgs args = new BytesEventArgs();
|
||||
args.ReceivedDataBytes = waitBytes.Bytes;
|
||||
this.ReceivedBytesThenReturn?.Invoke(this, args);
|
||||
waitBytes.Bytes = args.ReturnDataBytes;
|
||||
byte[] data = SerializeConvert.RRQMBinarySerialize(waitBytes, true);
|
||||
UDPSend(110, data, 0, data.Length);
|
||||
}
|
||||
|
||||
private void UdpSession_OnReceivedData(EndPoint remoteEndpoint, ByteBlock byteBlock)
|
||||
{
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
int r = (int)byteBlock.Position;
|
||||
int agreement = BitConverter.ToInt32(buffer, 0);
|
||||
switch (agreement)
|
||||
{
|
||||
case 100:/* 100表示获取RPC引用文件上传状态返回*/
|
||||
{
|
||||
try
|
||||
{
|
||||
proxyFile = SerializeConvert.RRQMBinaryDeserialize<RPCProxyInfo>(buffer, 4);
|
||||
this.singleWaitData.Set();
|
||||
}
|
||||
catch
|
||||
{
|
||||
proxyFile = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 101:/*函数调用返回数据对象*/
|
||||
{
|
||||
try
|
||||
{
|
||||
this.singleWaitData.Set(waitResult);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 101, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 102:/*连接初始化返回数据对象*/
|
||||
{
|
||||
try
|
||||
{
|
||||
List<MethodItem> methodItems = SerializeConvert.RRQMBinaryDeserialize<List<MethodItem>>(buffer, 4);
|
||||
this.methodStore = new MethodStore();
|
||||
foreach (var item in methodItems)
|
||||
{
|
||||
this.methodStore.AddMethodItem(item);
|
||||
}
|
||||
|
||||
this.singleWaitData.Set();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 110:/*反向函数调用返回*/
|
||||
{
|
||||
try
|
||||
{
|
||||
Agreement_110(buffer, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 110, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 111:/*收到服务器数据*/
|
||||
{
|
||||
ByteBlock block = this.BytePool.GetByteBlock(r - 4);
|
||||
try
|
||||
{
|
||||
block.Write(byteBlock.Buffer, 4, r - 4);
|
||||
ReceivedByteBlock?.Invoke(this, block);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 111, 错误详情:{e.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
block.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UDPSend(int agreement, byte[] buffer, int offset, int length)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(length + 4);
|
||||
try
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(agreement));
|
||||
byteBlock.Write(buffer, offset, length);
|
||||
this.udpSession.SendTo(byteBlock.Buffer, 0, (int)byteBlock.Length, remoteService);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void UDPSend(int agreement, ByteBlock block)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(block.Length + 4);
|
||||
try
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(agreement));
|
||||
byteBlock.Write(block.Buffer, 0, (int)block.Length);
|
||||
this.udpSession.SendTo(byteBlock.Buffer, 0, (int)byteBlock.Length, remoteService);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void UDPSend(int agreement)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(agreement));
|
||||
this.udpSession.SendTo(byteBlock.Buffer, 0, (int)byteBlock.Length, remoteService);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns>服务器返回结果</returns>
|
||||
public T RPCInvoke<T>(string method, ref object[] parameters, InvokeOption invokeOption)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
this.singleWaitData.WaitResult = null;
|
||||
RPCContext context = new RPCContext();
|
||||
MethodItem methodItem = this.methodStore.GetMethodItem(method);
|
||||
context.MethodToken = methodItem.MethodToken;
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
if (invokeOption == null)
|
||||
{
|
||||
invokeOption = InvokeOption.NoFeedback;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
context.Feedback = 1;
|
||||
}
|
||||
List<byte[]> datas = new List<byte[]>();
|
||||
foreach (object parameter in parameters)
|
||||
{
|
||||
datas.Add(this.SerializeConverter.SerializeParameter(parameter));
|
||||
}
|
||||
context.ParametersBytes = datas;
|
||||
context.Serialize(byteBlock);
|
||||
|
||||
UDPSend(101, byteBlock);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMException(e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
this.singleWaitData.Wait(invokeOption.WaitTime * 1000);
|
||||
if (this.singleWaitData.WaitResult == null)
|
||||
{
|
||||
throw new RRQMTimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">函数名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption"></param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
public void RPCInvoke(string method, ref object[] parameters, InvokeOption invokeOption)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
this.singleWaitData.WaitResult = null;
|
||||
RPCContext context = new RPCContext();
|
||||
MethodItem methodItem = this.methodStore.GetMethodItem(method);
|
||||
context.MethodToken = methodItem.MethodToken;
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
if (invokeOption == null)
|
||||
{
|
||||
invokeOption = InvokeOption.NoFeedback;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
context.Feedback = 1;
|
||||
}
|
||||
List<byte[]> datas = new List<byte[]>();
|
||||
foreach (object parameter in parameters)
|
||||
{
|
||||
datas.Add(this.SerializeConverter.SerializeParameter(parameter));
|
||||
}
|
||||
context.ParametersBytes = datas;
|
||||
context.Serialize(byteBlock);
|
||||
|
||||
UDPSend(101, byteBlock);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMException(e.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
if (invokeOption.Feedback)
|
||||
{
|
||||
this.singleWaitData.Wait(invokeOption.WaitTime * 1000);
|
||||
if (this.singleWaitData.WaitResult == null)
|
||||
{
|
||||
throw new RRQMTimeoutException("等待结果超时");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放所占资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.udpSession.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="port">端口号</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Bind(int port, int threadCount = 1)
|
||||
{
|
||||
this.Bind(new IPHost($"0.0.0.0:{port}"), threadCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="iPHost">ip和端口号,格式如“127.0.0.1:7789”。IP可输入Ipv6</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Bind(IPHost iPHost, int threadCount)
|
||||
{
|
||||
if (iPHost == null)
|
||||
{
|
||||
throw new ArgumentNullException("iPHost不能为空。");
|
||||
}
|
||||
this.Bind(iPHost.AddressFamily, iPHost.EndPoint, threadCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定本地监听
|
||||
/// </summary>
|
||||
/// <param name="addressFamily"></param>
|
||||
/// <param name="endPoint"></param>
|
||||
/// <param name="threadCount"></param>
|
||||
public void Bind(AddressFamily addressFamily, EndPoint endPoint, int threadCount)
|
||||
{
|
||||
this.udpSession.Bind(addressFamily, endPoint, threadCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
RRQMSocket.RPC/RRQMRPC/Control/CellCode.cs
Normal file
36
RRQMSocket.RPC/RRQMRPC/Control/CellCode.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成的单元代码
|
||||
/// </summary>
|
||||
|
||||
public class CellCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 类名
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代码本体
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代码类型
|
||||
/// </summary>
|
||||
public CodeType CodeType { get; set; }
|
||||
}
|
||||
}
|
||||
332
RRQMSocket.RPC/RRQMRPC/Control/CodeMap.cs
Normal file
332
RRQMSocket.RPC/RRQMRPC/Control/CodeMap.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
internal class CodeMap
|
||||
{
|
||||
internal CodeMap()
|
||||
{
|
||||
codeString = new StringBuilder();
|
||||
}
|
||||
|
||||
internal static string GetAssemblyInfo(string assemblyName, Version version)
|
||||
{
|
||||
CodeMap codeMap = new CodeMap();
|
||||
codeMap.AppendAssemblyInfo(assemblyName, version);
|
||||
return codeMap.codeString.ToString();
|
||||
}
|
||||
|
||||
private StringBuilder codeString;
|
||||
|
||||
internal MethodInfo[] Methods { get; set; }
|
||||
internal string ClassName { get; set; }
|
||||
internal static string Namespace { get; set; }
|
||||
internal static PropertyCodeMap PropertyCode { get; set; }
|
||||
internal static Version Version { get; set; }
|
||||
|
||||
internal string GetCode()
|
||||
{
|
||||
codeString.AppendLine("using System;");
|
||||
codeString.AppendLine("using RRQMSocket.RPC;");
|
||||
codeString.AppendLine("using RRQMSocket.RPC.RRQMRPC;");
|
||||
codeString.AppendLine("using RRQMCore.Exceptions;");
|
||||
codeString.AppendLine("using System.Collections.Generic;");
|
||||
codeString.AppendLine("using System.Diagnostics;");
|
||||
codeString.AppendLine("using System.Text;");
|
||||
codeString.AppendLine("using System.Threading.Tasks;");
|
||||
codeString.AppendLine(string.Format("namespace {0}", Namespace));
|
||||
codeString.AppendLine("{");
|
||||
string className = this.ClassName;
|
||||
codeString.AppendLine(string.Format("public class {0}", className));//类开始
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine($"public {className}(IRPCClient client)");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("this.Client=client;");
|
||||
codeString.AppendLine("}");
|
||||
AppendAttributes();
|
||||
AppendMethods();
|
||||
codeString.AppendLine("}");//类结束
|
||||
|
||||
codeString.AppendLine("}");//空间结束
|
||||
|
||||
return codeString.ToString();
|
||||
}
|
||||
|
||||
private void AppendAssemblyInfo(string assemblyName, Version version)
|
||||
{
|
||||
codeString.AppendLine("using System.Reflection;");
|
||||
codeString.AppendLine("using System.Runtime.CompilerServices;");
|
||||
codeString.AppendLine("using System.Runtime.InteropServices;");
|
||||
codeString.AppendLine("[assembly: AssemblyTitle(\"RRQMRPC\")]");
|
||||
codeString.AppendLine("[assembly: AssemblyProduct(\"RRQMRPC\")]");
|
||||
codeString.AppendLine("[assembly: AssemblyCopyright(\"Copyright © 2020 若汝棋茗\")]");
|
||||
codeString.AppendLine("[assembly: ComVisible(false)]");
|
||||
|
||||
if (version == null)
|
||||
{
|
||||
if (File.Exists($"{assemblyName}.dll"))
|
||||
{
|
||||
Assembly assembly = Assembly.Load(File.ReadAllBytes($"{assemblyName}.dll"));
|
||||
Version v = assembly.GetName().Version;
|
||||
version = new Version(v.Major, v.Minor, v.Build + 1, v.Revision);
|
||||
}
|
||||
else
|
||||
{
|
||||
version = new Version("1.0.0.0");
|
||||
}
|
||||
}
|
||||
|
||||
Version = version;
|
||||
codeString.AppendLine(string.Format("[assembly: AssemblyVersion(\"{0}\")]", version.ToString()));
|
||||
codeString.AppendLine(string.Format("[assembly: AssemblyFileVersion(\"{0}\")]", version.ToString()));
|
||||
}
|
||||
|
||||
private void AppendAttributes()
|
||||
{
|
||||
codeString.AppendLine("public IRPCClient Client{get;private set; }");
|
||||
}
|
||||
|
||||
public string GetName(Type type)
|
||||
{
|
||||
return PropertyCode.GetTypeFullName(type);
|
||||
}
|
||||
|
||||
private void AppendMethods()
|
||||
{
|
||||
if (Methods != null)
|
||||
{
|
||||
foreach (MethodInfo method in Methods)
|
||||
{
|
||||
bool isReturn;
|
||||
bool isOutOrRef = false;
|
||||
string methodName = method.GetCustomAttribute<RRQMRPCMethodAttribute>().MethodKey == null ? method.Name : method.GetCustomAttribute<RRQMRPCMethodAttribute>().MethodKey;
|
||||
|
||||
if (method.ReturnType.Name == "Void")
|
||||
{
|
||||
isReturn = false;
|
||||
codeString.Append(string.Format("public void {0} ", methodName));
|
||||
}
|
||||
else
|
||||
{
|
||||
isReturn = true;
|
||||
codeString.Append(string.Format("public {0} {1} ", this.GetName(method.ReturnType), methodName));
|
||||
}
|
||||
codeString.Append("(");//方法参数
|
||||
|
||||
ParameterInfo[] parameters = method.GetParameters();
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
}
|
||||
if (parameters[i].ParameterType.Name.Contains("&"))
|
||||
{
|
||||
isOutOrRef = true;
|
||||
if (parameters[i].IsOut)
|
||||
{
|
||||
codeString.Append(string.Format("out {0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append(string.Format("ref {0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append(string.Format("{0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name));
|
||||
}
|
||||
|
||||
if (parameters[i].DefaultValue != System.DBNull.Value)
|
||||
{
|
||||
object defaultValue = parameters[i].DefaultValue;
|
||||
if (defaultValue == null)
|
||||
{
|
||||
codeString.Append(string.Format("=null"));
|
||||
}
|
||||
else if (defaultValue.ToString() == string.Empty)
|
||||
{
|
||||
codeString.Append(string.Format("=\"\""));
|
||||
}
|
||||
else if (defaultValue.GetType() == typeof(string))
|
||||
{
|
||||
codeString.Append(string.Format("=\"{0}\"", defaultValue));
|
||||
}
|
||||
else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType()))
|
||||
{
|
||||
codeString.Append(string.Format("={0}", defaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parameters.Length > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
}
|
||||
codeString.AppendLine("InvokeOption invokeOption = null)");
|
||||
|
||||
codeString.AppendLine("{");//方法开始
|
||||
|
||||
codeString.AppendLine("if(Client==null)");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("throw new RRQMRPCException(\"IRPCClient为空,请先初始化或者进行赋值\");");
|
||||
codeString.AppendLine("}");
|
||||
|
||||
codeString.Append($"object[] parameters = new object[]");
|
||||
codeString.Append("{");
|
||||
foreach (ParameterInfo parameter in parameters)
|
||||
{
|
||||
if (parameter.ParameterType.Name.Contains("&") && parameter.IsOut)
|
||||
{
|
||||
codeString.Append($"default({this.GetName(parameter.ParameterType)})");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append(parameter.Name);
|
||||
}
|
||||
if (parameter != parameters[parameters.Length - 1])
|
||||
{
|
||||
codeString.Append(",");
|
||||
}
|
||||
}
|
||||
codeString.AppendLine("};");
|
||||
|
||||
if (isReturn)
|
||||
{
|
||||
codeString.Append(string.Format("{0} returnData=Client.RPCInvoke<{0}>", this.GetName(method.ReturnType)));
|
||||
codeString.Append("(");
|
||||
codeString.Append(string.Format("\"{0}\"", methodName));
|
||||
codeString.AppendLine(",ref parameters,invokeOption);");
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.Append("Client.RPCInvoke(");
|
||||
codeString.Append(string.Format("\"{0}\"", methodName));
|
||||
codeString.AppendLine(",ref parameters,invokeOption);");
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
codeString.AppendLine(string.Format("{0}=default({1});", parameters[i].Name, this.GetName(parameters[i].ParameterType)));
|
||||
}
|
||||
|
||||
codeString.AppendLine("if(parameters!=null)");
|
||||
codeString.AppendLine("{");
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
codeString.AppendLine(string.Format("{0}=({1})parameters[{2}];", parameters[i].Name, this.GetName(parameters[i].ParameterType), i));
|
||||
}
|
||||
codeString.AppendLine("}");
|
||||
if (isReturn)
|
||||
{
|
||||
codeString.AppendLine("return returnData;");
|
||||
}
|
||||
|
||||
codeString.AppendLine("}");
|
||||
|
||||
if (!isOutOrRef)//没有out或者ref
|
||||
{
|
||||
if (method.ReturnType.Name == "Void")
|
||||
{
|
||||
isReturn = false;
|
||||
codeString.Append(string.Format("public async void {0} ", methodName + "Async"));
|
||||
}
|
||||
else
|
||||
{
|
||||
isReturn = true;
|
||||
codeString.Append(string.Format("public async Task<{0}> {1} ", this.GetName(method.ReturnType), methodName + "Async"));
|
||||
}
|
||||
|
||||
codeString.Append("(");//方法参数
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
}
|
||||
|
||||
codeString.Append(string.Format("{0} {1}", this.GetName(parameters[i].ParameterType), parameters[i].Name));
|
||||
if (parameters[i].DefaultValue != System.DBNull.Value)
|
||||
{
|
||||
object defaultValue = parameters[i].DefaultValue;
|
||||
if (defaultValue == null)
|
||||
{
|
||||
codeString.Append(string.Format("=null"));
|
||||
}
|
||||
else if (defaultValue.ToString() == string.Empty)
|
||||
{
|
||||
codeString.Append(string.Format("=\"\""));
|
||||
}
|
||||
else if (defaultValue.GetType() == typeof(string))
|
||||
{
|
||||
codeString.Append(string.Format("=\"{0}\"", defaultValue));
|
||||
}
|
||||
else if (typeof(ValueType).IsAssignableFrom(defaultValue.GetType()))
|
||||
{
|
||||
codeString.Append(string.Format("={0}", defaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.Length > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
}
|
||||
codeString.AppendLine("InvokeOption invokeOption = null)");
|
||||
codeString.AppendLine("{");//方法开始
|
||||
codeString.AppendLine("if(Client==null)");
|
||||
codeString.AppendLine("{");
|
||||
codeString.AppendLine("throw new RRQMRPCException(\"RPCClient为空,请先初始化或者进行赋值\");");
|
||||
codeString.AppendLine("}");
|
||||
if (isReturn)
|
||||
{
|
||||
codeString.AppendLine("return await Task.Run(() =>{");
|
||||
codeString.Append(string.Format("return {0}(", methodName));
|
||||
}
|
||||
else
|
||||
{
|
||||
codeString.AppendLine("await Task.Run(() =>{");
|
||||
codeString.Append(string.Format("{0}(", methodName));
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
}
|
||||
|
||||
codeString.Append(string.Format("{0}", parameters[i].Name));
|
||||
}
|
||||
if (parameters.Length > 0)
|
||||
{
|
||||
codeString.Append(",");
|
||||
}
|
||||
codeString.Append("invokeOption);");
|
||||
codeString.AppendLine("});");
|
||||
codeString.AppendLine("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
RRQMSocket.RPC/RRQMRPC/Control/CodeType.cs
Normal file
31
RRQMSocket.RPC/RRQMRPC/Control/CodeType.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码类型
|
||||
/// </summary>
|
||||
|
||||
public enum CodeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 类代码
|
||||
/// </summary>
|
||||
ClassArgs,
|
||||
|
||||
/// <summary>
|
||||
/// 服务代码
|
||||
/// </summary>
|
||||
Service
|
||||
}
|
||||
}
|
||||
30
RRQMSocket.RPC/RRQMRPC/Control/IRPCCompiler.cs
Normal file
30
RRQMSocket.RPC/RRQMRPC/Control/IRPCCompiler.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC编译器
|
||||
/// </summary>
|
||||
public interface IRPCCompiler
|
||||
{
|
||||
/// <summary>
|
||||
/// 编译代码
|
||||
/// </summary>
|
||||
/// <param name="assemblyName"></param>
|
||||
/// <param name="codes"></param>
|
||||
/// <param name="refStrings"></param>
|
||||
/// <returns></returns>
|
||||
byte[] CompileCode(string assemblyName, string[] codes, List<string> refStrings);
|
||||
}
|
||||
}
|
||||
57
RRQMSocket.RPC/RRQMRPC/Control/InvokeOption.cs
Normal file
57
RRQMSocket.RPC/RRQMRPC/Control/InvokeOption.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC调用设置
|
||||
/// </summary>
|
||||
public class InvokeOption
|
||||
{
|
||||
static InvokeOption()
|
||||
{
|
||||
_tcpInvoke = new InvokeOption();
|
||||
_tcpInvoke.WaitTime = 3;
|
||||
_tcpInvoke.Feedback = true;
|
||||
|
||||
_udpInvoke = new InvokeOption();
|
||||
_udpInvoke.WaitTime = 3;
|
||||
_udpInvoke.Feedback = false;
|
||||
}
|
||||
|
||||
private static InvokeOption _tcpInvoke;
|
||||
|
||||
/// <summary>
|
||||
/// 默认设置。
|
||||
/// WaitTime=3,Feedback=True。
|
||||
/// </summary>
|
||||
public static InvokeOption CanFeedback { get { return _tcpInvoke; } }
|
||||
|
||||
private static InvokeOption _udpInvoke;
|
||||
|
||||
/// <summary>
|
||||
/// 默认设置。
|
||||
/// WaitTime=3,Feedback=False。
|
||||
/// </summary>
|
||||
public static InvokeOption NoFeedback { get { return _udpInvoke; } }
|
||||
|
||||
/// <summary>
|
||||
/// 调用等待时长
|
||||
/// </summary>
|
||||
public int WaitTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 调用反馈
|
||||
/// </summary>
|
||||
public bool Feedback { get; set; }
|
||||
}
|
||||
}
|
||||
57
RRQMSocket.RPC/RRQMRPC/Control/MethodItem.cs
Normal file
57
RRQMSocket.RPC/RRQMRPC/Control/MethodItem.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 方法体
|
||||
/// </summary>
|
||||
public class MethodItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 方法唯一标识
|
||||
/// </summary>
|
||||
public int MethodToken { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法名
|
||||
/// </summary>
|
||||
public string Method { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 返回值类型
|
||||
/// </summary>
|
||||
internal Type ReturnType;
|
||||
|
||||
/// <summary>
|
||||
/// 参数类型
|
||||
/// </summary>
|
||||
internal List<Type> ParameterTypes;
|
||||
|
||||
/// <summary>
|
||||
/// 返回值类型
|
||||
/// </summary>
|
||||
public string ReturnTypeString { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数类型
|
||||
/// </summary>
|
||||
public List<string> ParameterTypesString { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否含有Out或Ref
|
||||
/// </summary>
|
||||
public bool IsOutOrRef { get; internal set; }
|
||||
}
|
||||
}
|
||||
124
RRQMSocket.RPC/RRQMRPC/Control/MethodStore.cs
Normal file
124
RRQMSocket.RPC/RRQMRPC/Control/MethodStore.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Reflection;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 函数仓库
|
||||
/// </summary>
|
||||
public class MethodStore
|
||||
{
|
||||
internal MethodStore()
|
||||
{
|
||||
this.tokenToMethodItem = new Dictionary<int, MethodItem>();
|
||||
this.methodKeyToMethodItem = new Dictionary<string, MethodItem>();
|
||||
}
|
||||
|
||||
private Dictionary<int, MethodItem> tokenToMethodItem;
|
||||
private Dictionary<string, MethodItem> methodKeyToMethodItem;
|
||||
|
||||
internal void AddMethodItem(MethodItem methodItem)
|
||||
{
|
||||
tokenToMethodItem.Add(methodItem.MethodToken, methodItem);
|
||||
methodKeyToMethodItem.Add(methodItem.Method, methodItem);
|
||||
}
|
||||
|
||||
internal List<MethodItem> GetAllMethodItem()
|
||||
{
|
||||
List<MethodItem> mTs = new List<MethodItem>();
|
||||
foreach (var item in tokenToMethodItem.Values)
|
||||
{
|
||||
mTs.Add(item);
|
||||
}
|
||||
return mTs;
|
||||
}
|
||||
|
||||
private bool initialized;
|
||||
private TypeInitializeDic typeDic;
|
||||
|
||||
internal MethodItem GetMethodItem(string methodName)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
InitializedType(null);
|
||||
}
|
||||
if (this.methodKeyToMethodItem != null && this.methodKeyToMethodItem.ContainsKey(methodName))
|
||||
{
|
||||
return this.methodKeyToMethodItem[methodName];
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RRQMRPCException("方法初始化失败");
|
||||
}
|
||||
}
|
||||
|
||||
internal void InitializedType(TypeInitializeDic typeDic)
|
||||
{
|
||||
this.typeDic = typeDic;
|
||||
foreach (MethodItem item in this.methodKeyToMethodItem.Values)
|
||||
{
|
||||
if (item.ReturnTypeString != null)
|
||||
{
|
||||
item.ReturnType = this.MethodGetType(item.ReturnTypeString);
|
||||
}
|
||||
|
||||
item.ParameterTypes = new List<Type>();
|
||||
if (item.ParameterTypesString != null)
|
||||
{
|
||||
for (int i = 0; i < item.ParameterTypesString.Count; i++)
|
||||
{
|
||||
item.ParameterTypes.Add(this.MethodGetType(item.ParameterTypesString[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
private Type MethodGetType(string typeName)
|
||||
{
|
||||
if (this.typeDic != null && typeDic.ContainsKey(typeName))
|
||||
{
|
||||
return this.typeDic[typeName];
|
||||
}
|
||||
Type type = Type.GetType(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
type = assembly.GetType(typeName);
|
||||
if (type != null)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
if (type == null)
|
||||
{
|
||||
throw new RRQMRPCException($"RPC初始化时找不到{typeName}的类型");
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private string GetAssemblyName(string typeName)
|
||||
{
|
||||
int index = typeName.LastIndexOf(".");
|
||||
return typeName.Substring(0, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
316
RRQMSocket.RPC/RRQMRPC/Control/PropertyCodeMap.cs
Normal file
316
RRQMSocket.RPC/RRQMRPC/Control/PropertyCodeMap.cs
Normal file
@@ -0,0 +1,316 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 代码辅助类
|
||||
/// </summary>
|
||||
public class PropertyCodeMap
|
||||
{
|
||||
private static readonly string[] listType = { "List`1", "HashSet`1", "IList`1", "ISet`1", "ICollection`1", "IEnumerable`1" };
|
||||
|
||||
private static readonly string[] dicType = { "Dictionary`2", "IDictionary`2" };
|
||||
|
||||
private static readonly Type intType = typeof(int);
|
||||
private static readonly Type byteType = typeof(byte);
|
||||
private static readonly Type shortType = typeof(short);
|
||||
private static readonly Type longType = typeof(long);
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public PropertyCodeMap(Assembly assembly, string nameSpace)
|
||||
{
|
||||
this.Assembly = assembly;
|
||||
codeString = new StringBuilder();
|
||||
this.nameSpace = nameSpace;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所属程序集
|
||||
/// </summary>
|
||||
public Assembly Assembly { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取属性代码
|
||||
/// </summary>
|
||||
public string GetPropertyCode()
|
||||
{
|
||||
codeString.Clear();
|
||||
|
||||
codeString.AppendLine("using System;");
|
||||
codeString.AppendLine("using RRQMSocket.RPC;");
|
||||
codeString.AppendLine("using RRQMCore.Exceptions;");
|
||||
codeString.AppendLine("using System.Collections.Generic;");
|
||||
codeString.AppendLine("using System.Diagnostics;");
|
||||
codeString.AppendLine("using System.Text;");
|
||||
codeString.AppendLine("using System.Threading.Tasks;");
|
||||
|
||||
codeString.AppendLine(string.Format("namespace {0}", nameSpace));
|
||||
|
||||
codeString.AppendLine("{");
|
||||
foreach (var item in propertyDic.Values)
|
||||
{
|
||||
codeString.AppendLine(item);
|
||||
}
|
||||
codeString.AppendLine("}");
|
||||
return codeString.ToString();
|
||||
}
|
||||
|
||||
private StringBuilder codeString;
|
||||
private string nameSpace;
|
||||
private Dictionary<Type, string> propertyDic = new Dictionary<Type, string>();
|
||||
private Dictionary<Type, string> genericTypeDic = new Dictionary<Type, string>();
|
||||
|
||||
internal void AddTypeString(Type type)
|
||||
{
|
||||
if (type.IsByRef)
|
||||
{
|
||||
string typeName = type.FullName.Replace("&", string.Empty);
|
||||
type = Type.GetType(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
type = this.Assembly.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
if (!type.IsPrimitive && type != typeof(string))
|
||||
{
|
||||
if (type.IsArray)
|
||||
{
|
||||
AddTypeString(type.GetElementType());
|
||||
}
|
||||
else if (type.IsGenericType)
|
||||
{
|
||||
Type[] types = type.GetGenericArguments();
|
||||
foreach (Type itemType in types)
|
||||
{
|
||||
AddTypeString(itemType);
|
||||
}
|
||||
|
||||
if (listType.Contains(type.Name))
|
||||
{
|
||||
string typeInnerString = this.GetTypeFullName(types[0]);
|
||||
string typeString = $"{type.Name.Replace("`1", string.Empty)}<{typeInnerString}>";
|
||||
if (!genericTypeDic.ContainsKey(type))
|
||||
{
|
||||
genericTypeDic.Add(type, typeString);
|
||||
}
|
||||
}
|
||||
else if (dicType.Contains(type.Name))
|
||||
{
|
||||
string keyString = this.GetTypeFullName(types[0]);
|
||||
string valueString = this.GetTypeFullName(types[1]);
|
||||
string typeString = $"{type.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>";
|
||||
if (!genericTypeDic.ContainsKey(type))
|
||||
{
|
||||
genericTypeDic.Add(type, typeString);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type.IsInterface || type.IsAbstract)
|
||||
{
|
||||
throw new RRQMRPCException("服务参数类型不允许接口或抽象类");
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
{
|
||||
Type baseType = Enum.GetUnderlyingType(type);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (baseType == byteType)
|
||||
{
|
||||
stringBuilder.AppendLine($"public enum {type.Name}:byte");
|
||||
stringBuilder.AppendLine("{");
|
||||
Array array = Enum.GetValues(type);
|
||||
foreach (object item in array)
|
||||
{
|
||||
string enumString = item.ToString();
|
||||
stringBuilder.AppendLine($"{enumString}={(byte)item},");
|
||||
}
|
||||
}
|
||||
else if (baseType == shortType)
|
||||
{
|
||||
stringBuilder.AppendLine($"public enum {type.Name}:short");
|
||||
stringBuilder.AppendLine("{");
|
||||
Array array = Enum.GetValues(type);
|
||||
foreach (object item in array)
|
||||
{
|
||||
string enumString = item.ToString();
|
||||
stringBuilder.AppendLine($"{enumString}={(short)item},");
|
||||
}
|
||||
}
|
||||
else if (baseType == intType)
|
||||
{
|
||||
stringBuilder.AppendLine($"public enum {type.Name}:int");
|
||||
stringBuilder.AppendLine("{");
|
||||
Array array = Enum.GetValues(type);
|
||||
foreach (object item in array)
|
||||
{
|
||||
string enumString = item.ToString();
|
||||
stringBuilder.AppendLine($"{enumString}={(int)item},");
|
||||
}
|
||||
}
|
||||
else if (baseType == longType)
|
||||
{
|
||||
stringBuilder.AppendLine($"public enum {type.Name}:long");
|
||||
stringBuilder.AppendLine("{");
|
||||
Array array = Enum.GetValues(type);
|
||||
foreach (object item in array)
|
||||
{
|
||||
string enumString = item.ToString();
|
||||
stringBuilder.AppendLine($"{enumString}={(long)item},");
|
||||
}
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine("}");
|
||||
if (!propertyDic.ContainsKey(type))
|
||||
{
|
||||
propertyDic.Add(type, stringBuilder.ToString());
|
||||
}
|
||||
}
|
||||
else if (type.IsClass)
|
||||
{
|
||||
if (type.Assembly == this.Assembly)
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
stringBuilder.AppendLine("");
|
||||
stringBuilder.AppendLine($"public class {type.Name}");
|
||||
if (type.BaseType != typeof(object))
|
||||
{
|
||||
AddTypeString(type.BaseType);
|
||||
if (type.BaseType.IsGenericType)
|
||||
{
|
||||
Type[] types = type.BaseType.GetGenericArguments();
|
||||
foreach (Type itemType in types)
|
||||
{
|
||||
AddTypeString(itemType);
|
||||
}
|
||||
if (listType.Contains(type.BaseType.Name))
|
||||
{
|
||||
string typeString = this.GetTypeFullName(types[0]);
|
||||
stringBuilder.Append($":{type.BaseType.Name.Replace("`1", string.Empty)}<{typeString}>");
|
||||
}
|
||||
else if (dicType.Contains(type.BaseType.Name))
|
||||
{
|
||||
string keyString = this.GetTypeFullName(types[0]);
|
||||
string valueString = this.GetTypeFullName(types[1]);
|
||||
stringBuilder.Append($": {type.BaseType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}>");
|
||||
}
|
||||
}
|
||||
else if (type.BaseType.IsClass)
|
||||
{
|
||||
stringBuilder.AppendLine($": {this.GetTypeFullName(type.BaseType)}");
|
||||
}
|
||||
}
|
||||
stringBuilder.AppendLine("{");
|
||||
PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.GetProperty | BindingFlags.SetProperty);
|
||||
|
||||
foreach (PropertyInfo itemProperty in propertyInfos)
|
||||
{
|
||||
AddTypeString(itemProperty.PropertyType);
|
||||
if (propertyDic.ContainsKey(itemProperty.PropertyType))
|
||||
{
|
||||
stringBuilder.Append($"public {itemProperty.PropertyType.Name} {itemProperty.Name}");
|
||||
}
|
||||
else if (itemProperty.PropertyType.IsGenericType)
|
||||
{
|
||||
Type[] types = itemProperty.PropertyType.GetGenericArguments();
|
||||
foreach (Type itemType in types)
|
||||
{
|
||||
AddTypeString(itemType);
|
||||
}
|
||||
|
||||
if (listType.Contains(itemProperty.PropertyType.Name))
|
||||
{
|
||||
string typeString = this.GetTypeFullName(types[0]);
|
||||
stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`1", string.Empty)}<{typeString}> {itemProperty.Name}");
|
||||
}
|
||||
else if (dicType.Contains(itemProperty.PropertyType.Name))
|
||||
{
|
||||
string keyString = this.GetTypeFullName(types[0]);
|
||||
string valueString = this.GetTypeFullName(types[1]);
|
||||
stringBuilder.Append($"public {itemProperty.PropertyType.Name.Replace("`2", string.Empty)}<{keyString},{valueString}> {itemProperty.Name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddTypeString(itemProperty.PropertyType);
|
||||
stringBuilder.Append($"public {itemProperty.PropertyType.FullName} {itemProperty.Name}");
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine("{get;set;}");
|
||||
}
|
||||
|
||||
stringBuilder.AppendLine("}");
|
||||
|
||||
if (!propertyDic.ContainsKey(type))
|
||||
{
|
||||
propertyDic.Add(type, stringBuilder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取类型全名
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public string GetTypeFullName(Type type)
|
||||
{
|
||||
if (type.FullName == null)
|
||||
{
|
||||
return type.Name.Replace("&", string.Empty);
|
||||
}
|
||||
else if (type == typeof(void))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type.IsByRef)
|
||||
{
|
||||
string typeName = type.FullName.Replace("&", string.Empty);
|
||||
type = Type.GetType(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
type = this.Assembly.GetType(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.IsPrimitive || type == typeof(string))
|
||||
{
|
||||
return type.FullName;
|
||||
}
|
||||
else if (listType.Contains(type.Name) || dicType.Contains(type.Name))
|
||||
{
|
||||
return genericTypeDic[type];
|
||||
}
|
||||
else if (propertyDic.ContainsKey(type))
|
||||
{
|
||||
return this.nameSpace + "." + type.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return type.FullName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
126
RRQMSocket.RPC/RRQMRPC/Control/RPCContext.cs
Normal file
126
RRQMSocket.RPC/RRQMRPC/Control/RPCContext.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Run;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC传输类
|
||||
/// </summary>
|
||||
public class RPCContext : WaitResult
|
||||
{
|
||||
internal int MethodToken;
|
||||
internal byte Feedback;
|
||||
internal byte[] ReturnParameterBytes;
|
||||
internal object Flag;
|
||||
internal List<byte[]> ParametersBytes;
|
||||
|
||||
internal void Serialize(ByteBlock byteBlock)
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(this.Sign));
|
||||
byteBlock.Write(this.Status);
|
||||
byteBlock.Write(this.Feedback);
|
||||
byteBlock.Write(BitConverter.GetBytes(this.MethodToken));
|
||||
if (this.Message != null)
|
||||
{
|
||||
byte[] mesBytes = Encoding.UTF8.GetBytes(this.Message);
|
||||
byteBlock.Write((byte)mesBytes.Length);
|
||||
byteBlock.Write(mesBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write(0);
|
||||
}
|
||||
|
||||
|
||||
if (this.ReturnParameterBytes != null)
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(this.ReturnParameterBytes.Length));
|
||||
byteBlock.Write(this.ReturnParameterBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(0));
|
||||
}
|
||||
|
||||
if (this.ParametersBytes != null)
|
||||
{
|
||||
byteBlock.Write((byte)this.ParametersBytes.Count);
|
||||
foreach (byte[] item in this.ParametersBytes)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(item.Length));
|
||||
byteBlock.Write(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write(0);
|
||||
}
|
||||
}
|
||||
|
||||
internal static RPCContext Deserialize(byte[] buffer, int offset)
|
||||
{
|
||||
RPCContext context = new RPCContext();
|
||||
context.Sign = BitConverter.ToInt32(buffer, offset);
|
||||
offset += 4;
|
||||
context.Status = buffer[offset];
|
||||
offset += 1;
|
||||
context.Feedback = buffer[offset];
|
||||
offset += 1;
|
||||
context.MethodToken = BitConverter.ToInt32(buffer, offset);
|
||||
offset += 4;
|
||||
int lenMes = buffer[offset];
|
||||
offset += 1;
|
||||
context.Message = Encoding.UTF8.GetString(buffer, offset, lenMes);
|
||||
offset += lenMes;
|
||||
int lenRet = BitConverter.ToInt32(buffer, offset);
|
||||
offset += 4;
|
||||
if (lenRet > 0)
|
||||
{
|
||||
context.ReturnParameterBytes = new byte[lenRet];
|
||||
Array.Copy(buffer, offset, context.ReturnParameterBytes, 0, lenRet);
|
||||
}
|
||||
offset += lenRet;
|
||||
context.ParametersBytes = new List<byte[]>();
|
||||
int countPar = buffer[offset];
|
||||
offset += 1;
|
||||
for (int i = 0; i < countPar; i++)
|
||||
{
|
||||
int lenPar = BitConverter.ToInt32(buffer, offset);
|
||||
offset += 4;
|
||||
if (lenPar > 0)
|
||||
{
|
||||
byte[] datas = new byte[lenPar];
|
||||
Array.Copy(buffer, offset, datas, 0, lenPar);
|
||||
offset += lenPar;
|
||||
context.ParametersBytes.Add(datas);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ParametersBytes.Add(null);
|
||||
}
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
RRQMSocket.RPC/RRQMRPC/Control/RPCProxyInfo.cs
Normal file
47
RRQMSocket.RPC/RRQMRPC/Control/RPCProxyInfo.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// RPC代理文件程序
|
||||
/// </summary>
|
||||
|
||||
public class RPCProxyInfo : WaitResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 程序名
|
||||
/// </summary>
|
||||
public string AssemblyName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据
|
||||
/// </summary>
|
||||
public byte[] AssemblyData { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 版本号
|
||||
/// </summary>
|
||||
public string Version { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 源代码
|
||||
/// </summary>
|
||||
public List<CellCode> Codes { get; internal set; }
|
||||
}
|
||||
}
|
||||
32
RRQMSocket.RPC/RRQMRPC/Control/SupportProtocol.cs
Normal file
32
RRQMSocket.RPC/RRQMRPC/Control/SupportProtocol.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC支持协议
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum SupportProtocol
|
||||
{
|
||||
/// <summary>
|
||||
/// TCP协议
|
||||
/// </summary>
|
||||
TCP = 1,
|
||||
|
||||
/// <summary>
|
||||
/// UDP协议
|
||||
/// </summary>
|
||||
UDP = 2
|
||||
}
|
||||
}
|
||||
23
RRQMSocket.RPC/RRQMRPC/Control/TypeInitializeDic.cs
Normal file
23
RRQMSocket.RPC/RRQMRPC/Control/TypeInitializeDic.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化类型字典
|
||||
/// </summary>
|
||||
public class TypeInitializeDic : Dictionary<string, Type>
|
||||
{
|
||||
}
|
||||
}
|
||||
20
RRQMSocket.RPC/RRQMRPC/Control/WaitBytes.cs
Normal file
20
RRQMSocket.RPC/RRQMRPC/Control/WaitBytes.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RRQMRPC
|
||||
{
|
||||
internal class WaitBytes : WaitResult
|
||||
{
|
||||
internal byte[] Bytes;
|
||||
}
|
||||
}
|
||||
52
RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCKeyException.cs
Normal file
52
RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCKeyException.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RPC.RRQMRPC
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// RPC添加方法键异常
|
||||
/// </summary>
|
||||
|
||||
public class RRQMRPCKeyException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RRQMRPCKeyException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMRPCKeyException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMRPCKeyException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMRPCKeyException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
47
RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCNoFreeException.cs
Normal file
47
RRQMSocket.RPC/RRQMRPC/Exceptions/RRQMRPCNoFreeException.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 无可用RPC异常
|
||||
/// </summary>
|
||||
public class RRQMRPCNoFreeException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RRQMRPCNoFreeException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMRPCNoFreeException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMRPCNoFreeException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMRPCNoFreeException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 序列化异常类
|
||||
/// </summary>
|
||||
public class RRQMSerializationException : RRQMException
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public RRQMSerializationException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public RRQMSerializationException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="inner"></param>
|
||||
public RRQMSerializationException(string message, System.Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
protected RRQMSerializationException(System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
}
|
||||
98
RRQMSocket.RPC/RRQMRPC/Interface/IRPCClient.cs
Normal file
98
RRQMSocket.RPC/RRQMRPC/Interface/IRPCClient.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Log;
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端RPC接口
|
||||
/// </summary>
|
||||
public interface IRPCClient : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 收到ByteBlock时触发
|
||||
/// </summary>
|
||||
event RRQMByteBlockEventHandler ReceivedByteBlock;
|
||||
|
||||
/// <summary>
|
||||
/// 收到字节数组并返回
|
||||
/// </summary>
|
||||
event RRQMBytesEventHandler ReceivedBytesThenReturn;
|
||||
|
||||
/// <summary>
|
||||
/// 获取ID
|
||||
/// </summary>
|
||||
string ID { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
ILog Logger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存池实例
|
||||
/// </summary>
|
||||
BytePool BytePool { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 序列化生成器
|
||||
/// </summary>
|
||||
SerializeConverter SerializeConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取远程服务器RPC服务文件
|
||||
/// </summary>
|
||||
/// <param name="ipHost">IP和端口</param>
|
||||
/// <param name="verifyToken">连接验证</param>
|
||||
/// <param name="proxyToken">代理令箭</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="RRQMRPCException"></exception>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
RPCProxyInfo GetProxyInfo(string ipHost, string verifyToken = null, string proxyToken = null);
|
||||
|
||||
/// <summary>
|
||||
/// 初始化RPC
|
||||
/// </summary>
|
||||
/// <param name="ipHost"></param>
|
||||
/// <param name="verifyToken"></param>
|
||||
/// <param name="typeDic"></param>
|
||||
void InitializedRPC(string ipHost, string verifyToken = null, TypeInitializeDic typeDic = null);
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">函数名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption">RPC调用设置</param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
void RPCInvoke(string method, ref object[] parameters, InvokeOption invokeOption);
|
||||
|
||||
/// <summary>
|
||||
/// 函数式调用
|
||||
/// </summary>
|
||||
/// <param name="method">方法名</param>
|
||||
/// <param name="parameters">参数</param>
|
||||
/// <param name="invokeOption">RPC调用设置</param>
|
||||
/// <exception cref="RRQMTimeoutException"></exception>
|
||||
/// <exception cref="RRQMSerializationException"></exception>
|
||||
/// <exception cref="RRQMRPCInvokeException"></exception>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <returns>服务器返回结果</returns>
|
||||
T RPCInvoke<T>(string method, ref object[] parameters, InvokeOption invokeOption);
|
||||
}
|
||||
}
|
||||
306
RRQMSocket.RPC/RRQMRPC/Parser/RRQMRPCParser.cs
Normal file
306
RRQMSocket.RPC/RRQMRPC/Parser/RRQMRPCParser.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RRQM内置解析器
|
||||
/// </summary>
|
||||
public abstract class RRQMRPCParser : RPCParser, IService
|
||||
{
|
||||
private MethodStore clientMethodStore;
|
||||
|
||||
/// <summary>
|
||||
/// 序列化转换器
|
||||
/// </summary>
|
||||
public SerializeConverter SerializeConverter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置代理源文件命名空间
|
||||
/// </summary>
|
||||
public string NameSpace { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RPC代理版本
|
||||
/// </summary>
|
||||
public Version RPCVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// RPC编译器
|
||||
/// </summary>
|
||||
public IRPCCompiler RPCCompiler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取生成的代理代码
|
||||
/// </summary>
|
||||
public CellCode[] Codes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代理令箭,当客户端获取代理文件时需验证令箭
|
||||
/// </summary>
|
||||
public string ProxyToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取代理文件实例
|
||||
/// </summary>
|
||||
public RPCProxyInfo ProxyInfo { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取绑定状态
|
||||
/// </summary>
|
||||
public abstract bool IsBind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 内存池实例
|
||||
/// </summary>
|
||||
public abstract BytePool BytePool { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化服务
|
||||
/// </summary>
|
||||
/// <param name="methodInstances"></param>
|
||||
protected sealed override void InitializeServers(MethodInstance[] methodInstances)
|
||||
{
|
||||
|
||||
this.clientMethodStore = new MethodStore();
|
||||
string nameSpace = string.IsNullOrEmpty(this.NameSpace) ? "RRQMRPC" : $"RRQMRPC.{this.NameSpace}";
|
||||
List<string> refs = new List<string>();
|
||||
|
||||
PropertyCodeMap propertyCode = new PropertyCodeMap(this.RPCService.ServerProviders.SingleAssembly, nameSpace);
|
||||
string assemblyName = $"{nameSpace}.dll";
|
||||
|
||||
|
||||
foreach (MethodInstance methodInstance in methodInstances)
|
||||
{
|
||||
foreach (RPCMethodAttribute att in methodInstance.RPCAttributes)
|
||||
{
|
||||
if (att is RRQMRPCMethodAttribute attribute)
|
||||
{
|
||||
if (methodInstance.ReturnType != null)
|
||||
{
|
||||
refs.Add(methodInstance.ReturnType.Assembly.Location);
|
||||
propertyCode.AddTypeString(methodInstance.ReturnType);
|
||||
}
|
||||
foreach (var type in methodInstance.ParameterTypes)
|
||||
{
|
||||
refs.Add(type.Assembly.Location);
|
||||
propertyCode.AddTypeString(type);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<string, List<MethodInfo>> classAndMethods = new Dictionary<string, List<MethodInfo>>();
|
||||
|
||||
foreach (MethodInstance methodInstance in methodInstances)
|
||||
{
|
||||
foreach (RPCMethodAttribute att in methodInstance.RPCAttributes)
|
||||
{
|
||||
if (att is RRQMRPCMethodAttribute attribute)
|
||||
{
|
||||
MethodItem methodItem = new MethodItem();
|
||||
methodItem.IsOutOrRef = methodInstance.IsByRef;
|
||||
methodItem.MethodToken = methodInstance.MethodToken;
|
||||
if (methodInstance.ReturnType != null)
|
||||
{
|
||||
methodItem.ReturnTypeString = propertyCode.GetTypeFullName(methodInstance.ReturnType);
|
||||
}
|
||||
|
||||
methodItem.ParameterTypesString = new List<string>();
|
||||
methodItem.Method = attribute.MethodKey == null || attribute.MethodKey.Trim().Length == 0 ? methodInstance.Method.Name : attribute.MethodKey;
|
||||
|
||||
for (int i = 0; i < methodInstance.ParameterTypes.Length; i++)
|
||||
{
|
||||
methodItem.ParameterTypesString.Add(propertyCode.GetTypeFullName(methodInstance.ParameterTypes[i]));
|
||||
}
|
||||
try
|
||||
{
|
||||
clientMethodStore.AddMethodItem(methodItem);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new RRQMRPCKeyException($"方法键为{methodItem.Method}的服务已注册");
|
||||
}
|
||||
|
||||
|
||||
string className = methodInstance.Provider.GetType().Name;
|
||||
if (!classAndMethods.ContainsKey(className))
|
||||
{
|
||||
classAndMethods.Add(className, new List<MethodInfo>());
|
||||
}
|
||||
classAndMethods[className].Add(methodInstance.Method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CodeMap.Namespace = nameSpace;
|
||||
CodeMap.PropertyCode = propertyCode;
|
||||
List<CellCode> codes = new List<CellCode>();
|
||||
//codes.Add(CodeMap.GetAssemblyInfo(nameSpace, setting.Version));
|
||||
|
||||
foreach (string className in classAndMethods.Keys)
|
||||
{
|
||||
CodeMap codeMap = new CodeMap();
|
||||
codeMap.ClassName = className;
|
||||
codeMap.Methods = classAndMethods[className].ToArray();
|
||||
|
||||
CellCode cellCode = new CellCode();
|
||||
cellCode.Name = className;
|
||||
cellCode.CodeType = CodeType.Service;
|
||||
cellCode.Code = codeMap.GetCode();
|
||||
codes.Add(cellCode);
|
||||
}
|
||||
CellCode propertyCellCode = new CellCode();
|
||||
propertyCellCode.Name = "ClassArgs";
|
||||
propertyCellCode.CodeType = CodeType.ClassArgs;
|
||||
propertyCellCode.Code = propertyCode.GetPropertyCode();
|
||||
codes.Add(propertyCellCode);
|
||||
string assemblyInfo = CodeMap.GetAssemblyInfo(nameSpace, this.RPCVersion);
|
||||
this.RPCVersion = CodeMap.Version;
|
||||
|
||||
RPCProxyInfo proxyInfo = new RPCProxyInfo();
|
||||
proxyInfo.AssemblyName = assemblyName;
|
||||
proxyInfo.Version = this.RPCVersion.ToString();
|
||||
if (this.RPCCompiler != null)
|
||||
{
|
||||
List<string> codesString = new List<string>();
|
||||
foreach (var item in codes)
|
||||
{
|
||||
codesString.Add(item.Code);
|
||||
}
|
||||
codesString.Add(assemblyInfo);
|
||||
proxyInfo.AssemblyData = this.RPCCompiler.CompileCode(assemblyName, codesString.ToArray(), refs);
|
||||
}
|
||||
proxyInfo.Codes = codes;
|
||||
this.ProxyInfo = proxyInfo;
|
||||
|
||||
this.Codes = codes.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取代理文件
|
||||
/// </summary>
|
||||
/// <param name="proxyToken"></param>
|
||||
/// <param name="parser"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual RPCProxyInfo GetProxyInfo(string proxyToken, RPCParser parser)
|
||||
{
|
||||
RPCProxyInfo proxyInfo = new RPCProxyInfo();
|
||||
if (this.ProxyToken == proxyToken)
|
||||
{
|
||||
proxyInfo.AssemblyData = this.ProxyInfo.AssemblyData;
|
||||
proxyInfo.AssemblyName = this.ProxyInfo.AssemblyName;
|
||||
proxyInfo.Codes = this.ProxyInfo.Codes;
|
||||
proxyInfo.Version = this.ProxyInfo.Version;
|
||||
proxyInfo.Status = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
proxyInfo.Status = 2;
|
||||
proxyInfo.Message = "令箭不正确";
|
||||
}
|
||||
|
||||
return proxyInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行内容
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
protected virtual void ExecuteContext(RPCContext context)
|
||||
{
|
||||
MethodInvoker methodInvoker = new MethodInvoker();
|
||||
methodInvoker.Flag = context;
|
||||
if (this.MethodMap.TryGet(context.MethodToken, out MethodInstance methodInstance))
|
||||
{
|
||||
if (methodInstance.IsEnable)
|
||||
{
|
||||
object[] ps = new object[methodInstance.ParameterTypes.Length];
|
||||
for (int i = 0; i < context.ParametersBytes.Count; i++)
|
||||
{
|
||||
ps[i] = this.SerializeConverter.DeserializeParameter(context.ParametersBytes[i], methodInstance.ParameterTypes[i]);
|
||||
}
|
||||
methodInvoker.Parameters = ps;
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnEnable;
|
||||
}
|
||||
|
||||
this.ExecuteMethod(methodInvoker, methodInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
methodInvoker.Status = InvokeStatus.UnFound;
|
||||
this.ExecuteMethod(methodInvoker, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取已注册服务条目
|
||||
/// </summary>
|
||||
/// <param name="parser"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual List<MethodItem> GetRegisteredMethodItems(RPCParser parser)
|
||||
{
|
||||
return this.clientMethodStore.GetAllMethodItem();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="port">端口号</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public abstract void Bind(int port, int threadCount = 1);
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="iPHost">ip和端口号,格式如“127.0.0.1:7789”。IP可输入Ipv6</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public abstract void Bind(IPHost iPHost, int threadCount);
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="addressFamily">寻址方案</param>
|
||||
/// <param name="endPoint">绑定节点</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public abstract void Bind(AddressFamily addressFamily, EndPoint endPoint, int threadCount);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
286
RRQMSocket.RPC/RRQMRPC/Parser/TcpRPCParser.cs
Normal file
286
RRQMSocket.RPC/RRQMRPC/Parser/TcpRPCParser.cs
Normal file
@@ -0,0 +1,286 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Log;
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// TCP RPC解释器
|
||||
/// </summary>
|
||||
public sealed class TcpRPCParser : RRQMRPCParser
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public TcpRPCParser()
|
||||
{
|
||||
this.SerializeConverter = new BinarySerializeConverter();
|
||||
this.tcpService = new TokenTcpService<RPCSocketClient>();
|
||||
this.tcpService.CreatSocketCliect += this.TcpService_CreatSocketCliect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置日志记录器
|
||||
/// </summary>
|
||||
public ILog Logger { get { return this.tcpService.Logger; } set { this.tcpService.Logger = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取通信实例
|
||||
/// </summary>
|
||||
public TokenTcpService<RPCSocketClient> Service => this.tcpService;
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存池实例
|
||||
/// </summary>
|
||||
public override sealed BytePool BytePool { get { return this.tcpService.BytePool; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置缓存大小
|
||||
/// </summary>
|
||||
public int BufferLength { get { return this.tcpService.BufferLength; } set { this.tcpService.BufferLength = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取绑定状态
|
||||
/// </summary>
|
||||
public override bool IsBind => this.tcpService.IsBind;
|
||||
|
||||
private void TcpService_CreatSocketCliect(RPCSocketClient tcpSocketClient, CreatOption creatOption)
|
||||
{
|
||||
if (creatOption.NewCreat)
|
||||
{
|
||||
tcpSocketClient.Logger = this.Logger;
|
||||
tcpSocketClient.DataHandlingAdapter = new FixedHeaderDataHandlingAdapter();
|
||||
tcpSocketClient.OnReceivedRequest += this.TcpSocketClient_OnReceivedRequest;
|
||||
}
|
||||
tcpSocketClient.agreementHelper = new RRQMAgreementHelper(tcpSocketClient);
|
||||
}
|
||||
|
||||
private TokenTcpService<RPCSocketClient> tcpService;
|
||||
|
||||
private void TcpSocketClient_OnReceivedRequest(object sender, ByteBlock byteBlock)
|
||||
{
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
int r = (int)byteBlock.Position;
|
||||
int agreement = BitConverter.ToInt32(buffer, 0);
|
||||
|
||||
switch (agreement)
|
||||
{
|
||||
case 100:/*100,请求RPC文件*/
|
||||
{
|
||||
try
|
||||
{
|
||||
RPCSocketClient socketClient = (RPCSocketClient)sender;
|
||||
string proxyToken = null;
|
||||
if (r - 4 > 0)
|
||||
{
|
||||
proxyToken = Encoding.UTF8.GetString(buffer, 4, r - 4);
|
||||
}
|
||||
socketClient.agreementHelper.SocketSend(100, SerializeConvert.RRQMBinarySerialize(this.GetProxyInfo(proxyToken, this), true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 100, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 101:/*函数式调用*/
|
||||
{
|
||||
try
|
||||
{
|
||||
RPCContext content = RPCContext.Deserialize(buffer, 4);
|
||||
content.Flag = sender;
|
||||
this.ExecuteContext(content);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 101, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 102:/*连接初始化*/
|
||||
{
|
||||
try
|
||||
{
|
||||
((RPCSocketClient)sender).agreementHelper.SocketSend(102, SerializeConvert.RRQMBinarySerialize(this.GetRegisteredMethodItems(this), true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 110:/*函数式调用返回*/
|
||||
{
|
||||
try
|
||||
{
|
||||
((RPCSocketClient)sender).Agreement_110(buffer, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 110, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在调用结束后调用
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected override void EndInvokeMethod(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
RPCContext context = (RPCContext)methodInvoker.Flag;
|
||||
if (context.Feedback == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
switch (methodInvoker.Status)
|
||||
{
|
||||
case InvokeStatus.Ready:
|
||||
{
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case InvokeStatus.UnFound:
|
||||
{
|
||||
context.Status = 2;
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Success:
|
||||
{
|
||||
if (methodInstance.MethodToken > 50000000)
|
||||
{
|
||||
context.ReturnParameterBytes = this.SerializeConverter.SerializeParameter(methodInvoker.ReturnParameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ReturnParameterBytes = null;
|
||||
}
|
||||
|
||||
if (methodInstance.IsByRef)
|
||||
{
|
||||
context.ParametersBytes = new List<byte[]>();
|
||||
foreach (var item in methodInvoker.Parameters)
|
||||
{
|
||||
context.ParametersBytes.Add(this.SerializeConverter.SerializeParameter(item));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.ParametersBytes = null;
|
||||
}
|
||||
|
||||
context.Status = 1;
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Abort:
|
||||
{
|
||||
context.Status = 4;
|
||||
context.Message = methodInvoker.StatusMessage;
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.UnEnable:
|
||||
{
|
||||
context.Status = 3;
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.InvocationException:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case InvokeStatus.Exception:
|
||||
{
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
context.Serialize(byteBlock);
|
||||
((RPCSocketClient)context.Flag).agreementHelper.SocketSend(101, byteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="port">端口号</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override void Bind(int port, int threadCount = 1)
|
||||
{
|
||||
this.tcpService.Bind(port,threadCount);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="iPHost">ip和端口号,格式如“127.0.0.1:7789”。IP可输入Ipv6</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override void Bind(IPHost iPHost, int threadCount)
|
||||
{
|
||||
this.tcpService.Bind(iPHost, threadCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="addressFamily">寻址方案</param>
|
||||
/// <param name="endPoint">绑定节点</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override void Bind(AddressFamily addressFamily, EndPoint endPoint, int threadCount)
|
||||
{
|
||||
this.tcpService.Bind(addressFamily, endPoint, threadCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
this.tcpService.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
200
RRQMSocket.RPC/RRQMRPC/Parser/UdpRPCParser.cs
Normal file
200
RRQMSocket.RPC/RRQMRPC/Parser/UdpRPCParser.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Log;
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// UDP RPC解释器
|
||||
/// </summary>
|
||||
public class UdpRPCParser : RRQMRPCParser,IService
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public UdpRPCParser()
|
||||
{
|
||||
this.udpSession = new RRQMUdpSession();
|
||||
this.udpSession.OnReceivedData += this.UdpSession_OnReceivedData;
|
||||
}
|
||||
|
||||
private void UdpSession_OnReceivedData(EndPoint remoteEndpoint, ByteBlock byteBlock)
|
||||
{
|
||||
byte[] buffer = byteBlock.Buffer;
|
||||
int r = (int)byteBlock.Position;
|
||||
int agreement = BitConverter.ToInt32(buffer, 0);
|
||||
|
||||
switch (agreement)
|
||||
{
|
||||
case 100:/*100,请求RPC文件*/
|
||||
{
|
||||
try
|
||||
{
|
||||
string proxyToken = null;
|
||||
if (r - 4 > 0)
|
||||
{
|
||||
proxyToken = Encoding.UTF8.GetString(buffer, 4, r - 4);
|
||||
}
|
||||
this.UDPSend(100, remoteEndpoint, SerializeConvert.RRQMBinarySerialize(this.GetProxyInfo(proxyToken, this), true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"UDP错误代码: 100, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 101:/*函数式调用*/
|
||||
{
|
||||
try
|
||||
{
|
||||
RPCContext content = RPCContext.Deserialize(buffer, 4);
|
||||
content.Flag = remoteEndpoint;
|
||||
this.ExecuteContext(content);
|
||||
if (content.Feedback != 0)
|
||||
{
|
||||
this.UDPSend(101, remoteEndpoint, new byte[0]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"UDP错误代码: 101, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 102:/*连接初始化*/
|
||||
{
|
||||
try
|
||||
{
|
||||
UDPSend(102, remoteEndpoint, SerializeConvert.RRQMBinarySerialize(this.GetRegisteredMethodItems(this), true));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, $"错误代码: 102, 错误详情:{e.Message}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private RRQMUdpSession udpSession;
|
||||
|
||||
/// <summary>
|
||||
/// 获取通信实例
|
||||
/// </summary>
|
||||
public RRQMUdpSession Session => this.udpSession;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置日志记录仪
|
||||
/// </summary>
|
||||
public ILog Logger { get { return this.udpSession.Logger; } set { this.udpSession.Logger = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取绑定状态
|
||||
/// </summary>
|
||||
public override bool IsBind => this.udpSession.IsBind;
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存池实例
|
||||
/// </summary>
|
||||
public override BytePool BytePool => this.udpSession.BytePool;
|
||||
|
||||
/// <summary>
|
||||
/// 调用结束
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected override void EndInvokeMethod(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
private void UDPSend(int agreement, EndPoint endPoint, byte[] buffer, int offset, int length)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(length + 4);
|
||||
try
|
||||
{
|
||||
byteBlock.Write(BitConverter.GetBytes(agreement));
|
||||
byteBlock.Write(buffer, offset, length);
|
||||
this.udpSession.SendTo(byteBlock.Buffer, 0, (int)byteBlock.Length, endPoint);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void UDPSend(int agreement, EndPoint endPoint, byte[] buffer)
|
||||
{
|
||||
this.UDPSend(agreement, endPoint, buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="port">端口号</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override void Bind(int port, int threadCount = 1)
|
||||
{
|
||||
this.udpSession.Bind(port, threadCount);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="iPHost">ip和端口号,格式如“127.0.0.1:7789”。IP可输入Ipv6</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override void Bind(IPHost iPHost, int threadCount)
|
||||
{
|
||||
this.udpSession.Bind(iPHost, threadCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="addressFamily">寻址方案</param>
|
||||
/// <param name="endPoint">绑定节点</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public override void Bind(AddressFamily addressFamily, EndPoint endPoint, int threadCount)
|
||||
{
|
||||
this.udpSession.Bind(addressFamily, endPoint, threadCount);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
this.udpSession.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// 二进制序列化器,默认最大可序列化1K byte的大小
|
||||
/// </summary>
|
||||
public class BinarySerializeConverter : SerializeConverter
|
||||
{
|
||||
#pragma warning disable CS1591 // XML 注释跟随抽象类
|
||||
|
||||
public override object DeserializeParameter(byte[] parameterBytes, Type parameterType)
|
||||
{
|
||||
if (parameterBytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return SerializeConvert.RRQMBinaryDeserialize(parameterBytes, 0, parameterType);
|
||||
}
|
||||
|
||||
public override byte[] SerializeParameter(object parameter)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return SerializeConvert.RRQMBinarySerialize(parameter, true);
|
||||
}
|
||||
|
||||
#pragma warning restore CS1591
|
||||
}
|
||||
}
|
||||
40
RRQMSocket.RPC/RRQMRPC/Serialization/SerializeConverter.cs
Normal file
40
RRQMSocket.RPC/RRQMRPC/Serialization/SerializeConverter.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.RRQMRPC
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 序列化转换器
|
||||
/// </summary>
|
||||
public abstract class SerializeConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// 序列化RPC方法返回值参数
|
||||
/// </summary>
|
||||
/// <param name="parameter"></param>
|
||||
/// <returns></returns>
|
||||
public abstract byte[] SerializeParameter(object parameter);
|
||||
|
||||
/// <summary>
|
||||
/// 反序列化传输对象
|
||||
/// </summary>
|
||||
/// <param name="parameterBytes"></param>
|
||||
/// <param name="parameterType"></param>
|
||||
/// <returns></returns>
|
||||
public abstract object DeserializeParameter(byte[] parameterBytes, Type parameterType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// Xml序列化
|
||||
/// </summary>
|
||||
public class XmlSerializeConverter : SerializeConverter
|
||||
{
|
||||
#pragma warning disable CS1591 // XML 注释
|
||||
|
||||
public override object DeserializeParameter(byte[] parameterBytes, Type parameterType)
|
||||
{
|
||||
if (parameterBytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return SerializeConvert.XmlDeserializeFromBytes(parameterBytes, parameterType);
|
||||
}
|
||||
|
||||
public override byte[] SerializeParameter(object parameter)
|
||||
{
|
||||
if (parameter == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return SerializeConvert.XmlSerializeToBytes(parameter);
|
||||
}
|
||||
|
||||
#pragma warning restore CS1591
|
||||
}
|
||||
}
|
||||
107
RRQMSocket.RPC/RRQMRPC/Socket/RPCSocketClient .cs
Normal file
107
RRQMSocket.RPC/RRQMRPC/Socket/RPCSocketClient .cs
Normal file
@@ -0,0 +1,107 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Run;
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.RPC.RRQMRPC
|
||||
{
|
||||
/// <summary>
|
||||
/// RPC服务器辅助类
|
||||
/// </summary>
|
||||
public sealed class RPCSocketClient : TcpSocketClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public RPCSocketClient()
|
||||
{
|
||||
this.waitHandles = new RRQMWaitHandle<WaitBytes>();
|
||||
}
|
||||
|
||||
internal event RRQMByteBlockEventHandler OnReceivedRequest;
|
||||
|
||||
private RRQMWaitHandle<WaitBytes> waitHandles;
|
||||
internal RRQMAgreementHelper agreementHelper;
|
||||
|
||||
/// <summary>
|
||||
/// 等待字节返回
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="r"></param>
|
||||
internal void Agreement_110(byte[] buffer, int r)
|
||||
{
|
||||
WaitBytes waitBytes = SerializeConvert.RRQMBinaryDeserialize<WaitBytes>(buffer, 4);
|
||||
this.waitHandles.SetRun(waitBytes.Sign, waitBytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节并返回
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="waitTime"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] SendBytesWaitReturn(byte[] data, int waitTime = 3)
|
||||
{
|
||||
WaitData<WaitBytes> waitData = this.waitHandles.GetWaitData();
|
||||
waitData.WaitResult.Bytes = data;
|
||||
try
|
||||
{
|
||||
byte[] buffer = SerializeConvert.RRQMBinarySerialize(waitData.WaitResult, true);
|
||||
agreementHelper.SocketSend(110, buffer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RRQMRPCException(e.Message);
|
||||
}
|
||||
|
||||
waitData.Wait(waitTime * 1000);
|
||||
|
||||
waitData.Wait(waitTime * 1000);
|
||||
WaitBytes waitBytes = waitData.WaitResult;
|
||||
waitData.Dispose();
|
||||
|
||||
if (waitBytes.Status == 0)
|
||||
{
|
||||
throw new RRQMTimeoutException("等待结果超时");
|
||||
}
|
||||
else if (waitBytes.Status == 2)
|
||||
{
|
||||
throw new RRQMRPCException(waitBytes.Message);
|
||||
}
|
||||
|
||||
return waitBytes.Bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向RPC发送数据
|
||||
/// </summary>
|
||||
/// <param name="buffer"></param>
|
||||
/// <param name="offset"></param>
|
||||
/// <param name="length"></param>
|
||||
public override void Send(byte[] buffer, int offset, int length)
|
||||
{
|
||||
agreementHelper.SocketSend(111, buffer, offset, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理已接收到的数据
|
||||
/// </summary>
|
||||
/// <param name="byteBlock"></param>
|
||||
/// <param name="obj"></param>
|
||||
protected override void HandleReceivedData(ByteBlock byteBlock, object obj)
|
||||
{
|
||||
OnReceivedRequest?.Invoke(this, byteBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
RRQMSocket.RPC/RRQMSocket.RPC.csproj
Normal file
83
RRQMSocket.RPC/RRQMSocket.RPC.csproj
Normal file
@@ -0,0 +1,83 @@
|
||||
<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>1.0.0.0</Version>
|
||||
<Company>若汝棋茗</Company>
|
||||
<Copyright>Copyright © 2021 若汝棋茗</Copyright>
|
||||
<Description>
|
||||
更新时间:2021.04.02
|
||||
更新简介:RPC发布
|
||||
|
||||
RRQMSocket.RPC是一个轻量级RPC框架,支持TCP和UDP两种传输层协议调用。
|
||||
主要的特色功能:
|
||||
1.多线程工作。
|
||||
2.代码自动生成。
|
||||
3.支持多协议调用。
|
||||
4.支持ref、out返回。
|
||||
5.支持调用权限检测。
|
||||
6.支持调用异常反馈。
|
||||
7.支持回调。
|
||||
8.支持指定服务异步调用。
|
||||
9.性能卓著。
|
||||
在CanFeedback模式下,10w次调用用时3.8s。
|
||||
在NoFeedback模式下,10w次调用用时0.9s。
|
||||
性能非常卓著。
|
||||
|
||||
Demo:https://gitee.com/RRQM_Home/RRQMSocket.RPC.Demo
|
||||
</Description>
|
||||
<PackageProjectUrl>https://gitee.com/RRQM_Home/RRQMSocket.RPC</PackageProjectUrl>
|
||||
<PackageIconUrl></PackageIconUrl>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PackageIcon>RRQM.png</PackageIcon>
|
||||
<Authors>若汝棋茗</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<PackageTags>RPC;TCP;UDP;IOCP</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netstandard2.0\RRQMSocket.RPC.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netstandard2.0|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netstandard2.0\RRQMSocket.RPC.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net45\RRQMSocket.RPC.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net45|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\net45\RRQMSocket.RPC.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\netcoreapp3.1\RRQMSocket.RPC.xml</DocumentationFile>
|
||||
<OutputPath></OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|netcoreapp3.1|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp3.1\RRQMSocket.RPC.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>
|
||||
<ProjectReference Include="..\RRQMSocket.Http\RRQMSocket.Http.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
46
RRQMSocket.RPC/WebApi/Attribute/RouteAttribute.cs
Normal file
46
RRQMSocket.RPC/WebApi/Attribute/RouteAttribute.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 适用于WebApi的路由标记
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method|AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public sealed class RouteAttribute : RPCMethodAttribute
|
||||
{
|
||||
/// <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; }
|
||||
}
|
||||
}
|
||||
26
RRQMSocket.RPC/WebApi/Control/ControllerBase.cs
Normal file
26
RRQMSocket.RPC/WebApi/Control/ControllerBase.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// ControllerBase
|
||||
/// </summary>
|
||||
public abstract class ControllerBase:ServerProvider
|
||||
{
|
||||
}
|
||||
}
|
||||
53
RRQMSocket.RPC/WebApi/Control/RouteMap.cs
Normal file
53
RRQMSocket.RPC/WebApi/Control/RouteMap.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 路由映射图
|
||||
/// </summary>
|
||||
public class RouteMap
|
||||
{
|
||||
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>
|
||||
/// 通过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;
|
||||
}
|
||||
}
|
||||
}
|
||||
224
RRQMSocket.RPC/WebApi/Parser/WebApiParser.cs
Normal file
224
RRQMSocket.RPC/WebApi/Parser/WebApiParser.cs
Normal file
@@ -0,0 +1,224 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按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.Log;
|
||||
using RRQMSocket.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
|
||||
namespace RRQMSocket.RPC.WebApi
|
||||
{
|
||||
/// <summary>
|
||||
/// WebApi解析器
|
||||
/// </summary>
|
||||
public sealed class WebApiParser : RPCParser, IService
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public WebApiParser()
|
||||
{
|
||||
this.tcpService = new RRQMTcpService();
|
||||
this.routeMap = new RouteMap();
|
||||
this.tcpService.CreatSocketCliect += this.OnCreatSocketCliect;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在初次接收时
|
||||
/// </summary>
|
||||
/// <param name="socketClient"></param>
|
||||
/// <param name="creatOption"></param>
|
||||
private void OnCreatSocketCliect(RRQMSocketClient socketClient, CreatOption creatOption)
|
||||
{
|
||||
if (creatOption.NewCreat)
|
||||
{
|
||||
socketClient.DataHandlingAdapter = new Http.HttpDataHandlingAdapter(this.BufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private RouteMap routeMap;
|
||||
private RRQMTcpService tcpService;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前服务通信器
|
||||
/// </summary>
|
||||
public RRQMTcpService Service { get { return this.tcpService; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取绑定状态
|
||||
/// </summary>
|
||||
public bool IsBind => this.tcpService.IsBind;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置缓存大小
|
||||
/// </summary>
|
||||
public int BufferLength { get { return this.tcpService.BufferLength; } set { this.tcpService.BufferLength = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// 获取内存池实例
|
||||
/// </summary>
|
||||
public BytePool BytePool => this.tcpService.BytePool;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置日志记录器
|
||||
/// </summary>
|
||||
public ILog Logger { get { return this.tcpService.Logger; } set { this.tcpService.Logger = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="port">端口号</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Bind(int port, int threadCount = 1)
|
||||
{
|
||||
this.tcpService.Bind(port, threadCount);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="iPHost">ip和端口号,格式如“127.0.0.1:7789”。IP可输入Ipv6</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Bind(IPHost iPHost, int threadCount)
|
||||
{
|
||||
this.tcpService.Bind(iPHost, threadCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定服务
|
||||
/// </summary>
|
||||
/// <param name="addressFamily">寻址方案</param>
|
||||
/// <param name="endPoint">绑定节点</param>
|
||||
/// <param name="threadCount">多线程数量</param>
|
||||
/// <exception cref="RRQMException"></exception>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public void Bind(AddressFamily addressFamily, EndPoint endPoint, int threadCount)
|
||||
{
|
||||
this.tcpService.Bind(addressFamily, endPoint, threadCount);
|
||||
}
|
||||
|
||||
private void OnReceived(RRQMSocketClient socketClient, ByteBlock byteBlock, object obj)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)obj;
|
||||
if (this.routeMap.TryGet(httpRequest.URL, out MethodInstance methodInstance))
|
||||
{
|
||||
MethodInvoker methodInvoker = new MethodInvoker();
|
||||
httpRequest.Flag = socketClient;
|
||||
methodInvoker.Flag = httpRequest;
|
||||
this.ExecuteMethod(methodInvoker, methodInstance);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束调用
|
||||
/// </summary>
|
||||
/// <param name="methodInvoker"></param>
|
||||
/// <param name="methodInstance"></param>
|
||||
protected override void EndInvokeMethod(MethodInvoker methodInvoker, MethodInstance methodInstance)
|
||||
{
|
||||
HttpRequest httpRequest = (HttpRequest)methodInvoker.Flag;
|
||||
RRQMSocketClient socketClient = (RRQMSocketClient)httpRequest.Flag;
|
||||
|
||||
HttpResponse httpResponse = new HttpResponse();
|
||||
httpResponse.FromText("若汝棋茗");
|
||||
|
||||
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="methodInstances"></param>
|
||||
protected override void InitializeServers(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)
|
||||
{
|
||||
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>
|
||||
public override void Dispose()
|
||||
{
|
||||
this.tcpService.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,12 @@ VisualStudioVersion = 16.0.30804.86
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket", "RRQMSocket\RRQMSocket.csproj", "{2869A094-BBB1-4F15-A54D-581BC927E92E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.FileTransfer", "RRQMSocket.FileTransfer\RRQMSocket.FileTransfer.csproj", "{717FB0F1-3DA3-4A70-9502-8BAA8A949672}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.Http", "RRQMSocket.Http\RRQMSocket.Http.csproj", "{94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RRQMSocket.RPC", "RRQMSocket.RPC\RRQMSocket.RPC.csproj", "{E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -15,6 +21,18 @@ Global
|
||||
{2869A094-BBB1-4F15-A54D-581BC927E92E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2869A094-BBB1-4F15-A54D-581BC927E92E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2869A094-BBB1-4F15-A54D-581BC927E92E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{717FB0F1-3DA3-4A70-9502-8BAA8A949672}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94F85A89-73E3-4DB2-A87F-CDE9B71CF6F3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E88189B5-188B-4798-B5A5-FB8AF9C2A3E3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user