mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-19 01:46:44 +08:00
新增fast序列化支持attribute序列化
新增IPHost支持直接IPv6格式 新增发布net462,net472平台。依赖与net45保持一致。
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||||
<SignAssembly>True</SignAssembly>
|
<SignAssembly>True</SignAssembly>
|
||||||
<AssemblyOriginatorKeyFile>$(MSBuildProjectName).snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>$(MSBuildProjectName).snk</AssemblyOriginatorKeyFile>
|
||||||
<Version>2.0.0-beta.268</Version>
|
<Version>2.0.0-beta.269</Version>
|
||||||
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<Company>若汝棋茗</Company>
|
<Company>若汝棋茗</Company>
|
||||||
@@ -31,6 +31,12 @@
|
|||||||
<PropertyGroup Condition="'$(TargetFramework)'=='net45'">
|
<PropertyGroup Condition="'$(TargetFramework)'=='net45'">
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(TargetFramework)'=='net462'">
|
||||||
|
<LangVersion>8.0</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(TargetFramework)'=='net472'">
|
||||||
|
<LangVersion>8.0</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(TargetFramework)'=='net481'">
|
<PropertyGroup Condition="'$(TargetFramework)'=='net481'">
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>IOC;Autofac;DependencyInjection;TouchSocket</PackageTags>
|
<PackageTags>IOC;Autofac;DependencyInjection;TouchSocket</PackageTags>
|
||||||
<Description>这是一个为Core中扩展Ioc容器为Autofac的库。
|
<Description>这是一个为Core中扩展Ioc容器为Autofac的库。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net461;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net461;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>IOC;DependencyInjection;TouchSocket</PackageTags>
|
<PackageTags>IOC;DependencyInjection;TouchSocket</PackageTags>
|
||||||
<Description>这是一个为Core中扩展Ioc容器为IServiceCollection的库。
|
<Description>这是一个为Core中扩展Ioc容器为IServiceCollection的库。
|
||||||
|
|
||||||
|
|||||||
@@ -96,8 +96,11 @@ namespace TouchSocket.Core
|
|||||||
/// <param name="disposing"></param>
|
/// <param name="disposing"></param>
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
this.m_timer.SafeDispose();
|
if (disposing)
|
||||||
this.m_queue.Clear();
|
{
|
||||||
|
this.m_timer.SafeDispose();
|
||||||
|
this.m_queue.Clear();
|
||||||
|
}
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,13 +41,21 @@ namespace TouchSocket.Core
|
|||||||
public static readonly Type dicType = typeof(IDictionary);
|
public static readonly Type dicType = typeof(IDictionary);
|
||||||
public static readonly Type arrayType = typeof(Array);
|
public static readonly Type arrayType = typeof(Array);
|
||||||
public static readonly Type nullableType = typeof(Nullable<>);
|
public static readonly Type nullableType = typeof(Nullable<>);
|
||||||
|
|
||||||
public static readonly byte[] ZeroBytes = new byte[0];
|
|
||||||
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
|
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 空字符串常亮
|
/// 空字符串常亮
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string Empty = "";
|
public const string Empty = "";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 0长度字节数组
|
||||||
|
/// </summary>
|
||||||
|
#if NET45
|
||||||
|
public static readonly byte[] ZeroBytes = new byte[0];
|
||||||
|
#else
|
||||||
|
public static readonly byte[] ZeroBytes = Array.Empty<byte>();
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,8 +17,7 @@ namespace TouchSocket.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// PackageBase包结构数据。
|
/// PackageBase包结构数据。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable]
|
public abstract class PackageBase : IPackage
|
||||||
public abstract partial class PackageBase : IPackage
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public abstract void Package(in ByteBlock byteBlock);
|
public abstract void Package(in ByteBlock byteBlock);
|
||||||
|
|||||||
@@ -37,8 +37,10 @@ namespace TouchSocket.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MemberAccessor : IMemberAccessor
|
public class MemberAccessor : IMemberAccessor
|
||||||
{
|
{
|
||||||
private Func<object, string, object> GetValueDelegate;
|
private Func<object, string, object> m_getValueDelegate;
|
||||||
private Action<object, string, object> SetValueDelegate;
|
private Dictionary<string, FieldInfo> m_dicFieldInfes;
|
||||||
|
private Dictionary<string, PropertyInfo> m_dicProperties;
|
||||||
|
private Action<object, string, object> m_setValueDelegate;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态成员访问器
|
/// 动态成员访问器
|
||||||
@@ -51,8 +53,20 @@ namespace TouchSocket.Core
|
|||||||
this.OnGetProperties = (t) => { return t.GetProperties(); };
|
this.OnGetProperties = (t) => { return t.GetProperties(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<string, FieldInfo> dicFieldInfes;
|
/// <summary>
|
||||||
private Dictionary<string, PropertyInfo> dicProperties;
|
/// 获取字段
|
||||||
|
/// </summary>
|
||||||
|
public Func<Type, FieldInfo[]> OnGetFieldInfes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取属性
|
||||||
|
/// </summary>
|
||||||
|
public Func<Type, PropertyInfo[]> OnGetProperties { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所属类型
|
||||||
|
/// </summary>
|
||||||
|
public Type Type { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构建
|
/// 构建
|
||||||
@@ -61,39 +75,24 @@ namespace TouchSocket.Core
|
|||||||
{
|
{
|
||||||
if (GlobalEnvironment.DynamicBuilderType == DynamicBuilderType.Reflect)
|
if (GlobalEnvironment.DynamicBuilderType == DynamicBuilderType.Reflect)
|
||||||
{
|
{
|
||||||
this.dicFieldInfes = this.OnGetFieldInfes.Invoke(this.Type).ToDictionary(a => a.Name);
|
this.m_dicFieldInfes = this.OnGetFieldInfes.Invoke(this.Type).ToDictionary(a => a.Name);
|
||||||
this.dicProperties = this.OnGetProperties.Invoke(this.Type).ToDictionary(a => a.Name);
|
this.m_dicProperties = this.OnGetProperties.Invoke(this.Type).ToDictionary(a => a.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.GetValueDelegate = this.GenerateGetValue();
|
this.m_getValueDelegate = this.GenerateGetValue();
|
||||||
this.SetValueDelegate = this.GenerateSetValue();
|
this.m_setValueDelegate = this.GenerateSetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取属性
|
|
||||||
/// </summary>
|
|
||||||
public Func<Type, PropertyInfo[]> OnGetProperties { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取字段
|
|
||||||
/// </summary>
|
|
||||||
public Func<Type, FieldInfo[]> OnGetFieldInfes { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 所属类型
|
|
||||||
/// </summary>
|
|
||||||
public Type Type { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public object GetValue(object instance, string memberName)
|
public object GetValue(object instance, string memberName)
|
||||||
{
|
{
|
||||||
return this.GetValueDelegate(instance, memberName);
|
return this.m_getValueDelegate(instance, memberName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void SetValue(object instance, string memberName, object newValue)
|
public void SetValue(object instance, string memberName, object newValue)
|
||||||
{
|
{
|
||||||
this.SetValueDelegate(instance, memberName, newValue);
|
this.m_setValueDelegate(instance, memberName, newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Func<object, string, object> GenerateGetValue()
|
private Func<object, string, object> GenerateGetValue()
|
||||||
@@ -102,13 +101,13 @@ namespace TouchSocket.Core
|
|||||||
{
|
{
|
||||||
return (obj, key) =>
|
return (obj, key) =>
|
||||||
{
|
{
|
||||||
if (this.dicFieldInfes.TryGetValue(key, out var value1))
|
if (this.m_dicFieldInfes.TryGetValue(key, out var value1))
|
||||||
{
|
{
|
||||||
return value1.GetValue(obj);
|
return value1.GetValue(obj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return this.dicProperties.TryGetValue(key, out var value2) ? value2.GetValue(obj) : default;
|
return this.m_dicProperties.TryGetValue(key, out var value2) ? value2.GetValue(obj) : default;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -160,11 +159,11 @@ namespace TouchSocket.Core
|
|||||||
{
|
{
|
||||||
return (obj, key, value) =>
|
return (obj, key, value) =>
|
||||||
{
|
{
|
||||||
if (this.dicFieldInfes.TryGetValue(key, out var value1))
|
if (this.m_dicFieldInfes.TryGetValue(key, out var value1))
|
||||||
{
|
{
|
||||||
value1.SetValue(obj, value);
|
value1.SetValue(obj, value);
|
||||||
}
|
}
|
||||||
if (this.dicProperties.TryGetValue(key, out var value2))
|
if (this.m_dicProperties.TryGetValue(key, out var value2))
|
||||||
{
|
{
|
||||||
value2.SetValue(obj, value);
|
value2.SetValue(obj, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace TouchSocket.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// FastConverterAttribute
|
/// FastConverterAttribute
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class,AllowMultiple =false,Inherited =false)]
|
||||||
public class FastConverterAttribute : Attribute
|
public class FastConverterAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TouchSocket.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 标识Fast序列化成员编号。以此来代替属性、字段名。
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||||
|
public class FastMemberAttribute:Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 索引号
|
||||||
|
/// </summary>
|
||||||
|
public byte Index { get;private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标识Fast序列化成员编号。以此来代替属性、字段名。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">最大支持255个成员</param>
|
||||||
|
public FastMemberAttribute(byte index)
|
||||||
|
{
|
||||||
|
this.Index = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace TouchSocket.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 忽略的Fast序列化
|
/// 忽略的Fast序列化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||||
public sealed class FastNonSerializedAttribute : Attribute
|
public sealed class FastNonSerializedAttribute : Attribute
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,14 @@ using System;
|
|||||||
namespace TouchSocket.Core
|
namespace TouchSocket.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 强制Fast序列化。一般当某个属性为只读时,使用该特性。
|
/// 显式Fast序列化。一般当某个属性为只读时,使用该特性。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
[AttributeUsage(AttributeTargets.Property| AttributeTargets.Class| AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
|
||||||
public sealed class FastSerializedAttribute : Attribute
|
public sealed class FastSerializedAttribute : Attribute
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 使用索引替代属性名称。
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableIndex { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,31 +17,21 @@ using System.Data;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace TouchSocket.Core
|
namespace TouchSocket.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 快速二进制序列化。
|
/// 快速二进制序列化。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static partial class FastBinaryFormatter
|
public static class FastBinaryFormatter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DynamicallyAccessed
|
/// DynamicallyAccessed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const DynamicallyAccessedMemberTypes DynamicallyAccessed = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties;
|
public const DynamicallyAccessedMemberTypes DynamicallyAccessed = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties;
|
||||||
|
|
||||||
static FastBinaryFormatter()
|
private static readonly DefaultFastSerializerContext m_defaultFastSerializerContext = new DefaultFastSerializerContext();
|
||||||
{
|
|
||||||
AddFastBinaryConverter(typeof(string), new StringFastBinaryConverter());
|
|
||||||
AddFastBinaryConverter(typeof(Version), new VersionFastBinaryConverter());
|
|
||||||
AddFastBinaryConverter(typeof(ByteBlock), new ByteBlockFastBinaryConverter());
|
|
||||||
AddFastBinaryConverter(typeof(MemoryStream), new MemoryStreamFastBinaryConverter());
|
|
||||||
AddFastBinaryConverter(typeof(Guid), new GuidFastBinaryConverter());
|
|
||||||
AddFastBinaryConverter(typeof(DataTable), new DataTableFastBinaryConverter());
|
|
||||||
AddFastBinaryConverter(typeof(DataSet), new DataSetFastBinaryConverter());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<Type, SerializObject> m_instanceCache = new ConcurrentDictionary<Type, SerializObject>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加转换器。
|
/// 添加转换器。
|
||||||
@@ -68,8 +58,7 @@ namespace TouchSocket.Core
|
|||||||
/// <param name="converter"></param>
|
/// <param name="converter"></param>
|
||||||
public static void AddFastBinaryConverter([DynamicallyAccessedMembers(DynamicallyAccessed)] Type type, IFastBinaryConverter converter)
|
public static void AddFastBinaryConverter([DynamicallyAccessedMembers(DynamicallyAccessed)] Type type, IFastBinaryConverter converter)
|
||||||
{
|
{
|
||||||
var serializObject = new SerializObject(type, converter);
|
m_defaultFastSerializerContext.AddFastBinaryConverter(type, converter);
|
||||||
m_instanceCache.AddOrUpdate(type, serializObject, (k, v) => serializObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Serialize
|
#region Serialize
|
||||||
@@ -81,102 +70,109 @@ namespace TouchSocket.Core
|
|||||||
/// <param name="graph">对象</param>
|
/// <param name="graph">对象</param>
|
||||||
public static void Serialize<[DynamicallyAccessedMembers(DynamicallyAccessed)] T>(ByteBlock byteBlock, [DynamicallyAccessedMembers(DynamicallyAccessed)] in T graph)
|
public static void Serialize<[DynamicallyAccessedMembers(DynamicallyAccessed)] T>(ByteBlock byteBlock, [DynamicallyAccessedMembers(DynamicallyAccessed)] in T graph)
|
||||||
{
|
{
|
||||||
|
Serialize(byteBlock, graph, m_defaultFastSerializerContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="byteBlock">流</param>
|
||||||
|
/// <param name="graph">对象</param>
|
||||||
|
/// <param name="serializerContext"></param>
|
||||||
|
public static void Serialize<[DynamicallyAccessedMembers(DynamicallyAccessed)] T>(ByteBlock byteBlock, [DynamicallyAccessedMembers(DynamicallyAccessed)] in T graph, FastSerializerContext serializerContext)
|
||||||
|
{
|
||||||
|
if (serializerContext is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(serializerContext));
|
||||||
|
}
|
||||||
|
|
||||||
byteBlock.Position = 1;
|
byteBlock.Position = 1;
|
||||||
SerializeObject(byteBlock, graph);
|
SerializeObject(byteBlock, graph, serializerContext);
|
||||||
byteBlock.Buffer[0] = 1;
|
byteBlock.Buffer[0] = 1;
|
||||||
byteBlock.SetLength(byteBlock.Position);
|
byteBlock.SetLength(byteBlock.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int SerializeClass<T>(ByteBlock stream, T obj, Type type)
|
private static int SerializeClass<T>(ByteBlock byteBlock, T obj, Type type, FastSerializerContext serializerContext)
|
||||||
{
|
{
|
||||||
var len = 0;
|
var len = 0;
|
||||||
if (obj != null)
|
if (obj != null)
|
||||||
{
|
{
|
||||||
var serializObject = GetOrAddInstance(type);
|
var serializObject = serializerContext.GetSerializObject(type);
|
||||||
|
|
||||||
for (var i = 0; i < serializObject.MemberInfos.Length; i++)
|
for (var i = 0; i < serializObject.MemberInfos.Length; i++)
|
||||||
{
|
{
|
||||||
var memberInfo = serializObject.MemberInfos[i];
|
var memberInfo = serializObject.MemberInfos[i];
|
||||||
var propertyBytes = Encoding.UTF8.GetBytes(memberInfo.Name);
|
if (serializObject.EnableIndex)
|
||||||
if (propertyBytes.Length > byte.MaxValue)
|
|
||||||
{
|
{
|
||||||
throw new Exception($"属性名:{memberInfo.Name}超长");
|
byteBlock.Write((byte)memberInfo.Index);
|
||||||
|
len += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var propertyBytes = Encoding.UTF8.GetBytes(memberInfo.Name);
|
||||||
|
if (propertyBytes.Length > byte.MaxValue)
|
||||||
|
{
|
||||||
|
throw new Exception($"属性名:{memberInfo.Name}超长");
|
||||||
|
}
|
||||||
|
byteBlock.Write((byte)propertyBytes.Length);
|
||||||
|
byteBlock.Write(propertyBytes, 0, propertyBytes.Length);
|
||||||
|
len += propertyBytes.Length + 1;
|
||||||
}
|
}
|
||||||
stream.Write((byte)propertyBytes.Length);
|
|
||||||
stream.Write(propertyBytes, 0, propertyBytes.Length);
|
|
||||||
len += propertyBytes.Length + 1;
|
|
||||||
//len += SerializeObject(stream, property.GetValue(obj));
|
|
||||||
len += SerializeObject(stream, serializObject.MemberAccessor.GetValue(obj, memberInfo.Name));
|
|
||||||
}
|
|
||||||
//foreach (PropertyInfo property in serializObject.Properties)
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
|
|
||||||
//foreach (FieldInfo fieldInfo in serializObject.FieldInfos)
|
len += SerializeObject(byteBlock, serializObject.MemberAccessor.GetValue(obj, memberInfo.Name), serializerContext);
|
||||||
//{
|
}
|
||||||
// byte[] propertyBytes = Encoding.UTF8.GetBytes(fieldInfo.Name);
|
|
||||||
// if (propertyBytes.Length > byte.MaxValue)
|
|
||||||
// {
|
|
||||||
// throw new Exception($"属性名:{fieldInfo.Name}超长");
|
|
||||||
// }
|
|
||||||
// byte lenBytes = (byte)propertyBytes.Length;
|
|
||||||
// stream.Write(lenBytes);
|
|
||||||
// stream.Write(propertyBytes, 0, propertyBytes.Length);
|
|
||||||
// len += propertyBytes.Length + 1;
|
|
||||||
// len += SerializeObject(stream, fieldInfo.GetValue(obj));
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int SerializeDictionary(in ByteBlock stream, in IEnumerable param)
|
private static int SerializeDictionary(in ByteBlock byteBlock, in IEnumerable param, FastSerializerContext serializerContext)
|
||||||
{
|
{
|
||||||
var len = 0;
|
var len = 0;
|
||||||
if (param != null)
|
if (param != null)
|
||||||
{
|
{
|
||||||
var oldPosition = stream.Position;
|
var oldPosition = byteBlock.Position;
|
||||||
stream.Position += 4;
|
byteBlock.Position += 4;
|
||||||
len += 4;
|
len += 4;
|
||||||
uint paramLen = 0;
|
uint paramLen = 0;
|
||||||
|
|
||||||
foreach (var item in param)
|
foreach (var item in param)
|
||||||
{
|
{
|
||||||
len += SerializeObject(stream, DynamicMethodMemberAccessor.Default.GetValue(item, "Key"));
|
len += SerializeObject(byteBlock, DynamicMethodMemberAccessor.Default.GetValue(item, "Key"), serializerContext);
|
||||||
len += SerializeObject(stream, DynamicMethodMemberAccessor.Default.GetValue(item, "Value"));
|
len += SerializeObject(byteBlock, DynamicMethodMemberAccessor.Default.GetValue(item, "Value"), serializerContext);
|
||||||
paramLen++;
|
paramLen++;
|
||||||
}
|
}
|
||||||
var newPosition = stream.Position;
|
var newPosition = byteBlock.Position;
|
||||||
stream.Position = oldPosition;
|
byteBlock.Position = oldPosition;
|
||||||
stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
|
byteBlock.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
|
||||||
stream.Position = newPosition;
|
byteBlock.Position = newPosition;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int SerializeIListOrArray(in ByteBlock stream, in IEnumerable param)
|
private static int SerializeIListOrArray(in ByteBlock byteBlock, in IEnumerable param, FastSerializerContext serializerContext)
|
||||||
{
|
{
|
||||||
var len = 0;
|
var len = 0;
|
||||||
if (param != null)
|
if (param != null)
|
||||||
{
|
{
|
||||||
var oldPosition = stream.Position;
|
var oldPosition = byteBlock.Position;
|
||||||
stream.Position += 4;
|
byteBlock.Position += 4;
|
||||||
len += 4;
|
len += 4;
|
||||||
uint paramLen = 0;
|
uint paramLen = 0;
|
||||||
|
|
||||||
foreach (var item in param)
|
foreach (var item in param)
|
||||||
{
|
{
|
||||||
paramLen++;
|
paramLen++;
|
||||||
len += SerializeObject(stream, item);
|
len += SerializeObject(byteBlock, item, serializerContext);
|
||||||
}
|
}
|
||||||
var newPosition = stream.Position;
|
var newPosition = byteBlock.Position;
|
||||||
stream.Position = oldPosition;
|
byteBlock.Position = oldPosition;
|
||||||
stream.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
|
byteBlock.Write(TouchSocketBitConverter.Default.GetBytes(paramLen));
|
||||||
stream.Position = newPosition;
|
byteBlock.Position = newPosition;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int SerializeObject<T>(in ByteBlock byteBlock, in T graph)
|
private static int SerializeObject<T>(in ByteBlock byteBlock, in T graph, FastSerializerContext serializerContext)
|
||||||
{
|
{
|
||||||
var len = 0;
|
var len = 0;
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
@@ -260,11 +256,6 @@ namespace TouchSocket.Core
|
|||||||
{
|
{
|
||||||
switch (graph)
|
switch (graph)
|
||||||
{
|
{
|
||||||
//case string value:
|
|
||||||
// {
|
|
||||||
// data = Encoding.UTF8.GetBytes(value);
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
case decimal value:
|
case decimal value:
|
||||||
{
|
{
|
||||||
data = TouchSocketBitConverter.Default.GetBytes(value);
|
data = TouchSocketBitConverter.Default.GetBytes(value);
|
||||||
@@ -311,7 +302,7 @@ namespace TouchSocket.Core
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
byteBlock.Position += 4;
|
byteBlock.Position += 4;
|
||||||
var serializeObj = GetOrAddInstance(type);
|
var serializeObj = serializerContext.GetSerializObject(type);
|
||||||
if (serializeObj.Converter != null)
|
if (serializeObj.Converter != null)
|
||||||
{
|
{
|
||||||
len += serializeObj.Converter.Write(byteBlock, graph);
|
len += serializeObj.Converter.Write(byteBlock, graph);
|
||||||
@@ -321,20 +312,20 @@ namespace TouchSocket.Core
|
|||||||
switch (serializeObj.InstanceType)
|
switch (serializeObj.InstanceType)
|
||||||
{
|
{
|
||||||
case InstanceType.List:
|
case InstanceType.List:
|
||||||
len += SerializeIListOrArray(byteBlock, (IEnumerable)graph);
|
len += SerializeIListOrArray(byteBlock, (IEnumerable)graph, serializerContext);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InstanceType.Array:
|
case InstanceType.Array:
|
||||||
len += SerializeIListOrArray(byteBlock, (IEnumerable)graph);
|
len += SerializeIListOrArray(byteBlock, (IEnumerable)graph, serializerContext);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InstanceType.Dictionary:
|
case InstanceType.Dictionary:
|
||||||
len += SerializeDictionary(byteBlock, (IEnumerable)graph);
|
len += SerializeDictionary(byteBlock, (IEnumerable)graph, serializerContext);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case InstanceType.Class:
|
case InstanceType.Class:
|
||||||
len += SerializeClass(byteBlock, graph, type);
|
len += SerializeClass(byteBlock, graph, type, serializerContext);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -388,10 +379,34 @@ namespace TouchSocket.Core
|
|||||||
throw new Exception("Fast反序列化数据流解析错误。");
|
throw new Exception("Fast反序列化数据流解析错误。");
|
||||||
}
|
}
|
||||||
offset += 1;
|
offset += 1;
|
||||||
return Deserialize(type, data, ref offset);
|
return Deserialize(type, data, ref offset, m_defaultFastSerializerContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object Deserialize(Type type, byte[] datas, ref int offset)
|
/// <summary>
|
||||||
|
/// 反序列化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="offset"></param>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="serializerContext"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object Deserialize(byte[] data, int offset, [DynamicallyAccessedMembers(DynamicallyAccessed)] Type type, FastSerializerContext serializerContext)
|
||||||
|
{
|
||||||
|
if (data[offset] != 1)
|
||||||
|
{
|
||||||
|
throw new Exception("Fast反序列化数据流解析错误。");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serializerContext is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(serializerContext));
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += 1;
|
||||||
|
return Deserialize(type, data, ref offset, serializerContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object Deserialize(Type type, byte[] datas, ref int offset, FastSerializerContext serializerContext)
|
||||||
{
|
{
|
||||||
var nullable = type.IsNullableType();
|
var nullable = type.IsNullableType();
|
||||||
if (nullable)
|
if (nullable)
|
||||||
@@ -403,11 +418,6 @@ namespace TouchSocket.Core
|
|||||||
offset += 4;
|
offset += 4;
|
||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
//if (type == TouchSocketCoreUtility.stringType)
|
|
||||||
//{
|
|
||||||
// obj = Encoding.UTF8.GetString(datas, offset, len);
|
|
||||||
//}
|
|
||||||
//else
|
|
||||||
if (type == TouchSocketCoreUtility.byteType)
|
if (type == TouchSocketCoreUtility.byteType)
|
||||||
{
|
{
|
||||||
obj = datas[offset];
|
obj = datas[offset];
|
||||||
@@ -499,14 +509,14 @@ namespace TouchSocket.Core
|
|||||||
}
|
}
|
||||||
else if (type.IsClass || type.IsStruct())
|
else if (type.IsClass || type.IsStruct())
|
||||||
{
|
{
|
||||||
var serializeObj = GetOrAddInstance(type);
|
var serializeObj = serializerContext.GetSerializObject(type);
|
||||||
if (serializeObj.Converter != null)
|
if (serializeObj.Converter != null)
|
||||||
{
|
{
|
||||||
obj = serializeObj.Converter.Read(datas, offset, len);
|
obj = serializeObj.Converter.Read(datas, offset, len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
obj = DeserializeClass(type, datas, offset, len);
|
obj = DeserializeClass(type, datas, offset, len, serializerContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -529,75 +539,101 @@ namespace TouchSocket.Core
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object DeserializeClass(Type type, byte[] datas, int offset, int length)
|
private static object DeserializeClass(Type type, byte[] datas, int offset, int length, FastSerializerContext serializerContext)
|
||||||
{
|
{
|
||||||
var serializObject = GetOrAddInstance(type);
|
var serializObject = serializerContext.GetSerializObject(type);
|
||||||
|
|
||||||
object instance;
|
object instance;
|
||||||
switch (serializObject.InstanceType)
|
switch (serializObject.InstanceType)
|
||||||
{
|
{
|
||||||
case InstanceType.Class:
|
case InstanceType.Class:
|
||||||
{
|
{
|
||||||
instance = serializObject.GetNewInstance();
|
instance = serializerContext.GetNewInstance(type);
|
||||||
var index = offset;
|
var index = offset;
|
||||||
while (offset - index < length && (length >= 4))
|
if (serializObject.EnableIndex)
|
||||||
{
|
{
|
||||||
int len = datas[offset];
|
while (offset - index < length && (length > 0))
|
||||||
var propertyName = Encoding.UTF8.GetString(datas, offset + 1, len);
|
|
||||||
offset += len + 1;
|
|
||||||
if (serializObject.IsStruct)
|
|
||||||
{
|
{
|
||||||
if (serializObject.PropertiesDic.ContainsKey(propertyName))
|
var propertyNameIndex = datas[offset];
|
||||||
|
offset += 1;
|
||||||
|
if (serializObject.IsStruct)
|
||||||
{
|
{
|
||||||
var property = serializObject.PropertiesDic[propertyName];
|
if (serializObject.FastMemberInfoDicForIndex.TryGetValue(propertyNameIndex, out var property))
|
||||||
var obj = Deserialize(property.PropertyType, datas, ref offset);
|
{
|
||||||
property.SetValue(instance, obj);
|
var obj = Deserialize(property.Type, datas, ref offset, serializerContext);
|
||||||
}
|
property.SetValue(ref instance, obj);
|
||||||
else if (serializObject.FieldInfosDic.ContainsKey(propertyName))
|
}
|
||||||
{
|
else
|
||||||
var property = serializObject.FieldInfosDic[propertyName];
|
{
|
||||||
var obj = Deserialize(property.FieldType, datas, ref offset);
|
var pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
|
||||||
property.SetValue(instance, obj);
|
offset += pLen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
|
if (serializObject.FastMemberInfoDicForIndex.TryGetValue(propertyNameIndex, out var property))
|
||||||
offset += 4;
|
{
|
||||||
offset += pLen;
|
var obj = Deserialize(property.Type, datas, ref offset, serializerContext);
|
||||||
}
|
serializObject.MemberAccessor.SetValue(instance, property.Name, obj);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (serializObject.PropertiesDic.TryGetValue(propertyName, out var property))
|
var pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
|
||||||
{
|
offset += pLen;
|
||||||
var obj = Deserialize(property.PropertyType, datas, ref offset);
|
}
|
||||||
serializObject.MemberAccessor.SetValue(instance, property.Name, obj);
|
|
||||||
}
|
|
||||||
else if (serializObject.FieldInfosDic.TryGetValue(propertyName, out var fieldInfo))
|
|
||||||
{
|
|
||||||
var obj = Deserialize(fieldInfo.FieldType, datas, ref offset);
|
|
||||||
serializObject.MemberAccessor.SetValue(instance, fieldInfo.Name, obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
|
|
||||||
offset += 4;
|
|
||||||
offset += pLen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (offset - index < length && (length >= 4))
|
||||||
|
{
|
||||||
|
int len = datas[offset];
|
||||||
|
var propertyName = Encoding.UTF8.GetString(datas, offset + 1, len);
|
||||||
|
offset += len + 1;
|
||||||
|
if (serializObject.IsStruct)
|
||||||
|
{
|
||||||
|
if (serializObject.FastMemberInfoDicForName.TryGetValue(propertyName, out var property))
|
||||||
|
{
|
||||||
|
var obj = Deserialize(property.Type, datas, ref offset, serializerContext);
|
||||||
|
property.SetValue(ref instance, obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
|
||||||
|
offset += 4;
|
||||||
|
offset += pLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (serializObject.FastMemberInfoDicForName.TryGetValue(propertyName, out var property))
|
||||||
|
{
|
||||||
|
var obj = Deserialize(property.Type, datas, ref offset, serializerContext);
|
||||||
|
serializObject.MemberAccessor.SetValue(instance, property.Name, obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var pLen = TouchSocketBitConverter.Default.ToInt32(datas, offset);
|
||||||
|
offset += 4;
|
||||||
|
offset += pLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InstanceType.List:
|
case InstanceType.List:
|
||||||
{
|
{
|
||||||
instance = serializObject.GetNewInstance();
|
instance = serializerContext.GetNewInstance(type);
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
{
|
{
|
||||||
var paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
|
var paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
for (uint i = 0; i < paramLen; i++)
|
for (uint i = 0; i < paramLen; i++)
|
||||||
{
|
{
|
||||||
var obj = Deserialize(serializObject.ArgTypes[0], datas, ref offset);
|
var obj = Deserialize(serializObject.ArgTypes[0], datas, ref offset, serializerContext);
|
||||||
serializObject.AddMethod.Invoke(instance, new object[] { obj });
|
serializObject.AddMethod.Invoke(instance, new object[] { obj });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -617,7 +653,7 @@ namespace TouchSocket.Core
|
|||||||
offset += 4;
|
offset += 4;
|
||||||
for (uint i = 0; i < paramLen; i++)
|
for (uint i = 0; i < paramLen; i++)
|
||||||
{
|
{
|
||||||
var obj = Deserialize(serializObject.ArrayType, datas, ref offset);
|
var obj = Deserialize(serializObject.ArrayType, datas, ref offset, serializerContext);
|
||||||
array.SetValue(obj, i);
|
array.SetValue(obj, i);
|
||||||
}
|
}
|
||||||
instance = array;
|
instance = array;
|
||||||
@@ -630,15 +666,15 @@ namespace TouchSocket.Core
|
|||||||
}
|
}
|
||||||
case InstanceType.Dictionary:
|
case InstanceType.Dictionary:
|
||||||
{
|
{
|
||||||
instance = serializObject.GetNewInstance();
|
instance = serializerContext.GetNewInstance(type);
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
{
|
{
|
||||||
var paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
|
var paramLen = TouchSocketBitConverter.Default.ToUInt32(datas, offset);
|
||||||
offset += 4;
|
offset += 4;
|
||||||
for (uint i = 0; i < paramLen; i++)
|
for (uint i = 0; i < paramLen; i++)
|
||||||
{
|
{
|
||||||
var key = Deserialize(serializObject.ArgTypes[0], datas, ref offset);
|
var key = Deserialize(serializObject.ArgTypes[0], datas, ref offset, serializerContext);
|
||||||
var value = Deserialize(serializObject.ArgTypes[1], datas, ref offset);
|
var value = Deserialize(serializObject.ArgTypes[1], datas, ref offset, serializerContext);
|
||||||
if (key != null)
|
if (key != null)
|
||||||
{
|
{
|
||||||
serializObject.AddMethod.Invoke(instance, new object[] { key, value });
|
serializObject.AddMethod.Invoke(instance, new object[] { key, value });
|
||||||
@@ -676,26 +712,5 @@ namespace TouchSocket.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion Deserialize
|
#endregion Deserialize
|
||||||
|
|
||||||
private static SerializObject GetOrAddInstance(Type type)
|
|
||||||
{
|
|
||||||
if (type.IsNullableType())
|
|
||||||
{
|
|
||||||
type = type.GetGenericArguments()[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_instanceCache.TryGetValue(type, out var instance))
|
|
||||||
{
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type.IsArray || type.IsClass || type.IsStruct())
|
|
||||||
{
|
|
||||||
var instanceObject = new SerializObject(type);
|
|
||||||
m_instanceCache.TryAdd(type, instanceObject);
|
|
||||||
return instanceObject;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TouchSocket.Core
|
||||||
|
{
|
||||||
|
internal class FastMemberInfo
|
||||||
|
{
|
||||||
|
public byte Index;
|
||||||
|
private readonly PropertyInfo m_propertyInfo;
|
||||||
|
private readonly FieldInfo m_fieldInfo;
|
||||||
|
private readonly bool m_isField;
|
||||||
|
public FastMemberInfo(MemberInfo memberInfo, bool enableIndex)
|
||||||
|
{
|
||||||
|
if (enableIndex)
|
||||||
|
{
|
||||||
|
if (memberInfo.GetCustomAttribute(typeof(FastMemberAttribute), false) is FastMemberAttribute fastMamberAttribute)
|
||||||
|
{
|
||||||
|
this.Index = fastMamberAttribute.Index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"成员{memberInfo.Name}未标识{nameof(FastMemberAttribute)}特性。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memberInfo is PropertyInfo propertyInfo)
|
||||||
|
{
|
||||||
|
this.m_propertyInfo = propertyInfo;
|
||||||
|
}
|
||||||
|
else if (memberInfo is FieldInfo fieldInfo)
|
||||||
|
{
|
||||||
|
m_isField = true;
|
||||||
|
this.m_fieldInfo = fieldInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name => this.m_isField ? this.m_fieldInfo.Name : this.m_propertyInfo.Name;
|
||||||
|
|
||||||
|
public Type Type =>this.m_isField? this.m_fieldInfo.FieldType : this.m_propertyInfo.PropertyType;
|
||||||
|
|
||||||
|
public void SetValue(ref object instance, object obj)
|
||||||
|
{
|
||||||
|
if (this.m_isField)
|
||||||
|
{
|
||||||
|
this.m_fieldInfo.SetValue(instance, obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.m_propertyInfo.SetValue(instance, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,20 +41,20 @@ namespace TouchSocket.Core
|
|||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
public abstract class FastBinaryConverter<T> : IFastBinaryConverter
|
public abstract class FastBinaryConverter<T> : IFastBinaryConverter
|
||||||
{
|
{
|
||||||
int IFastBinaryConverter.Write(ByteBlock byteBlock, object obj)
|
|
||||||
{
|
|
||||||
return this.Write(byteBlock, (T)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
object IFastBinaryConverter.Read(byte[] buffer, int offset, int len)
|
object IFastBinaryConverter.Read(byte[] buffer, int offset, int len)
|
||||||
{
|
{
|
||||||
return this.Read(buffer, offset, len);
|
return this.Read(buffer, offset, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IFastBinaryConverter.Write(ByteBlock, object)"/>
|
int IFastBinaryConverter.Write(ByteBlock byteBlock, object obj)
|
||||||
protected abstract int Write(ByteBlock byteBlock, T obj);
|
{
|
||||||
|
return this.Write(byteBlock, (T)obj);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IFastBinaryConverter.Read(byte[], int, int)"/>
|
/// <inheritdoc cref="IFastBinaryConverter.Read(byte[], int, int)"/>
|
||||||
protected abstract T Read(byte[] buffer, int offset, int len);
|
protected abstract T Read(byte[] buffer, int offset, int len);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IFastBinaryConverter.Write(ByteBlock, object)"/>
|
||||||
|
protected abstract int Write(ByteBlock byteBlock, T obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,18 +17,38 @@ using System.Reflection;
|
|||||||
|
|
||||||
namespace TouchSocket.Core
|
namespace TouchSocket.Core
|
||||||
{
|
{
|
||||||
internal sealed class SerializObject
|
/// <summary>
|
||||||
|
/// 可序列化对象
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SerializObject
|
||||||
{
|
{
|
||||||
private FieldInfo[] m_fieldInfos;
|
internal Method AddMethod;
|
||||||
private MemberInfo[] m_memberInfos;
|
internal Type[] ArgTypes;
|
||||||
private PropertyInfo[] m_properties;
|
internal Type ArrayType;
|
||||||
|
internal bool EnableIndex;
|
||||||
|
internal Dictionary<byte, FastMemberInfo> FastMemberInfoDicForIndex;
|
||||||
|
internal Dictionary<string, FastMemberInfo> FastMemberInfoDicForName;
|
||||||
|
internal InstanceType InstanceType;
|
||||||
|
internal bool IsStruct;
|
||||||
|
internal MemberAccessor MemberAccessor;
|
||||||
|
internal FastMemberInfo[] MemberInfos;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从转换器初始化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="converter"></param>
|
||||||
public SerializObject(Type type, IFastBinaryConverter converter)
|
public SerializObject(Type type, IFastBinaryConverter converter)
|
||||||
{
|
{
|
||||||
this.Type = type;
|
this.Type = type;
|
||||||
this.Converter = converter;
|
this.Converter = converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从类型创建序列化器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
public SerializObject(Type type)
|
public SerializObject(Type type)
|
||||||
{
|
{
|
||||||
this.Type = type;
|
this.Type = type;
|
||||||
@@ -92,12 +112,50 @@ namespace TouchSocket.Core
|
|||||||
};
|
};
|
||||||
this.MemberAccessor.Build();
|
this.MemberAccessor.Build();
|
||||||
}
|
}
|
||||||
if (type.GetCustomAttribute<FastConverterAttribute>() is FastConverterAttribute attribute)
|
|
||||||
|
if (type.GetCustomAttribute(typeof(FastConverterAttribute), false) is FastConverterAttribute attribute)
|
||||||
{
|
{
|
||||||
this.Converter = (IFastBinaryConverter)Activator.CreateInstance(attribute.Type);
|
this.Converter = (IFastBinaryConverter)Activator.CreateInstance(attribute.Type);
|
||||||
}
|
}
|
||||||
this.PropertiesDic = GetProperties(type).ToDictionary(a => a.Name);
|
|
||||||
this.FieldInfosDic = GetFieldInfos(type).ToDictionary(a => a.Name);
|
if (type.GetCustomAttribute(typeof(FastSerializedAttribute), false) is FastSerializedAttribute fastSerializedAttribute)
|
||||||
|
{
|
||||||
|
this.EnableIndex = fastSerializedAttribute.EnableIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = new List<MemberInfo>();
|
||||||
|
list.AddRange(GetProperties(type));
|
||||||
|
list.AddRange(GetFieldInfos(type));
|
||||||
|
|
||||||
|
this.FastMemberInfoDicForIndex = new Dictionary<byte, FastMemberInfo>();
|
||||||
|
this.FastMemberInfoDicForName = new Dictionary<string, FastMemberInfo>();
|
||||||
|
|
||||||
|
if (this.EnableIndex)
|
||||||
|
{
|
||||||
|
foreach (var memberInfo in list)
|
||||||
|
{
|
||||||
|
var fastMemberInfo = new FastMemberInfo(memberInfo, true);
|
||||||
|
if (this.FastMemberInfoDicForIndex.ContainsKey(fastMemberInfo.Index))
|
||||||
|
{
|
||||||
|
throw new Exception($"类型:{type}中的成员{memberInfo.Name},在标识{nameof(FastMemberAttribute)}特性时Index重复。");
|
||||||
|
}
|
||||||
|
this.FastMemberInfoDicForIndex.Add(fastMemberInfo.Index, fastMemberInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var memberInfo in list)
|
||||||
|
{
|
||||||
|
var fastMemberInfo = new FastMemberInfo(memberInfo, false);
|
||||||
|
this.FastMemberInfoDicForName.Add(fastMemberInfo.Name, fastMemberInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var infos = new List<FastMemberInfo>();
|
||||||
|
infos.AddRange(this.FastMemberInfoDicForIndex.Values);
|
||||||
|
infos.AddRange(this.FastMemberInfoDicForName.Values);
|
||||||
|
this.MemberInfos = infos.ToArray();
|
||||||
|
|
||||||
if (type.IsGenericType)
|
if (type.IsGenericType)
|
||||||
{
|
{
|
||||||
this.ArgTypes = type.GetGenericArguments();
|
this.ArgTypes = type.GetGenericArguments();
|
||||||
@@ -106,64 +164,22 @@ namespace TouchSocket.Core
|
|||||||
this.IsStruct = type.IsStruct();
|
this.IsStruct = type.IsStruct();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Method AddMethod { get; private set; }
|
/// <summary>
|
||||||
public Type[] ArgTypes { get; private set; }
|
/// 转化器
|
||||||
public Type ArrayType { get; private set; }
|
/// </summary>
|
||||||
public IFastBinaryConverter Converter { get; private set; }
|
public IFastBinaryConverter Converter { get;private set; }
|
||||||
|
|
||||||
public FieldInfo[] FieldInfos
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
this.m_fieldInfos ??= this.FieldInfosDic.Values.ToArray();
|
|
||||||
return this.m_fieldInfos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<string, FieldInfo> FieldInfosDic { get; private set; }
|
|
||||||
public InstanceType InstanceType { get; private set; }
|
|
||||||
public bool IsStruct { get; private set; }
|
|
||||||
public MemberAccessor MemberAccessor { get; private set; }
|
|
||||||
|
|
||||||
public MemberInfo[] MemberInfos
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (this.m_memberInfos == null)
|
|
||||||
{
|
|
||||||
var infos = new List<MemberInfo>();
|
|
||||||
infos.AddRange(this.FieldInfosDic.Values);
|
|
||||||
infos.AddRange(this.PropertiesDic.Values);
|
|
||||||
this.m_memberInfos = infos.ToArray();
|
|
||||||
}
|
|
||||||
return this.m_memberInfos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PropertyInfo[] Properties
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
this.m_properties ??= this.PropertiesDic.Values.ToArray();
|
|
||||||
return this.m_properties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<string, PropertyInfo> PropertiesDic { get; private set; }
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 类型
|
||||||
|
/// </summary>
|
||||||
public Type Type { get; private set; }
|
public Type Type { get; private set; }
|
||||||
|
|
||||||
public object GetNewInstance()
|
|
||||||
{
|
|
||||||
return Activator.CreateInstance(this.Type);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FieldInfo[] GetFieldInfos(Type type)
|
private static FieldInfo[] GetFieldInfos(Type type)
|
||||||
{
|
{
|
||||||
return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default)
|
return type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default)
|
||||||
.Where(p =>
|
.Where(p =>
|
||||||
{
|
{
|
||||||
return !p.IsInitOnly && (!p.IsDefined(typeof(FastNonSerializedAttribute), true));
|
return !p.IsInitOnly && (!p.IsDefined(typeof(FastNonSerializedAttribute), false));
|
||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
@@ -173,9 +189,9 @@ namespace TouchSocket.Core
|
|||||||
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default)
|
return type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Default)
|
||||||
.Where(p =>
|
.Where(p =>
|
||||||
{
|
{
|
||||||
return p.IsDefined(typeof(FastSerializedAttribute), true) || p.CanWrite &&
|
return p.IsDefined(typeof(FastSerializedAttribute), false) || p.CanWrite &&
|
||||||
p.CanRead &&
|
p.CanRead &&
|
||||||
(!p.IsDefined(typeof(FastNonSerializedAttribute), true) &&
|
(!p.IsDefined(typeof(FastNonSerializedAttribute), false) &&
|
||||||
(p.SetMethod.GetParameters().Length == 1) &&
|
(p.SetMethod.GetParameters().Length == 1) &&
|
||||||
(p.GetMethod.GetParameters().Length == 0));
|
(p.GetMethod.GetParameters().Length == 0));
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace TouchSocket.Core
|
||||||
|
{
|
||||||
|
internal sealed class DefaultFastSerializerContext : FastSerializerContext
|
||||||
|
{
|
||||||
|
private readonly ConcurrentDictionary<Type, SerializObject> m_instanceCache = new ConcurrentDictionary<Type, SerializObject>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加转换器。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="converter"></param>
|
||||||
|
public void AddFastBinaryConverter([DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] Type type, IFastBinaryConverter converter)
|
||||||
|
{
|
||||||
|
base.AddConverter(type, converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override SerializObject GetSerializObject(Type type)
|
||||||
|
{
|
||||||
|
var serializObject = base.GetSerializObject(type);
|
||||||
|
if (serializObject != null)
|
||||||
|
{
|
||||||
|
return serializObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsNullableType())
|
||||||
|
{
|
||||||
|
type = type.GetGenericArguments()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_instanceCache.TryGetValue(type, out var instance))
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsArray || type.IsClass || type.IsStruct())
|
||||||
|
{
|
||||||
|
var instanceObject = new SerializObject(type);
|
||||||
|
m_instanceCache.TryAdd(type, instanceObject);
|
||||||
|
return instanceObject;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TouchSocket.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 快速序列化上下文
|
||||||
|
/// </summary>
|
||||||
|
public abstract class FastSerializerContext
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Type, SerializObject> m_instanceCache = new Dictionary<Type, SerializObject>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 快速序列化上下文
|
||||||
|
/// </summary>
|
||||||
|
public FastSerializerContext()
|
||||||
|
{
|
||||||
|
this.AddConverter(typeof(string), new StringFastBinaryConverter());
|
||||||
|
this.AddConverter(typeof(Version), new VersionFastBinaryConverter());
|
||||||
|
this.AddConverter(typeof(ByteBlock), new ByteBlockFastBinaryConverter());
|
||||||
|
this.AddConverter(typeof(MemoryStream), new MemoryStreamFastBinaryConverter());
|
||||||
|
this.AddConverter(typeof(Guid), new GuidFastBinaryConverter());
|
||||||
|
this.AddConverter(typeof(DataTable), new DataTableFastBinaryConverter());
|
||||||
|
this.AddConverter(typeof(DataSet), new DataSetFastBinaryConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取新实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual object GetNewInstance(Type type)
|
||||||
|
{
|
||||||
|
return Activator.CreateInstance(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取序列化对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual SerializObject GetSerializObject(Type type)
|
||||||
|
{
|
||||||
|
if (this.m_instanceCache.TryGetValue(type, out var serializObject))
|
||||||
|
{
|
||||||
|
return serializObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加转换器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="converter"></param>
|
||||||
|
protected void AddConverter([DynamicallyAccessedMembers(FastBinaryFormatter.DynamicallyAccessed)] Type type, IFastBinaryConverter converter)
|
||||||
|
{
|
||||||
|
var serializObject = new SerializObject(type, converter);
|
||||||
|
m_instanceCache.AddOrUpdate(type, serializObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,9 +47,9 @@ namespace TouchSocket.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步等待设置此事件
|
/// 异步等待设置此事件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Task WaitOneAsync()
|
public async Task WaitOneAsync()
|
||||||
{
|
{
|
||||||
return this.WaitOneAsync(CancellationToken.None);
|
await this.WaitOneAsync(CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,7 +62,7 @@ namespace TouchSocket.Core
|
|||||||
{
|
{
|
||||||
using (var timeoutSource = new CancellationTokenSource(timeout))
|
using (var timeoutSource = new CancellationTokenSource(timeout))
|
||||||
{
|
{
|
||||||
await this.WaitOneAsync(timeoutSource.Token);
|
await this.WaitOneAsync(timeoutSource.Token).ConfigureFalseAwait();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,17 +182,21 @@ namespace TouchSocket.Core
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
lock (this.m_locker)
|
|
||||||
{
|
|
||||||
if (this.m_waitQueue.Count == 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Set();
|
if (disposing)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
lock (this.m_locker)
|
||||||
|
{
|
||||||
|
if (this.m_waitQueue.Count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Set();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Message;ArrayPool;Logger;Plugin;3DES;Xml;FilePool;Serialize;TouchSocket</PackageTags>
|
<PackageTags>Message;ArrayPool;Logger;Plugin;3DES;Xml;FilePool;Serialize;TouchSocket</PackageTags>
|
||||||
<Description>这是一个基础服务功能的库,其中包含:内存池、对象池、文件池、流式数据解包器、等待逻辑池、AppMessenger、3DES加密、Xml快速存储、运行时间测量器、文件快捷操作、高性能二进制序列化器、规范日志接口等。
|
<Description>这是一个基础服务功能的库,其中包含:内存池、对象池、文件池、流式数据解包器、等待逻辑池、AppMessenger、3DES加密、Xml快速存储、运行时间测量器、文件快捷操作、高性能二进制序列化器、规范日志接口等。
|
||||||
|
|
||||||
|
|||||||
@@ -1005,7 +1005,7 @@ namespace TouchSocket.Dmtp
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.SendJsonObject(P5_Ping_Request, waitPing);
|
this.SendJsonObject(P5_Ping_Request, waitPing);
|
||||||
switch (await waitData.WaitAsync(timeout).ConfigureFalseAwait())
|
switch (await waitData.WaitAsync(timeout))
|
||||||
{
|
{
|
||||||
case WaitDataStatus.SetRunning:
|
case WaitDataStatus.SetRunning:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ namespace TouchSocket.Dmtp
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="msg"></param>
|
/// <param name="msg"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override void Close(string msg = "")
|
public override void Close(string msg)
|
||||||
{
|
{
|
||||||
if (this.IsHandshaked)
|
if (this.IsHandshaked)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Duplex;Rpc;FileTransfer;Redis;TouchSocket</PackageTags>
|
<PackageTags>Duplex;Rpc;FileTransfer;Redis;TouchSocket</PackageTags>
|
||||||
<Description>DMTP(Duplex Message Transport Protocol双工消息传输协议)是一个简单易用,便捷高效,且易于扩展的二进制数据协议。目前基于该协议,已实现的功能包括:连接验证、同步Id、Rpc(包括客户端请求服务器,服务器请求客户端、客户端请求客户端)、文件传输(包括客户端向服务器请求文件、客户端向服务器推送文件、服务器向客户端请求文件、服务器向客户端推送文件、
|
<Description>DMTP(Duplex Message Transport Protocol双工消息传输协议)是一个简单易用,便捷高效,且易于扩展的二进制数据协议。目前基于该协议,已实现的功能包括:连接验证、同步Id、Rpc(包括客户端请求服务器,服务器请求客户端、客户端请求客户端)、文件传输(包括客户端向服务器请求文件、客户端向服务器推送文件、服务器向客户端请求文件、服务器向客户端推送文件、
|
||||||
客户端之间请求、推送文件)、Redis等。
|
客户端之间请求、推送文件)、Redis等。
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net461;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net461;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Hosting;Socket;JsonRpc;NamedPipe;XmlRpc;Dmtp;TouchSocket</PackageTags>
|
<PackageTags>Hosting;Socket;JsonRpc;NamedPipe;XmlRpc;Dmtp;TouchSocket</PackageTags>
|
||||||
<Description>这是TouchSocket基于通用主机的扩展。目前包括Tcp、Udp、NamedPipe、Dmtp、SerialPort等服务。
|
<Description>这是TouchSocket基于通用主机的扩展。目前包括Tcp、Udp、NamedPipe、Dmtp、SerialPort等服务。
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// 感谢您的下载和使用
|
// 感谢您的下载和使用
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if !NET45
|
#if NETSTANDARD2_0_OR_GREATER||NET481_OR_GREATER||NET6_0_OR_GREATER
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Http;Https;HttpServer;HttpClient;WebSocket;WebSocketServer;WebSocketClient;TouchSocket</PackageTags>
|
<PackageTags>Http;Https;HttpServer;HttpClient;WebSocket;WebSocketServer;WebSocketClient;TouchSocket</PackageTags>
|
||||||
<Description>这是一个基于Http1.1协议的组件库。它能提供Http服务器、客户端、以及WebSocket组件。功能上支持大文件下载、上传、以及多线程下载和断点续传,小文件form上传,WebApi声明和执行。所提供的Http客户端是基于连接的,可以捕获连接和断开连接等消息。
|
<Description>这是一个基于Http1.1协议的组件库。它能提供Http服务器、客户端、以及WebSocket组件。功能上支持大文件下载、上传、以及多线程下载和断点续传,小文件form上传,WebApi声明和执行。所提供的Http客户端是基于连接的,可以捕获连接和断开连接等消息。
|
||||||
|
|
||||||
@@ -12,6 +12,14 @@
|
|||||||
<ItemGroup Condition="'$(TargetFramework)'=='net45'">
|
<ItemGroup Condition="'$(TargetFramework)'=='net45'">
|
||||||
<Reference Include="System.Web" />
|
<Reference Include="System.Web" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)'=='net462'">
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)'=='net472'">
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)'=='net481'">
|
<ItemGroup Condition="'$(TargetFramework)'=='net481'">
|
||||||
<Reference Include="System.Web" />
|
<Reference Include="System.Web" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>JsonRpc;TouchSocket</PackageTags>
|
<PackageTags>JsonRpc;TouchSocket</PackageTags>
|
||||||
<Description>这是一个提供JsonRpc服务器和客户端的组件库。可以通过该组件创建基于Tcp、Http、WebSocket协议的JsonRpc服务器和客户端,支持JsonRpc全部功能,可与Web,Android等平台无缝对接。
|
<Description>这是一个提供JsonRpc服务器和客户端的组件库。可以通过该组件创建基于Tcp、Http、WebSocket协议的JsonRpc服务器和客户端,支持JsonRpc全部功能,可与Web,Android等平台无缝对接。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Modbus;Master;TouchSocket</PackageTags>
|
<PackageTags>Modbus;Master;TouchSocket</PackageTags>
|
||||||
<Description>这是一个Modbus功能库,目前包括ModbusTcpMaster、ModbusUdpMaster、ModbusRtuMaster、ModbusRtuOverTcpMaster、ModbusRtuOverUdpMaster。
|
<Description>这是一个Modbus功能库,目前包括ModbusTcpMaster、ModbusUdpMaster、ModbusRtuMaster、ModbusRtuOverTcpMaster、ModbusRtuOverUdpMaster。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Pipeline;NamedPipe;Ipc;TouchSocket</PackageTags>
|
<PackageTags>Pipeline;NamedPipe;Ipc;TouchSocket</PackageTags>
|
||||||
<Description>这是一个基于命名管道的组件库。它模仿Tcp封装了命名管道的服务器和客户端,以及连接、断开连接等消息。功能上实现了多管道名称监听、流式数据解析,以极致接近Tcp的体验使用命名管道。
|
<Description>这是一个基于命名管道的组件库。它模仿Tcp封装了命名管道的服务器和客户端,以及连接、断开连接等消息。功能上实现了多管道名称监听、流式数据解析,以极致接近Tcp的体验使用命名管道。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net462;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Rpc;RateLimiting;TouchSocket</PackageTags>
|
<PackageTags>Rpc;RateLimiting;TouchSocket</PackageTags>
|
||||||
<Description>这是一个扩展于Rpc管理平台的限流包。目前支持开发DmtpRpc、XmlRpc、JsonRpc、WebApi等所有Rpc部分。
|
<Description>这是一个扩展于Rpc管理平台的限流包。目前支持开发DmtpRpc、XmlRpc、JsonRpc、WebApi等所有Rpc部分。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Rpc;TouchSocket</PackageTags>
|
<PackageTags>Rpc;TouchSocket</PackageTags>
|
||||||
<Description>这是一个超轻量、高性能、可扩展的Rpc管理平台框架。您可以基于该框架,快速开发出Rpc执行。目前已扩展开发DmtpRpc、XmlRpc、JsonRpc、WebApi部分。
|
<Description>这是一个超轻量、高性能、可扩展的Rpc管理平台框架。您可以基于该框架,快速开发出Rpc执行。目前已扩展开发DmtpRpc、XmlRpc、JsonRpc、WebApi部分。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Serial;SerialPort;TouchSocket</PackageTags>
|
<PackageTags>Serial;SerialPort;TouchSocket</PackageTags>
|
||||||
<Description>这是.Net(包括 C# 、VB.Net、F#)的一个整合性的串口通信框架。包含了串口连接、断开等一系列的通信事务。同时能一键式解决数据黏分包问题。使用协议模板,可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。
|
<Description>这是.Net(包括 C# 、VB.Net、F#)的一个整合性的串口通信框架。包含了串口连接、断开等一系列的通信事务。同时能一键式解决数据黏分包问题。使用协议模板,可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Swagger;TouchSocket</PackageTags>
|
<PackageTags>Swagger;TouchSocket</PackageTags>
|
||||||
<Description>这是适用于TouchSocket.WebApi的Swagger页面,可以直接在浏览器调试WebApi。
|
<Description>这是适用于TouchSocket.WebApi的Swagger页面,可以直接在浏览器调试WebApi。
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// 感谢您的下载和使用
|
// 感谢您的下载和使用
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#if !NET45
|
#if NETSTANDARD2_0_OR_GREATER||NET481_OR_GREATER||NET6_0_OR_GREATER
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace TouchSocket.WebApi
|
|||||||
public HttpResponse Response { get; }
|
public HttpResponse Response { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !NET45
|
#if NETSTANDARD2_0_OR_GREATER||NET481_OR_GREATER||NET6_0_OR_GREATER
|
||||||
|
|
||||||
public partial class WebApiEventArgs
|
public partial class WebApiEventArgs
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>WebApi;TouchSocket</PackageTags>
|
<PackageTags>WebApi;TouchSocket</PackageTags>
|
||||||
<Description>这是一个提供WebApi服务器和客户端的组件库。可以通过该组件创建WebApi服务解析器和客户端,让桌面端、Web端、移动端可以跨语言调用Rpc函数。功能支持自定义路由、Get传参、Post传参等。
|
<Description>这是一个提供WebApi服务器和客户端的组件库。可以通过该组件创建WebApi服务解析器和客户端,让桌面端、Web端、移动端可以跨语言调用Rpc函数。功能支持自定义路由、Get传参、Post传参等。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>XmlRpc;TouchSocket</PackageTags>
|
<PackageTags>XmlRpc;TouchSocket</PackageTags>
|
||||||
<Description>这是一个提供XmlRpc服务器和客户端的组件库。可以通过该组件创建XmlRpc服务解析器,完美支持XmlRpc数据类型,类型嵌套,Array等。也能与CookComputing.XmlRpcV2完美对接。不限Web,Android等平台。
|
<Description>这是一个提供XmlRpc服务器和客户端的组件库。可以通过该组件创建XmlRpc服务解析器,完美支持XmlRpc数据类型,类型嵌套,Array等。也能与CookComputing.XmlRpcV2完美对接。不限Web,Android等平台。
|
||||||
|
|
||||||
|
|||||||
@@ -18,14 +18,6 @@ namespace TouchSocket.Sockets
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// IP解析映射
|
/// IP解析映射
|
||||||
/// <para>
|
|
||||||
/// 支持端口,ip,域名等。具体格式如下:
|
|
||||||
/// <list type=" number">
|
|
||||||
/// <item>端口:直接按<see cref="int"/>入参,该操作一般在监听时使用。</item>
|
|
||||||
/// <item>ip:按127.0.0.1:7789入参。</item>
|
|
||||||
/// <item>域名:按tcp://127.0.0.1:7789、或者http://baidu.com入参。</item>
|
|
||||||
/// </list>
|
|
||||||
/// </para>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class IPHost : Uri
|
public class IPHost : Uri
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -468,23 +468,15 @@ namespace TouchSocket.Sockets
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Stop()
|
public override void Stop()
|
||||||
{
|
{
|
||||||
foreach (var item in this.m_monitors)
|
|
||||||
{
|
|
||||||
item.Socket.SafeDispose();
|
|
||||||
item.SocketAsyncEvent.SafeDispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_monitors.Clear();
|
|
||||||
|
|
||||||
this.Clear();
|
|
||||||
|
|
||||||
this.m_serverState = ServerState.Stopped;
|
this.m_serverState = ServerState.Stopped;
|
||||||
|
|
||||||
|
this.ReleaseAll();
|
||||||
|
|
||||||
this.PluginManager.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
this.PluginManager.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
private void ReleaseAll()
|
||||||
public override async Task StopAsync()
|
|
||||||
{
|
{
|
||||||
foreach (var item in this.m_monitors)
|
foreach (var item in this.m_monitors)
|
||||||
{
|
{
|
||||||
@@ -495,9 +487,14 @@ namespace TouchSocket.Sockets
|
|||||||
this.m_monitors.Clear();
|
this.m_monitors.Clear();
|
||||||
|
|
||||||
this.Clear();
|
this.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override async Task StopAsync()
|
||||||
|
{
|
||||||
this.m_serverState = ServerState.Stopped;
|
this.m_serverState = ServerState.Stopped;
|
||||||
await this.PluginManager.RaiseAsync(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
this.ReleaseAll();
|
||||||
|
await this.PluginManager.RaiseAsync(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default)).ConfigureFalseAwait();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -524,17 +521,8 @@ namespace TouchSocket.Sockets
|
|||||||
|
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
foreach (var item in this.m_monitors)
|
|
||||||
{
|
|
||||||
item.Socket.SafeDispose();
|
|
||||||
item.SocketAsyncEvent.SafeDispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.m_monitors.Clear();
|
|
||||||
|
|
||||||
this.Clear();
|
|
||||||
|
|
||||||
this.m_serverState = ServerState.Disposed;
|
this.m_serverState = ServerState.Disposed;
|
||||||
|
this.ReleaseAll();
|
||||||
this.PluginManager.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
this.PluginManager.Raise(nameof(IServerStopedPlugin.OnServerStoped), this, new ServiceStateEventArgs(this.m_serverState, default));
|
||||||
}
|
}
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
@@ -655,7 +643,10 @@ namespace TouchSocket.Sockets
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
this.Logger.Exception(ex);
|
if (this.m_serverState== ServerState.Running)
|
||||||
|
{
|
||||||
|
this.Logger.Exception(ex);
|
||||||
|
}
|
||||||
e.SafeDispose();
|
e.SafeDispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ namespace TouchSocket.Sockets
|
|||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
public static void SafeClose<T>(this T client) where T : ICloseObject
|
public static void SafeClose<T>(this T client) where T : ICloseObject
|
||||||
{
|
{
|
||||||
SafeClose(client);
|
SafeClose(client, "SafeClose");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ namespace TouchSocket.Sockets
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await c.ConnectAsync();
|
await c.ConnectAsync().ConfigureFalseAwait();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -83,7 +83,7 @@ namespace TouchSocket.Sockets
|
|||||||
{
|
{
|
||||||
this.ActionForCheck = async (c, i) =>
|
this.ActionForCheck = async (c, i) =>
|
||||||
{
|
{
|
||||||
await EasyTask.CompletedTask;
|
await EasyTask.CompletedTask.ConfigureFalseAwait();
|
||||||
return actionForCheck.Invoke(c, i);
|
return actionForCheck.Invoke(c, i);
|
||||||
};
|
};
|
||||||
return this;
|
return this;
|
||||||
@@ -142,9 +142,9 @@ namespace TouchSocket.Sockets
|
|||||||
pluginManager.Add<TClient, DisconnectEventArgs>(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this.OnTcpDisconnected);
|
pluginManager.Add<TClient, DisconnectEventArgs>(nameof(ITcpDisconnectedPlugin.OnTcpDisconnected), this.OnTcpDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task OnLoadedConfig(object sender, ConfigEventArgs e)
|
private async Task OnLoadedConfig(object sender, ConfigEventArgs e)
|
||||||
{
|
{
|
||||||
Task.Run(async () =>
|
_=Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (!this.m_polling)
|
if (!this.m_polling)
|
||||||
{
|
{
|
||||||
@@ -159,17 +159,17 @@ namespace TouchSocket.Sockets
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await Task.Delay(this.Tick);
|
await Task.Delay(this.Tick).ConfigureFalseAwait();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var b = await this.ActionForCheck.Invoke(client, failCount);
|
var b = await this.ActionForCheck.Invoke(client, failCount).ConfigureFalseAwait();
|
||||||
if (b == null)
|
if (b == null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (b == false)
|
else if (b == false)
|
||||||
{
|
{
|
||||||
if (await this.ActionForConnect.Invoke(client))
|
if (await this.ActionForConnect.Invoke(client).ConfigureFalseAwait())
|
||||||
{
|
{
|
||||||
failCount = 0;
|
failCount = 0;
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ namespace TouchSocket.Sockets
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return e.InvokeNext();
|
await e.InvokeNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnTcpDisconnected(TClient client, DisconnectEventArgs e)
|
private async Task OnTcpDisconnected(TClient client, DisconnectEventArgs e)
|
||||||
@@ -201,7 +201,7 @@ namespace TouchSocket.Sockets
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (await this.ActionForConnect.Invoke(client))
|
if (await this.ActionForConnect.Invoke(client).ConfigureFalseAwait())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net481;net45;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
<TargetFrameworks>net481;net45;net462;net472;netstandard2.0;net6.0;net7.0</TargetFrameworks>
|
||||||
<PackageTags>Tcp;Udp;Ssl;Socket;Saea;TouchSocket</PackageTags>
|
<PackageTags>Tcp;Udp;Ssl;Socket;Saea;TouchSocket</PackageTags>
|
||||||
<Description>TouchSocket是.Net(包括 C# 、VB.Net、F#)的一个整合性的socket网络通信框架。包含了 tcp、udp、ssl等一系列的通信模块。一键式解决 tcp 黏分包问题,udp大数据包分片组合问题等。使用协议模板,可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。
|
<Description>TouchSocket是.Net(包括 C# 、VB.Net、F#)的一个整合性的socket网络通信框架。包含了 tcp、udp、ssl等一系列的通信模块。一键式解决 tcp 黏分包问题,udp大数据包分片组合问题等。使用协议模板,可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user