This commit is contained in:
snltty
2023-09-14 15:16:12 +08:00
commit eb08f03738
173 changed files with 14799 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
using System.Diagnostics;
using System.IO;
namespace common.libs
{
public sealed class CommandHelper
{
public static string Windows(string arg, string[] commands)
{
return Execute("cmd.exe", arg, commands);
}
public static string Linux(string arg, string[] commands)
{
return Execute("/bin/bash", arg, commands);
}
public static string Osx(string arg, string[] commands)
{
return Execute("/bin/bash", arg, commands);
}
public static Process Execute(string fileName, string arg)
{
Process proc = new Process();
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = fileName;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.Arguments = arg;
proc.StartInfo.Verb = "runas";
proc.Start();
//Process proc = Process.Start(fileName, arg);
return proc;
}
public static string Execute(string fileName, string arg, string[] commands)
{
Process proc = new Process();
proc.StartInfo.WorkingDirectory = Path.GetFullPath(Path.Join("./"));
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.FileName = fileName;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.Arguments = arg;
proc.StartInfo.Verb = "runas";
proc.Start();
if (commands.Length > 0)
{
for (int i = 0; i < commands.Length; i++)
{
proc.StandardInput.WriteLine(commands[i]);
}
}
proc.StandardInput.AutoFlush = true;
proc.StandardInput.WriteLine("exit");
proc.StandardInput.Close();
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
proc.Close();
proc.Dispose();
return output;
}
}
}

View File

@@ -0,0 +1,17 @@
namespace common.libs
{
public enum EnumBufferSize : byte
{
KB_1 = 0,
KB_2 = 1,
KB_4 = 2,
KB_8 = 3,
KB_16 = 4,
KB_32 = 5,
KB_64 = 6,
KB_128 = 7,
KB_256 = 8,
KB_512 = 9,
KB_1024 = 10,
}
}

27
common.libs/GCHelper.cs Normal file
View File

@@ -0,0 +1,27 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace common.libs
{
public static class GCHelper
{
[DllImport("kernel32.dll")]
public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
public static void FlushMemory()
{
GC.Collect();
GC.SuppressFinalize(true);
GC.WaitForPendingFinalizers();
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
{
SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
}
}
public static void Gc(object obj)
{
GC.Collect();
GC.SuppressFinalize(obj);
}
}
}

21
common.libs/Helper.cs Normal file
View File

@@ -0,0 +1,21 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace common.libs
{
public static class Helper
{
public static byte[] EmptyArray = Array.Empty<byte>();
public static byte[] TrueArray = new byte[] { 1 };
public static byte[] FalseArray = new byte[] { 0 };
public static async Task Await()
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
AppDomain.CurrentDomain.ProcessExit += (sender, e) => cancellationTokenSource.Cancel();
Console.CancelKeyPress += (sender, e) => cancellationTokenSource.Cancel();
await Task.Delay(-1, cancellationTokenSource.Token);
}
}
}

