新增fast序列化支持attribute序列化

新增IPHost支持直接IPv6格式
新增发布net462,net472平台。依赖与net45保持一致。
This commit is contained in:
若汝棋茗
2024-01-28 00:03:46 +08:00
parent da99c62b3b
commit ee0520f0d8
41 changed files with 580 additions and 328 deletions

View File

@@ -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>

View File

@@ -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的库。

View File

@@ -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的库。

View File

@@ -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);
} }

View File

@@ -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
} }
} }

View File

@@ -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);

View File

@@ -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);
} }

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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
{ {
} }

View File

@@ -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; }
} }
} }

View File

@@ -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;
}
} }
} }

View File

@@ -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);
}
}
}
}

View File

@@ -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);
} }
} }

View File

@@ -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));
}) })

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
} }

View File

@@ -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快速存储、运行时间测量器、文件快捷操作、高性能二进制序列化器、规范日志接口等。

View File

@@ -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:
{ {

View File

@@ -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)
{ {

View File

@@ -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>DMTPDuplex Message Transport Protocol双工消息传输协议是一个简单易用便捷高效且易于扩展的二进制数据协议。目前基于该协议已实现的功能包括连接验证、同步Id、Rpc包括客户端请求服务器服务器请求客户端、客户端请求客户端、文件传输包括客户端向服务器请求文件、客户端向服务器推送文件、服务器向客户端请求文件、服务器向客户端推送文件、 <Description>DMTPDuplex Message Transport Protocol双工消息传输协议是一个简单易用便捷高效且易于扩展的二进制数据协议。目前基于该协议已实现的功能包括连接验证、同步Id、Rpc包括客户端请求服务器服务器请求客户端、客户端请求客户端、文件传输包括客户端向服务器请求文件、客户端向服务器推送文件、服务器向客户端请求文件、服务器向客户端推送文件、
客户端之间请求、推送文件、Redis等。 客户端之间请求、推送文件、Redis等。

View File

@@ -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等服务。

View File

@@ -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;

View File

@@ -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" />

View File

@@ -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全部功能可与WebAndroid等平台无缝对接。 <Description>这是一个提供JsonRpc服务器和客户端的组件库。可以通过该组件创建基于Tcp、Http、WebSocket协议的JsonRpc服务器和客户端支持JsonRpc全部功能可与WebAndroid等平台无缝对接。

View File

@@ -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。

View File

@@ -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的体验使用命名管道。

View File

@@ -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部分。

View File

@@ -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部分。

View File

@@ -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#)的一个整合性的串口通信框架。包含了串口连接、断开等一系列的通信事务。同时能一键式解决数据黏分包问题。使用协议模板,可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。

View File

@@ -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。

View File

@@ -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;

View File

@@ -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
{ {

View File

@@ -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传参等。

View File

@@ -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完美对接。不限WebAndroid等平台。 <Description>这是一个提供XmlRpc服务器和客户端的组件库。可以通过该组件创建XmlRpc服务解析器完美支持XmlRpc数据类型类型嵌套Array等。也能与CookComputing.XmlRpcV2完美对接。不限WebAndroid等平台。

View File

@@ -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
{ {

View File

@@ -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;
} }

View File

@@ -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");
} }
} }
} }

View File

@@ -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;
} }

View File

@@ -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大数据包分片组合问题等。使用协议模板可快速实现「固定包头」、「固定长度」、「区间字符」等一系列的数据报文解析。