123
common.libs/Logger.cs Normal file
View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace common.libs
{
public sealed class Logger
{
private static readonly Lazy<Logger> lazy = new Lazy<Logger>(() => new Logger());
public static Logger Instance => lazy.Value;
private readonly ConcurrentQueue<LoggerModel> queue = new ConcurrentQueue<LoggerModel>();
public Action<LoggerModel> OnLogger { get; set; } = (param) => { };
public int PaddingWidth { get; set; } = 50;
#if DEBUG
public LoggerTypes LoggerLevel { get; set; } = LoggerTypes.DEBUG;
#else
public LoggerTypes LoggerLevel { get; set; } = LoggerTypes.WARNING;
#endif
private Logger()
{
new Thread(() =>
{
while (true)
{
while (queue.Count > 0)
{
if (queue.TryDequeue(out LoggerModel model))
{
OnLogger?.Invoke(model);
}
}
Thread.Sleep(15);
}
})
{ IsBackground = true }.Start();
}
public int lockNum = 0;
public void Lock()
{
Interlocked.Increment(ref lockNum);
}
public void UnLock()
{
Interlocked.Decrement(ref lockNum);
}
public void Debug(string content, params object[] args)
{
if (args != null && args.Length > 0)
{
content = string.Format(content, args);
}
Enqueue(new LoggerModel { Type = LoggerTypes.DEBUG, Content = content });
}
public void Info(string content, params object[] args)
{
if (args != null && args.Length > 0)
{
content = string.Format(content, args);
}
Enqueue(new LoggerModel { Type = LoggerTypes.INFO, Content = content });
}
public void Warning(string content, params object[] args)
{
if (args != null && args.Length > 0)
{
content = string.Format(content, args);
}
Enqueue(new LoggerModel { Type = LoggerTypes.WARNING, Content = content });
}
public void Error(string content, params object[] args)
{
if (args != null && args.Length > 0)
{
content = string.Format(content, args);
}
Enqueue(new LoggerModel { Type = LoggerTypes.ERROR, Content = content });
}
public void Error(Exception ex)
{
Enqueue(new LoggerModel { Type = LoggerTypes.ERROR, Content = ex + "" });
}
public void FATAL(string content, params object[] args)
{
if (args != null && args.Length > 0)
{
content = string.Format(content, args);
}
Enqueue(new LoggerModel { Type = LoggerTypes.FATAL, Content = content });
}
public void FATAL(Exception ex)
{
Enqueue(new LoggerModel { Type = LoggerTypes.FATAL, Content = ex + "" });
}
public void Enqueue(LoggerModel model)
{
queue.Enqueue(model);
}
}
public sealed class LoggerModel
{
public LoggerTypes Type { get; set; } = LoggerTypes.INFO;
public DateTime Time { get; set; } = DateTime.Now;
public string Content { get; set; } = string.Empty;
}
public enum LoggerTypes : byte
{
DEBUG = 0,
INFO = 1,
WARNING = 2,
ERROR = 3,
FATAL = 4,
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Net;
using System.Net.Sockets;
namespace common.libs
{
public static class NetworkHelper
{
/// <summary>
/// 域名解析
/// </summary>
/// <param name="domain"></param>
/// <returns></returns>
public static IPAddress GetDomainIp(string domain)
{
try
{
if (string.IsNullOrWhiteSpace(domain)) return null;
if (IPAddress.TryParse(domain, out IPAddress ip))
{
return ip;
}
IPAddress[] list = Dns.GetHostEntry(domain).AddressList;
if (list.Length > 0) return list[0];
return null;
}
catch (Exception)
{
}
return null;
}
#if DISABLE_IPV6 || (!UNITY_EDITOR && ENABLE_IL2CPP && !UNITY_2018_3_OR_NEWER)
public static bool IPv6Support = false;
#elif !UNITY_2019_1_OR_NEWER && !UNITY_2018_4_OR_NEWER && (!UNITY_EDITOR && ENABLE_IL2CPP && UNITY_2018_3_OR_NEWER)
public static bool IPv6Support = Socket.OSSupportsIPv6 && int.Parse(UnityEngine.Application.unityVersion.Remove(UnityEngine.Application.unityVersion.IndexOf('f')).Split('.')[2]) >= 6;
#elif UNITY_2018_2_OR_NEWER
public static bool IPv6Support = Socket.OSSupportsIPv6;
#elif UNITY
#pragma warning disable 618
public static bool IPv6Support = Socket.SupportsIPv6;
#pragma warning restore 618
#else
public static bool IPv6Support = Socket.OSSupportsIPv6;
#endif
}
}

View File

@@ -0,0 +1,79 @@
using System.Threading;
namespace common.libs
{
public sealed class NumberSpace
{
private ulong num;
public NumberSpace(ulong defaultVal = 0)
{
num = defaultVal;
}
public ulong Increment()
{
Interlocked.CompareExchange(ref num, 0, ulong.MaxValue - 10000);
Interlocked.Increment(ref num);
return num;
}
}
public sealed class NumberSpaceUInt32
{
private uint num = 0;
public NumberSpaceUInt32(uint defaultVal = 0)
{
num = defaultVal;
}
public uint Get()
{
return num;
}
public uint Increment()
{
Interlocked.CompareExchange(ref num, 0, uint.MaxValue - 10000);
Interlocked.Increment(ref num);
return num;
}
public void Decrement()
{
Interlocked.Decrement(ref num);
}
public void Reset(uint val = 0)
{
Interlocked.Exchange(ref num, val);
}
}
public sealed class BoolSpace
{
bool _default;
private bool value;
public BoolSpace(bool defaultVal = true)
{
_default = defaultVal;
value = _default;
}
/// <summary>
/// 是否是原始值
/// </summary>
public bool IsDefault => value == _default;
public bool Reverse()
{
value = !_default;
return value;
}
public void Reset()
{
value = _default;
}
}
}

View File

@@ -0,0 +1,99 @@
using System;
namespace common.libs
{
public sealed class ReceiveDataBuffer
{
private Memory<byte> items { get; set; }
private int size = 0;
public int Size
{
get
{
return size;
}
private set
{
if (value == 0)
{
items = Helper.EmptyArray;
}
else if (value > items.Length)
{
Memory<byte> newItems = new byte[value].AsMemory();
items.CopyTo(newItems);
items = newItems;
}
}
}
public Memory<byte> Data
{
get
{
return items;
}
}
public void AddRange(Memory<byte> data)
{
if(data.Length > 0)
{
BeResize(data.Length);
data.CopyTo(items.Slice(size, data.Length));
size += data.Length;
}
}
public void AddRange(Memory<byte> data, int length)
{
if (length > 0)
{
BeResize(length);
data.Slice(0, length).CopyTo(items.Slice(size, length));
size += length;
}
}
public void AddRange(byte[] data, int offset, int length)
{
if(length > 0)
{
BeResize(length);
data.AsMemory(offset, length).CopyTo(items.Slice(size, length));
size += length;
}
}
public void RemoveRange(int index, int count)
{
if (index >= 0 && count > 0 && size - index >= count)
{
size -= count;
if (index < size)
{
items.Slice(index + count, size - index).CopyTo(items.Slice(index, size - index));
}
}
}
public void Clear(bool clearData = false)
{
size = 0;
if (clearData)
{
Size = 0;
}
}
private void BeResize(int length)
{
int _size = size + length;
if (_size > items.Length)
{
int newsize = items.Length * 2;
if (newsize < _size)
{
newsize = _size;
}
Size = newsize;
}
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace common.libs
{
public sealed class ReflectionHelper
{
public static IEnumerable<Type> GetInterfaceSchieves(Type type)
{
return GetInterfaceSchieves(AppDomain.CurrentDomain.GetAssemblies(), type);
}
public static IEnumerable<Type> GetInterfaceSchieves(Assembly[] assemblys, Type type)
{
return assemblys.SelectMany(c => c.GetTypes())
.Where(c => !c.IsAbstract).Where(c => c.GetInterfaces().Contains(type));
}
public static IEnumerable<Type> GetSubClass(Assembly[] assemblys, Type type)
{
return assemblys.SelectMany(c => c.GetTypes())
.Where(c => !c.IsAbstract).Where(c => c.IsSubclassOf(type));
}
public static IEnumerable<Type> GetEnums(Assembly[] assemblys)
{
return assemblys.SelectMany(c => c.GetTypes())
.Where(c => c.IsEnum);
}
}
}

209
common.libs/WheelTimer.cs Normal file
View File

@@ -0,0 +1,209 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
namespace common.libs
{
/// <summary>
/// 时间轮延时任务
/// </summary>
public sealed class WheelTimer<T>
{
//流转次数,
long ticks = 0;
//槽数
int bucketLength = 2 << 8;
//mask = bucketLength-1;ticks & mask; 获得槽下标
int mask = 0;
//精度应使用Thread.Sleep(1)时间的倍数
int tickDurationMs = 30;
//槽
WheelTimerBucket<T>[] buckets = Array.Empty<WheelTimerBucket<T>>();
//先入列,等待入槽
ConcurrentQueue<WheelTimerTimeout<T>> timeouts = new ConcurrentQueue<WheelTimerTimeout<T>>();
AutoResetEvent autoReset = new AutoResetEvent(true);
public WheelTimer()
{
CreateBuckets();
Worker();
}
public WheelTimerTimeout<T> NewTimeout(WheelTimerTimeoutTask<T> task, int delayMs, bool reuse = false)
{
if (task == null)
{
throw new ArgumentNullException("task must be not null");
}
if (delayMs <= 1)
{
throw new ArgumentNullException("delayMs must be > 1 ms");
}
WheelTimerTimeout<T> timeout = new WheelTimerTimeout<T> { Delay = delayMs, Task = task, Reuse = reuse };
timeouts.Enqueue(timeout);
return timeout;
}
private void CreateBuckets()
{
mask = bucketLength - 1;
buckets = new WheelTimerBucket<T>[bucketLength];
for (int i = 0; i < buckets.Length; i++)
{
buckets[i] = new WheelTimerBucket<T>();
}
}
double ticksMore = 0;
private void Worker()
{
new Thread(() =>
{
for (; ; )
{
long start = DateTime.UtcNow.Ticks;
//等下一个时间点
WaitForNextTick();
//待入槽队列入槽
TransferTimeoutsToBuckets();
//执行当前槽的任务
ExpireTimeouts(buckets[(ticks & mask)]);
ticks++;
ticksMore += (DateTime.UtcNow.Ticks - start) / TimeSpan.TicksPerMillisecond - tickDurationMs;
double forwardCount = (ticksMore / tickDurationMs);
while (forwardCount > 1)
{
ticksMore -= tickDurationMs;
start = DateTime.UtcNow.Ticks;
//待入槽队列入槽
TransferTimeoutsToBuckets();
//执行当前槽的任务
ExpireTimeouts(buckets[(ticks & mask)]);
ticks++;
ticksMore += (DateTime.UtcNow.Ticks - start) / TimeSpan.TicksPerMillisecond;
forwardCount = ticksMore / tickDurationMs;
}
}
})
{ IsBackground = true }.Start();
}
private void WaitForNextTick()
{
autoReset.WaitOne(tickDurationMs);
}
private void TransferTimeoutsToBuckets()
{
if (timeouts.Count == 0)
{
return;
}
//一次最多转移100000个
for (int i = 0; i < 100000; i++)
{
if (timeouts.TryDequeue(out WheelTimerTimeout<T> timeout) == false)
{
break;
}
if (timeout.IsCanceled)
{
continue;
}
//所需格子数
int expireTicks = (int)((timeout.Delay + ticksMore) / tickDurationMs);
//所需轮次
timeout.Rounds = expireTicks / buckets.Length;
//除轮次外,剩下的格子数应在哪个槽中
int stopIndex = ((int)(ticks & mask) + (expireTicks - timeout.Rounds * buckets.Length)) & mask;
buckets[stopIndex].AddTimeout(timeout);
}
}
private void ExpireTimeouts(WheelTimerBucket<T> bucket)
{
LinkedListNode<WheelTimerTimeout<T>> timeout = bucket.List.First;
while (timeout != null)
{
bool remove = false;
if (timeout.Value.Rounds <= 0 && timeout.Value.IsCanceled == false)
{
remove = true;
try
{
timeout.Value.Task.Callback?.Invoke(timeout.Value);
}
catch (Exception) { }
}
else if (timeout.Value.IsCanceled)
{
remove = true;
}
else
{
timeout.Value.Rounds--;
}
LinkedListNode<WheelTimerTimeout<T>> next = timeout.Next;
if (remove)
{
bucket.Remove(timeout);
if (timeout.Value.Reuse && !timeout.Value.IsCanceled)
{
timeouts.Enqueue(timeout.Value);
}
}
timeout = next;
}
}
}
public sealed class WheelTimerBucket<T>
{
public LinkedList<WheelTimerTimeout<T>> List { get; private set; } = new LinkedList<WheelTimerTimeout<T>>();
public void AddTimeout(WheelTimerTimeout<T> timeout)
{
List.AddLast(timeout);
}
public void Remove(LinkedListNode<WheelTimerTimeout<T>> node)
{
List.Remove(node);
}
}
public sealed class WheelTimerTimeout<T>
{
public int Delay { get; init; } = 0;
public int Rounds { get; set; } = 0;
public bool Reuse { get; init; } = false;
public WheelTimerTimeoutTask<T> Task { get; init; }
public TimeoutState State { get; private set; } = TimeoutState.Normal;
public bool IsCanceled => State == TimeoutState.Canceld;
public void Cancel()
{
State = TimeoutState.Canceld;
}
public enum TimeoutState
{
Normal = 1 << 0,
Canceld = 1 << 1,
}
}
public sealed class WheelTimerTimeoutTask<T>
{
/// <summary>
/// 保存状态数据
/// </summary>
public T State { get; init; }
/// <summary>
/// 不要抛异常影响轮转时间
/// </summary>
public Action<WheelTimerTimeout<T>> Callback { get; init; }
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Diagnostics;
using System.Linq;
namespace common.libs
{
public class WindowHelper
{
#region
public static Process[] processes;
public static void UpdateCurrentProcesses()
{
processes = Process.GetProcesses();
}
public static bool GetHasWindowByName(string name)
{
return processes != null && processes.Any(c => c.ProcessName.Equals(name, StringComparison.OrdinalIgnoreCase));
}
#endregion
}
}

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<Configurations>Debug;Release;ReleaseLinux</Configurations>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<PublishAot>false</PublishAot>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;RELEASE</DefineConstants>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLinux|AnyCPU'">
<DefineConstants>TRACE;RELEASE</DefineConstants>
<DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup Condition="'$(VisualStudioVersion)'&gt;='17.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0-preview.7.22375.6" />
</ItemGroup>
<ItemGroup Condition="'$(VisualStudioVersion)'&lt;'17.0'">
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,110 @@
using common.libs.extends;
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace common.libs.database
{
/// <summary>
/// 配置文件缓存
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IConfigDataProvider<T> where T : class, new()
{
/// <summary>
/// 加载
/// </summary>
/// <returns></returns>
Task<T> Load();
/// <summary>
/// 加载
/// </summary>
/// <returns></returns>
Task<string> LoadString();
/// <summary>
/// 保存
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task Save(T model);
/// <summary>
/// 保存
/// </summary>
/// <param name="jsonStr"></param>
/// <returns></returns>
Task Save(string jsonStr);
}
/// <summary>
/// 配置文件的文件缓存
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class ConfigDataFileProvider<T> : IConfigDataProvider<T> where T : class, new()
{
public async Task<T> Load()
{
string fileName = GetTableName(typeof(T));
try
{
if (File.Exists(fileName))
{
string str = (await File.ReadAllTextAsync(fileName).ConfigureAwait(false));
return str.DeJson<T>();
}
else
{
Logger.Instance.Warning($"{fileName} 配置文件缺失~");
}
}
catch (Exception ex)
{
Logger.Instance.Error($"{fileName} 配置文件解析有误~ :{ex}");
}
return null;
}
public async Task<string> LoadString()
{
string fileName = GetTableName(typeof(T));
if (File.Exists(fileName))
{
return (await File.ReadAllTextAsync(fileName).ConfigureAwait(false));
}
return string.Empty;
}
public async Task Save(T model)
{
try
{
string fileName = GetTableName(typeof(T));
await File.WriteAllTextAsync(fileName, model.ToJsonIndented(), Encoding.UTF8).ConfigureAwait(false);
}
catch (Exception)
{
}
}
public async Task Save(string jsonStr)
{
try
{
string fileName = GetTableName(typeof(T));
await File.WriteAllTextAsync(fileName, jsonStr, Encoding.UTF8).ConfigureAwait(false);
}
catch (Exception)
{
}
}
private string GetTableName(Type type)
{
var attrs = type.GetCustomAttributes(typeof(TableAttribute), false);
if (attrs.Length > 0)
{
return $"{(attrs[0] as TableAttribute).Name}.json";
}
return $"{type.Name}.json";
}
}
}

View File

@@ -0,0 +1,315 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace common.libs.extends
{
public static class NumberExtends
{
#region
#region double
public static byte[] ToBytes(this double num)
{
return BitConverter.GetBytes(num);
}
public static unsafe void ToBytes(this double value, Memory<byte> memory)
{
ref double v = ref value;
fixed (void* p = &v)
{
new Span<byte>(p, 8).CopyTo(memory.Span);
}
}
#endregion
#region 64
public static byte[] ToBytes(this long num)
{
return BitConverter.GetBytes(num);
}
public static unsafe void ToBytes(this long value, Memory<byte> memory)
{
ref long v = ref value;
fixed (void* p = &v)
{
new Span<byte>(p, 8).CopyTo(memory.Span);
}
}
public static unsafe void ToBytes(this long[] value, Memory<byte> memory)
{
fixed (void* p = &value[0])
{
new Span<byte>(p, value.Length * sizeof(long)).CopyTo(memory.Span);
}
}
public static byte[] ToBytes(this ulong value)
{
return BitConverter.GetBytes(value);
}
public static unsafe void ToBytes(this ulong value, Memory<byte> memory)
{
ref ulong v = ref value;
fixed (void* p = &v)
{
new Span<byte>(p, sizeof(ulong)).CopyTo(memory.Span);
}
}
public static unsafe void ToBytes(this ulong[] value, Memory<byte> memory)
{
fixed (void* p = &value[0])
{
new Span<byte>(p, value.Length * 8).CopyTo(memory.Span);
}
}
public static unsafe void ToBytes(this Memory<ulong> value, Memory<byte> memory)
{
fixed (void* p = &value.Span[0])
{
new Span<byte>(p, value.Length * 8).CopyTo(memory.Span);
}
}
#endregion
#region 32
public static byte[] ToBytes(this int num)
{
return BitConverter.GetBytes(num);
}
public static unsafe void ToBytes(this int value, Memory<byte> memory)
{
ref int v = ref value;
fixed (void* p = &v)
{
new Span<byte>(p, 4).CopyTo(memory.Span);
}
}
public static unsafe void ToBytes(this int[] value, Memory<byte> memory)
{
fixed (void* p = &value[0])
{
new Span<byte>(p, value.Length * sizeof(int)).CopyTo(memory.Span);
}
}
public static byte[] ToBytes(this uint num)
{
return BitConverter.GetBytes(num);
}
public static unsafe void ToBytes(this uint value, Memory<byte> memory)
{
ref uint v = ref value;
fixed (void* p = &v)
{
new Span<byte>(p, 4).CopyTo(memory.Span);
}
}
public static unsafe void ToBytes(this uint[] value, Memory<byte> memory)
{
fixed (void* p = &value[0])
{
new Span<byte>(p, value.Length * sizeof(uint)).CopyTo(memory.Span);
}
}
#endregion
#region 16
public static byte[] ToBytes(this short num)
{
return BitConverter.GetBytes(num);
}
public static unsafe void ToBytes(this short value, Memory<byte> memory)
{
ref short v = ref value;
fixed (void* p = &v)
{
var span = new Span<byte>(p, sizeof(short));
memory.Span[0] = span[0];
memory.Span[1] = span[1];
}
}
public static unsafe void ToBytes(this short[] value, Memory<byte> memory)
{
fixed (void* p = &value[0])
{
new Span<byte>(p, value.Length * sizeof(short)).CopyTo(memory.Span);
}
}
public static byte[] ToBytes(this ushort num)
{
return BitConverter.GetBytes(num);
}
public static unsafe void ToBytes(this ushort value, Memory<byte> memory)
{
ref ushort v = ref value;
fixed (void* p = &v)
{
var span = new Span<byte>(p, sizeof(ushort));
memory.Span[0] = span[0];
memory.Span[1] = span[1];
}
}
public static unsafe void ToBytes(this ushort[] value, Memory<byte> memory)
{
fixed (void* p = &value[0])
{
new Span<byte>(p, value.Length * sizeof(ushort)).CopyTo(memory.Span);
}
}
#endregion
#endregion
#region
#region double
public static double ToDouble(this byte[] bytes, int startindex = 0)
{
return Unsafe.As<byte, double>(ref bytes[startindex]);
}
public static double ToDouble(this Span<byte> span)
{
return Unsafe.As<byte, double>(ref MemoryMarshal.GetReference(span));
}
public static double ToDouble(this ReadOnlySpan<byte> span)
{
return Unsafe.As<byte, double>(ref MemoryMarshal.GetReference(span));
}
#endregion
#region 64
public static long ToInt64(this ReadOnlySpan<byte> span)
{
return Unsafe.As<byte, long>(ref MemoryMarshal.GetReference(span));
}
public static long ToInt64(this Span<byte> span)
{
return Unsafe.As<byte, long>(ref MemoryMarshal.GetReference(span));
}
public static long ToInt64(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToInt64();
}
public static long ToInt64(this Memory<byte> memory)
{
return memory.Span.ToInt64();
}
public static ulong ToUInt64(this ReadOnlySpan<byte> span)
{
return Unsafe.As<byte, ulong>(ref MemoryMarshal.GetReference(span));
}
public static ulong ToUInt64(this Span<byte> span)
{
return Unsafe.As<byte, ulong>(ref MemoryMarshal.GetReference(span));
}
public static ulong ToUInt64(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToUInt64();
}
public static ulong ToUInt64(this Memory<byte> memory)
{
return memory.Span.ToUInt64();
}
#endregion
#region 32
public static int ToInt32(this byte[] bytes, int startindex = 0)
{
return Unsafe.As<byte, ushort>(ref bytes[startindex]);
}
public static int ToInt32(this ReadOnlySpan<byte> span)
{
return Unsafe.As<byte, int>(ref MemoryMarshal.GetReference(span));
}
public static int ToInt32(this Span<byte> span)
{
return Unsafe.As<byte, int>(ref MemoryMarshal.GetReference(span));
}
public static int ToInt32(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToInt32();
}
public static int ToInt32(this Memory<byte> memory)
{
return memory.Span.ToInt32();
}
public static uint ToUInt32(this ReadOnlySpan<byte> span)
{
return Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(span));
}
public static uint ToUInt32(this Span<byte> span)
{
return Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(span));
}
public static uint ToUInt32(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToUInt32();
}
public static uint ToUInt32(this Memory<byte> memory)
{
return memory.Span.ToUInt32();
}
#endregion
#region 16
public static short ToInt16(this ReadOnlySpan<byte> span)
{
return Unsafe.As<byte, short>(ref MemoryMarshal.GetReference(span));
}
public static short ToInt16(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToInt16();
}
public static short[] ToInt16Array(this ReadOnlySpan<byte> span)
{
short[] res = new short[span.Length / 2];
int index = 0;
for (int i = 0; i < res.Length; i++)
{
res[i] = span.Slice(index, 2).ToInt16();
index += 2;
}
return res;
}
public static short[] ToInt16Array(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToInt16Array();
}
public static ushort ToUInt16(this ReadOnlySpan<byte> span)
{
return Unsafe.As<byte, ushort>(ref MemoryMarshal.GetReference(span));
}
public static ushort ToUInt16(this Span<byte> span)
{
return Unsafe.As<byte, ushort>(ref MemoryMarshal.GetReference(span));
}
public static ushort ToUInt16(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToUInt16();
}
public static ushort ToUInt16(this Memory<byte> memory)
{
return memory.Span.ToUInt16();
}
public static ushort[] ToUInt16Array(this ReadOnlySpan<byte> span)
{
ushort[] res = new ushort[span.Length / 2];
int index = 0;
for (int i = 0; i < res.Length; i++)
{
res[i] = span.Slice(index, 2).ToUInt16();
index += 2;
}
return res;
}
public static ushort[] ToUInt16Array(this ReadOnlyMemory<byte> memory)
{
return memory.Span.ToUInt16Array();
}
#endregion
#endregion
}
}

View File

@@ -0,0 +1,40 @@
using common.libs.jsonConverters;
using System.Text.Json;
using System.Text.Unicode;
namespace common.libs.extends
{
public static class SerialzeExtends
{
private static JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
PropertyNameCaseInsensitive = true,
WriteIndented = true,
Converters = { new IPAddressJsonConverter(), new IPEndpointJsonConverter(), new DateTimeConverter() }
};
private static JsonSerializerOptions jsonSerializerOptionsIndented = new JsonSerializerOptions
{
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(UnicodeRanges.All),
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
PropertyNameCaseInsensitive = true,
WriteIndented = true,
Converters = { new IPAddressJsonConverter(), new IPEndpointJsonConverter(), new DateTimeConverter() }
};
public static string ToJson(this object obj)
{
return JsonSerializer.Serialize(obj, jsonSerializerOptions);
}
public static string ToJsonIndented(this object obj)
{
return JsonSerializer.Serialize(obj, jsonSerializerOptionsIndented);
}
public static T DeJson<T>(this string json)
{
return JsonSerializer.Deserialize<T>(json, options: jsonSerializerOptions);
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
namespace common.libs.extends
{
public static class SocketExtends
{
public static void WindowsUdpBug(this Socket socket)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
try
{
const uint IOC_IN = 0x80000000;
int IOC_VENDOR = 0x18000000;
int SIO_UDP_CONNRESET = (int)(IOC_IN | IOC_VENDOR | 12);
socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
}
catch (Exception)
{
}
}
}
public static void IPv6Only(this Socket socket, AddressFamily family, bool val)
{
if (NetworkHelper.IPv6Support && family == AddressFamily.InterNetworkV6)
{
try
{
socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, val);
}
catch (Exception)
{
}
}
}
public static void SafeClose(this Socket socket)
{
if (socket != null)
{
try
{
socket.Shutdown(SocketShutdown.Both);
//调试注释
socket.Disconnect(false);
}
catch (Exception)
{
}
finally
{
socket.Close();
}
}
}
public static void Reuse(this Socket socket, bool reuse = true)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuse);
}
public static void ReuseBind(this Socket socket, IPEndPoint ip)
{
socket.Reuse(true);
socket.Bind(ip);
}
public static void KeepAlive(this Socket socket, int time = 60, int interval = 5, int retryCount = 5)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, interval);
//socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, retryCount);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, time);
}
}
}

View File

@@ -0,0 +1,441 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.Unicode;
namespace common.libs.extends
{
/// <summary>
/// | Method | Mean | Error | StdDev | Median | Rank | Gen0 | Allocated |
/// |--------------------- |-----------:|----------:|-----------:|-----------:|-----:|-------:|----------:|
/// utf8
/// | TestUTF8OldWrite | 121.167 ns | 0.3973 ns | 1.0467 ns | 120.881 ns | 5 | 0.0687 | 144 B |
/// | TestUTF8OldRead | 495.893 ns | 5.7436 ns | 15.4297 ns | 490.850 ns | 8 | 0.9174 | 1920 B |
/// | TestUTF8OldWriteRead | 656.620 ns | 6.7862 ns | 18.1138 ns | 650.086 ns | 9 | 0.9861 | 2064 B |
/// utf8优化
/// | TestUTF8NewWrite | 92.238 ns | 0.3602 ns | 0.9799 ns | 92.008 ns | 4 | - | - |
/// | TestUTF8NewRead | 135.711 ns | 0.5058 ns | 1.3412 ns | 136.129 ns | 6 | 0.1338 | 280 B |
/// | TestUTF8NewWriteRead | 255.466 ns | 0.5967 ns | 1.6336 ns | 255.028 ns | 7 | 0.1335 | 280 B |
/// utf16
/// | TestUTF16Write | 7.898 ns | 0.0723 ns | 0.2004 ns | 7.933 ns | 1 | - | - |
/// | TestUTF16Read | 19.062 ns | 0.1379 ns | 0.3682 ns | 19.032 ns | 2 | 0.0497 | 104 B |
/// | TestUTF16WriteRead | 25.630 ns | 0.1499 ns | 0.4102 ns | 25.524 ns | 3 | 0.0497 | 104 B |
/// </summary>
public static class StringExtends
{
/// <summary>
/// 截取
/// </summary>
/// <param name="str"></param>
/// <param name="start"></param>
/// <param name="maxLength"></param>
/// <returns></returns>
public static string SubStr(this string str, int start, int maxLength)
{
if (maxLength + start > str.Length)
{
maxLength = str.Length - start;
}
return str.Substring(start, maxLength);
}
/// <summary>
/// md5
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static string Md5(this string input)
{
MD5 md5Hasher = MD5.Create();
byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
StringBuilder sBuilder = new();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
#region utf8
/// <summary>
/// 慢,但通用,性能基准 1Allocated 1
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static byte[] ToBytes(this string str)
{
if (str == null) return Helper.EmptyArray;
return Encoding.UTF8.GetBytes(str);
}
/// <summary>
/// 慢,但通用,性能基准 1Allocated 1
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static string GetString(this Span<byte> span)
{
return Encoding.UTF8.GetString(span);
}
/// <summary>
/// 慢,但通用,性能基准 1Allocated 1
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static string GetString(this ReadOnlySpan<byte> span)
{
return Encoding.UTF8.GetString(span);
}
/// <summary>
/// 慢,但通用,性能基准 1Allocated 1
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static string GetString(this Memory<byte> span)
{
return Encoding.UTF8.GetString(span.Span);
}
/// <summary>
/// 慢,但通用,性能基准 1Allocated 1
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static string GetString(this ReadOnlyMemory<byte> span)
{
return Encoding.UTF8.GetString(span.Span);
}
#endregion
#region utf8优化
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// utf16Length = str.AsSpan().Length
/// 保存的时候,保存 utf16Length 和 utf8Length
/// </summary>
/// <param name="str"></param>
/// <param name="bytes"></param>
/// <returns></returns>
public static int ToUTF8Bytes(this ReadOnlySpan<char> str, Memory<byte> bytes)
{
if (str.Length == 0) return 0;
Utf8.FromUtf16(str, bytes.Span, out var _, out var utf8Length, replaceInvalidSequences: false);
return utf8Length;
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static Memory<byte> ToUTF8Bytes(this string str)
{
int utf16Length = 0, utf8Length = 0;
byte[] bytes;
int length;
if (str != null)
{
var source = str.AsSpan();
utf16Length = source.Length;
bytes = new byte[(source.Length + 1) * 3 + 8];
Utf8.FromUtf16(str, bytes.AsSpan(8), out _, out utf8Length, replaceInvalidSequences: false);
length = utf8Length + 8;
}
else
{
bytes = new byte[8];
length = 8;
}
utf16Length.ToBytes(bytes);
utf8Length.ToBytes(bytes.AsMemory(4));
return bytes.AsMemory(0, length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="span"></param>
/// <param name="utf16Length"></param>
/// <param name="utf8Length"></param>
/// <returns></returns>
public static string GetUTF8String(this Span<byte> span, int utf16Length, int utf8Length)
{
if (span.Length == 0) return string.Empty;
return ReadUtf8(span, utf16Length, utf8Length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static string GetUTF8String(this Span<byte> span)
{
if (span.Length == 0) return string.Empty;
int utf16Length = span.ToInt32();
int utf8Length = span.Slice(4).ToInt32();
return ReadUtf8(span.Slice(8), utf16Length, utf8Length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="span"></param>
/// <param name="utf16Length"></param>
/// <param name="utf8Length"></param>
/// <returns></returns>
public static string GetUTF8String(this ReadOnlySpan<byte> span, int utf16Length, int utf8Length)
{
if (span.Length == 0) return string.Empty;
return ReadUtf8(span, utf16Length, utf8Length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static string GetUTF8String(this ReadOnlySpan<byte> span)
{
if (span.Length == 0) return string.Empty;
int utf16Length = span.ToInt32();
int utf8Length = span.Slice(4).ToInt32();
return ReadUtf8(span.Slice(8), utf16Length, utf8Length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="memory"></param>
/// <param name="utf16Length"></param>
/// <param name="utf8Length"></param>
/// <returns></returns>
public static string GetUTF8String(this Memory<byte> memory, int utf16Length, int utf8Length)
{
if (memory.Length == 0) return string.Empty;
return ReadUtf8(memory.Span, utf16Length, utf8Length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="memory"></param>
/// <returns></returns>
public static string GetUTF8String(this Memory<byte> memory)
{
if (memory.Length == 0) return string.Empty;
int utf16Length = memory.ToInt32();
int utf8Length = memory.Slice(4).ToInt32();
return ReadUtf8(memory.Slice(8).Span, utf16Length, utf8Length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="memory"></param>
/// <param name="utf16Length"></param>
/// <param name="utf8Length"></param>
/// <returns></returns>
public static string GetUTF8String(this ReadOnlyMemory<byte> memory, int utf16Length, int utf8Length)
{
if (memory.Length == 0)
return string.Empty;
return ReadUtf8(memory.Span, utf16Length, utf8Length);
}
/// <summary>
/// UTF8比较快但是中文字符比UTF16更大Allocated 0.135
/// write 0.76 read 0.27 readwrite 0.38
/// </summary>
/// <param name="memory"></param>
/// <returns></returns>
public static string GetUTF8String(this ReadOnlyMemory<byte> memory)
{
if (memory.Length == 0)
return string.Empty;
int utf16Length = memory.ToInt32();
int utf8Length = memory.Slice(4).ToInt32();
return ReadUtf8(memory.Slice(8).Span, utf16Length, utf8Length);
}
#endregion
#region utf16
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="str"></param>
/// <param name="bytes"></param>
public static ReadOnlySpan<byte> GetUTF16Bytes(this string str)
{
if (str == null) return Helper.EmptyArray;
return MemoryMarshal.AsBytes(str.AsSpan());
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static byte[] ToUTF16Bytes(this string str)
{
byte[] bytes;
if (str != null)
{
var source = MemoryMarshal.AsBytes(str.AsSpan());
bytes = new byte[source.Length + 4];
source.CopyTo(bytes.AsSpan(4));
}
else
{
bytes = new byte[4];
}
str.Length.ToBytes(bytes);
return bytes;
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="span"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this Span<byte> span, int strLength)
{
if (span.Length == 0) return string.Empty;
return ReadUtf16(span, strLength);
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="span"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this Span<byte> span)
{
if (span.Length == 0) return string.Empty;
int strLength = span.ToInt32();
return ReadUtf16(span.Slice(4), strLength);
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="span"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this ReadOnlySpan<byte> span, int strLength)
{
if (span.Length == 0) return string.Empty;
return ReadUtf16(span, strLength);
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="span"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this ReadOnlySpan<byte> span)
{
if (span.Length == 0)
return string.Empty;
int strLength = span.ToInt32();
return ReadUtf16(span.Slice(4), strLength);
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="memory"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this Memory<byte> memory, int strLength)
{
if (memory.Length == 0)
return string.Empty;
return ReadUtf16(memory.Span, strLength);
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="memory"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this Memory<byte> memory)
{
if (memory.Length == 0) return string.Empty;
return memory.Span.GetUTF16String();
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="memory"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this ReadOnlyMemory<byte> memory, int strLength)
{
if (memory.Length == 0)
return string.Empty;
return ReadUtf16(memory.Span, strLength);
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="memory"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this ReadOnlyMemory<byte> memory)
{
if (memory.Length == 0) return string.Empty;
return memory.Span.GetUTF16String();
}
/// <summary>
/// utf16非常快但是ASCII 字符的大小将是原来的两倍中文字符则比UTF8略小Allocated 0.05
/// write 0.065 read 0.038 readwrite 0.039
/// </summary>
/// <param name="memory"></param>
/// <param name="strLength"></param>
/// <returns></returns>
public static string GetUTF16String(this byte[] memory, int strLength)
{
if (memory.Length == 0) return string.Empty;
return ReadUtf16(memory, strLength);
}
#endregion
static string ReadUtf8(ReadOnlySpan<byte> span, int utf16Length, int utf8Length)
{
unsafe
{
fixed (byte* p = &span[0])
{
return string.Create(utf16Length, ((IntPtr)p, utf8Length), static (dest, state) =>
{
var src = MemoryMarshal.CreateSpan(ref Unsafe.AsRef<byte>((byte*)state.Item1), state.Item2);
Utf8.ToUtf16(src, dest, out var bytesRead, out var charsWritten, replaceInvalidSequences: false);
});
}
}
}
static string ReadUtf16(ReadOnlySpan<byte> span, int strLength)
{
ReadOnlySpan<char> src = MemoryMarshal.Cast<byte, char>(span).Slice(0, strLength);
return new string(src);
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Text.Json.Serialization;
using System.Text.Json;
namespace common.libs.jsonConverters
{
public sealed class DateTimeConverter : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.Parse(s: reader.GetString());
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace common.libs.jsonConverters
{
public sealed class IPAddressJsonConverter : JsonConverter<IPAddress>
{
public override IPAddress Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return IPAddress.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, IPAddress value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace common.libs.jsonConverters
{
public sealed class IPEndpointJsonConverter : JsonConverter<IPEndPoint>
{
public override IPEndPoint Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return IPEndPoint.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, IPEndPoint value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
}

View File

@@ -0,0 +1,140 @@
using System;
namespace common.libs.socks5
{
/// <summary>
/// 数据验证结果
/// </summary>
[Flags]
public enum EnumProxyValidateDataResult : byte
{
Equal = 1,
TooShort = 2,
TooLong = 4,
Bad = 8,
}
/// <summary>
/// 当前处于socks5协议的哪一步
/// </summary>
public enum Socks5EnumStep : byte
{
/// <summary>
/// 第一次请求,处理认证方式
/// </summary>
Request = 1,
/// <summary>
/// 如果有认证
/// </summary>
Auth = 2,
/// <summary>
/// 发送命令CONNECT BIND 还是 UDP ASSOCIATE
/// </summary>
Command = 3,
/// <summary>
/// 转发
/// </summary>
Forward = 4,
/// <summary>
/// udp转发
/// </summary>
ForwardUdp = 5,
None = 0
}
/// <summary>
/// socks5的连接地址类型
/// </summary>
public enum Socks5EnumAddressType : byte
{
IPV4 = 1,
Domain = 3,
IPV6 = 4
}
/// <summary>
/// socks5的认证类型
/// </summary>
public enum Socks5EnumAuthType : byte
{
NoAuth = 0x00,
GSSAPI = 0x01,
Password = 0x02,
IANA = 0x03,
UnKnow = 0x80,
NotSupported = 0xff,
}
/// <summary>
/// socks5的认证状态0成功 其它失败
/// </summary>
public enum Socks5EnumAuthState : byte
{
Success = 0x00,
UnKnow = 0xff,
}
/// <summary>
/// socks5的请求指令
/// </summary>
public enum Socks5EnumRequestCommand : byte
{
/// <summary>
/// 连接上游服务器
/// </summary>
Connect = 1,
/// <summary>
/// 绑定客户端会接收来自代理服务器的链接著名的FTP被动模式
/// </summary>
Bind = 2,
/// <summary>
/// UDP中继
/// </summary>
UdpAssociate = 3
}
/// <summary>
/// socks5的请求的回复数据的指令
/// </summary>
public enum Socks5EnumResponseCommand : byte
{
/// <summary>
/// 代理服务器连接目标服务器成功
/// </summary>
ConnecSuccess = 0,
/// <summary>
/// 代理服务器故障
/// </summary>
ServerError = 1,
/// <summary>
/// 代理服务器规则集不允许连接
/// </summary>
ConnectNotAllow = 2,
/// <summary>
/// 网络无法访问
/// </summary>
NetworkError = 3,
/// <summary>
/// 目标服务器无法访问(主机名无效)
/// </summary>
ConnectFail = 4,
/// <summary>
/// 连接目标服务器被拒绝
/// </summary>
DistReject = 5,
/// <summary>
/// TTL已过期
/// </summary>
TTLTimeout = 6,
/// <summary>
/// 不支持的命令
/// </summary>
CommandNotAllow = 7,
/// <summary>
/// 不支持的目标服务器地址类型
/// </summary>
AddressNotAllow = 8,
/// <summary>
/// 未分配
/// </summary>
Unknow = 8,
}
}

View File

@@ -0,0 +1,322 @@
using common.libs.extends;
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Net;
using System.Text;
namespace common.libs.socks5
{
/// <summary>
/// socks5 数据包解析和组装
/// </summary>
public sealed class Socks5Parser
{
/// <summary>
/// 获取客户端过来的支持的认证方式列表
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static Socks5EnumAuthType[] GetAuthMethods(ReadOnlySpan<byte> span)
{
//VER NMETHODS METHODS
// 1 1 1-255
//版本 支持哪些认证 一个认证方式一个字节
byte length = span[1];
Socks5EnumAuthType[] res = new Socks5EnumAuthType[length];
for (byte i = 0; i < length; i++)
{
res[i] = (Socks5EnumAuthType)span[2 + i];
}
return res;
}
/// <summary>
/// 获取账号密码
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
public static (string username, string password) GetPasswordAuthInfo(Span<byte> span)
{
/*
子版本 username长度 username password长度 password
0x01
*/
string username = span.Slice(2, span[1]).GetString();
string password = span.Slice(2 + span[1] + 1, span[2 + span[1]]).GetString();
return (username, password);
}
/// <summary>
/// 获取地址
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static Memory<byte> GetRemoteEndPoint(Memory<byte> data, out Socks5EnumAddressType addressType, out ushort port, out int index)
{
//VERSION COMMAND RSV ATYPE DST.ADDR DST.PORT
//去掉 VERSION COMMAND RSV
Memory<byte> memory = data.Slice(3);
Span<byte> span = memory.Span;
addressType = (Socks5EnumAddressType)span[0];
index = 0;
Memory<byte> result = Helper.EmptyArray;
switch (addressType)
{
case Socks5EnumAddressType.IPV4:
{
result = memory.Slice(1, 4);
index = 1 + 4;
}
break;
case Socks5EnumAddressType.Domain:
{
result = memory.Slice(2, span[1]);
index = 2 + span[1];
}
break;
case Socks5EnumAddressType.IPV6:
{
result = memory.Slice(1, 16);
index = 1 + 16;
}
break;
default:
break;
}
port = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(index, 2));
index += 2;
index += 3;
return result;
}
/// <summary>
/// 获取udp中继中的数据
/// </summary>
/// <param name="span"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public static Memory<byte> GetUdpData(Memory<byte> span)
{
//RSV FRAG ATYPE DST.ADDR DST.PORT DATA
//去掉 RSV FRAG RSV占俩字节
span = span.Slice(3);
return (Socks5EnumAddressType)span.Span[0] switch
{
Socks5EnumAddressType.IPV4 => span[(1 + 4 + 2)..],
Socks5EnumAddressType.IPV6 => span[(1 + 16 + 2)..],
Socks5EnumAddressType.Domain => span[(2 + span.Span[1] + 2)..],
_ => Helper.EmptyArray,
};
}
/// <summary>
/// 生成connect返回包
/// </summary>
/// <param name="remoteEndPoint"></param>
/// <param name="responseCommand"></param>
/// <returns></returns>
public static unsafe byte[] MakeConnectResponse(IPEndPoint remoteEndPoint, byte responseCommand)
{
//VER REP RSV ATYPE BND.ADDR BND.PORT
byte[] res = new byte[6 + (remoteEndPoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16)];
var span = res.AsSpan();
res[0] = 5;
res[1] = responseCommand;
res[2] = 0;
res[3] = (byte)(remoteEndPoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? Socks5EnumAddressType.IPV4 : Socks5EnumAddressType.IPV6);
remoteEndPoint.Address.TryWriteBytes(span.Slice(4), out _);
int port = remoteEndPoint.Port;
ref int _port = ref port;
fixed (void* p = &_port)
{
byte* pp = (byte*)p;
res[^2] = *(pp + 1);
res[^1] = *pp;
}
return res;
}
/// <summary>
/// 生成udp中中继数据包
/// </summary>
/// <param name="remoteEndPoint"></param>
/// <param name="data"></param>
/// <returns></returns>
public static unsafe byte[] MakeUdpResponse(IPEndPoint remoteEndPoint, Memory<byte> data, out int length)
{
//RSV FRAG ATYPE DST.ADDR DST.PORT DATA
//RSV占俩字节
int ipLength = (remoteEndPoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16);
length = 4 + ipLength + 2 + data.Length;
byte[] res = ArrayPool<byte>.Shared.Rent(length);
var span = res.AsSpan();
res[0] = 0;
res[1] = 0;
res[2] = 0; //FRAG
res[3] = (byte)(ipLength == 4 ? Socks5EnumAddressType.IPV4 : Socks5EnumAddressType.IPV6);
int index = 4;
remoteEndPoint.Address.TryWriteBytes(span.Slice(index), out _);
index += ipLength;
int port = remoteEndPoint.Port;
ref int _port = ref port;
fixed (void* p = &_port)
{
byte* pp = (byte*)p;
res[index] = *(pp + 1);
res[index + 1] = *pp;
}
index += 2;
data.CopyTo(res.AsMemory(index, data.Length));
return res;
}
public static void Return(byte[] data)
{
ArrayPool<byte>.Shared.Return(data);
}
public static EnumProxyValidateDataResult ValidateData(Socks5EnumStep step, Memory<byte> data)
{
return step switch
{
Socks5EnumStep.Request => ValidateRequestData(data),
Socks5EnumStep.Command => ValidateCommandData(data),
Socks5EnumStep.Auth => ValidateAuthData(data, Socks5EnumAuthType.Password),
Socks5EnumStep.Forward => EnumProxyValidateDataResult.Equal,
Socks5EnumStep.ForwardUdp => EnumProxyValidateDataResult.Equal,
_ => EnumProxyValidateDataResult.Equal
};
}
/// <summary>
/// 验证 request数据完整性
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static EnumProxyValidateDataResult ValidateRequestData(Memory<byte> data)
{
/*
* VERSION METHODS_COUNT METHODS
1字节 1字节 1到255字节长度由METHODS_COUNT值决定
0x05 0x03 0x00 0x01 0x02
*/
if (data.Length < 2 || data.Length < 2 + data.Span[1])
{
return EnumProxyValidateDataResult.TooShort;
}
/*
if (data.Length > 2 + data.Span[1])
{
return EnumProxyValidateDataResult.TooLong;
}*/
return EnumProxyValidateDataResult.Equal;
}
/// <summary>
/// 验证command数据完整性
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static EnumProxyValidateDataResult ValidateCommandData(Memory<byte> data)
{
/*
* VERSION COMMAND RSV ADDRESS_TYPE DST.ADDR DST.PORT
* 1 1 1 1 1-255 2
* 域名模式下 DST.ADDR第一个字节是域名长度那么整个数据至少8个字节
*/
if (data.Length < 8) return EnumProxyValidateDataResult.TooShort;
var span = data.Span;
int addrLength = (Socks5EnumAddressType)span[3] switch
{
Socks5EnumAddressType.IPV4 => 4 + 2,
Socks5EnumAddressType.Domain => span[4] + 1 + 2, //DST.ADDR第一个字节是域名长度 剩下的才是域名数据
Socks5EnumAddressType.IPV6 => 16 + 2,
_ => throw new NotImplementedException(),
};
if (data.Length < 4 + addrLength)
{
return EnumProxyValidateDataResult.TooShort;
}
/*
if (data.Length > 4 + addrLength)
{
return EnumProxyValidateDataResult.TooLong;
}
*/
return EnumProxyValidateDataResult.Equal;
}
/// <summary>
/// 验证认证数据完整性
/// </summary>
/// <param name="data"></param>
/// <param name="authType"></param>
/// <returns></returns>
public static EnumProxyValidateDataResult ValidateAuthData(Memory<byte> data, Socks5EnumAuthType authType)
{
return authType switch
{
Socks5EnumAuthType.NoAuth => EnumProxyValidateDataResult.Equal,
Socks5EnumAuthType.Password => ValidateAuthPasswordData(data),
Socks5EnumAuthType.GSSAPI => EnumProxyValidateDataResult.Equal,
Socks5EnumAuthType.IANA => EnumProxyValidateDataResult.Equal,
Socks5EnumAuthType.UnKnow => EnumProxyValidateDataResult.Bad,
Socks5EnumAuthType.NotSupported => EnumProxyValidateDataResult.Bad,
_ => EnumProxyValidateDataResult.Bad,
};
}
private static EnumProxyValidateDataResult ValidateAuthPasswordData(Memory<byte> data)
{
/*
VERSION USERNAME_LENGTH USERNAME PASSWORD_LENGTH PASSWORD
1字节 1字节 1到255字节 1字节 1到255字节
0x01 0x01 0x0a 0x01 0x0a
*/
var span = data.Slice(1).Span;
//至少有 USERNAME_LENGTH PASSWORD_LENGTH 字节以上
if (span.Length <= 2)
{
return EnumProxyValidateDataResult.TooShort;
}
byte nameLength = span[0];
//至少有 USERNAME_LENGTH USERNAME PASSWORD_LENGTH
if (span.Length < nameLength + 1 + 1)
{
return EnumProxyValidateDataResult.TooShort;
}
byte passwordLength = span[1 + nameLength];
if (span.Length < 1 + 1 + nameLength + passwordLength)
{
return EnumProxyValidateDataResult.TooShort;
}
/*
if (span.Length > 1 + 1 + nameLength + passwordLength)
{
return EnumProxyValidateDataResult.TooLong;
}
*/
return EnumProxyValidateDataResult.Equal;
}
}
}