You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
13 KiB
388 lines
13 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有
|
||
|
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||
|
|
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||
|
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||
|
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||
|
|
// Github源代码仓库:https://github.com/RRQM
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
using System;
|
||
|
|
using System.Collections.Concurrent;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.Net;
|
||
|
|
using System.Threading;
|
||
|
|
using TouchSocket.Core;
|
||
|
|
|
||
|
|
namespace TouchSocket.Sockets
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// UDP数据帧
|
||
|
|
/// </summary>
|
||
|
|
public struct UdpFrame
|
||
|
|
{
|
||
|
|
/// <summary>
|
||
|
|
/// Crc校验
|
||
|
|
/// </summary>
|
||
|
|
public byte[] Crc { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 数据
|
||
|
|
/// </summary>
|
||
|
|
public byte[] Data { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 是否为终结帧
|
||
|
|
/// </summary>
|
||
|
|
public bool FIN { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 数据ID
|
||
|
|
/// </summary>
|
||
|
|
public long ID { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 帧序号
|
||
|
|
/// </summary>
|
||
|
|
public ushort SN { get; set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 解析
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool Parse(byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
if (length > 11)
|
||
|
|
{
|
||
|
|
this.ID = TouchSocketBitConverter.Default.ToInt64(buffer, offset);
|
||
|
|
this.SN = TouchSocketBitConverter.Default.ToUInt16(buffer, 8 + offset);
|
||
|
|
this.FIN = buffer[10 + offset].GetBit(7) == 1;
|
||
|
|
if (this.FIN)
|
||
|
|
{
|
||
|
|
if (length > 13)
|
||
|
|
{
|
||
|
|
this.Data = new byte[length - 13];
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
this.Data = new byte[0];
|
||
|
|
}
|
||
|
|
this.Crc = new byte[2] { buffer[length - 2], buffer[length - 1] };
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
this.Data = new byte[length - 11];
|
||
|
|
}
|
||
|
|
|
||
|
|
Array.Copy(buffer, 11, this.Data, 0, this.Data.Length);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// UDP数据包
|
||
|
|
/// </summary>
|
||
|
|
[System.Diagnostics.DebuggerDisplay("Count={Count}")]
|
||
|
|
public class UdpPackage
|
||
|
|
{
|
||
|
|
private readonly ConcurrentQueue<UdpFrame> m_frames;
|
||
|
|
private readonly Timer m_timer;
|
||
|
|
private int m_count;
|
||
|
|
private int m_length;
|
||
|
|
|
||
|
|
private int m_mtu;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 构造函数
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="id"></param>
|
||
|
|
/// <param name="timeout"></param>
|
||
|
|
/// <param name="revStore"></param>
|
||
|
|
public UdpPackage(long id, int timeout, ConcurrentDictionary<long, UdpPackage> revStore)
|
||
|
|
{
|
||
|
|
this.ID = id;
|
||
|
|
this.m_frames = new ConcurrentQueue<UdpFrame>();
|
||
|
|
this.m_timer = new Timer((o) =>
|
||
|
|
{
|
||
|
|
if (revStore.TryRemove(this.ID, out UdpPackage udpPackage))
|
||
|
|
{
|
||
|
|
udpPackage.m_frames.Clear();
|
||
|
|
}
|
||
|
|
}, null, timeout, Timeout.Infinite);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当前长度
|
||
|
|
/// </summary>
|
||
|
|
public int Count => this.m_count;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Crc
|
||
|
|
/// </summary>
|
||
|
|
public byte[] Crc { get; private set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 包唯一标识
|
||
|
|
/// </summary>
|
||
|
|
public long ID { get; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 是否已完成
|
||
|
|
/// </summary>
|
||
|
|
public bool IsComplated => this.TotalCount > 0 ? (this.TotalCount == this.m_count ? true : false) : false;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 当前数据长度
|
||
|
|
/// </summary>
|
||
|
|
public int Length => this.m_length;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// MTU
|
||
|
|
/// </summary>
|
||
|
|
public int MTU => this.m_mtu + 11;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 总长度,在收到最后一帧之前,为-1。
|
||
|
|
/// </summary>
|
||
|
|
public int TotalCount { get; private set; } = -1;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 添加帧
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="frame"></param>
|
||
|
|
public void Add(UdpFrame frame)
|
||
|
|
{
|
||
|
|
Interlocked.Increment(ref this.m_count);
|
||
|
|
|
||
|
|
if (frame.FIN)
|
||
|
|
{
|
||
|
|
this.TotalCount = frame.SN + 1;
|
||
|
|
this.Crc = frame.Crc;
|
||
|
|
}
|
||
|
|
Interlocked.Add(ref this.m_length, frame.Data.Length);
|
||
|
|
if (frame.SN == 0)
|
||
|
|
{
|
||
|
|
this.m_mtu = frame.Data.Length;
|
||
|
|
}
|
||
|
|
this.m_frames.Enqueue(frame);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 获得数据
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="byteBlock"></param>
|
||
|
|
/// <returns></returns>
|
||
|
|
public bool TryGetData(ByteBlock byteBlock)
|
||
|
|
{
|
||
|
|
while (this.m_frames.TryDequeue(out UdpFrame frame))
|
||
|
|
{
|
||
|
|
byteBlock.Pos = frame.SN * this.m_mtu;
|
||
|
|
byteBlock.Write(frame.Data);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (byteBlock.Len != this.Length)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
byte[] crc = TouchSocket.Core.Crc.Crc16(byteBlock.Buffer, 0, byteBlock.Len);
|
||
|
|
if (crc[0] != this.Crc[0] || crc[1] != this.Crc[1])
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// UDP数据包的适配器
|
||
|
|
/// </summary>
|
||
|
|
public class UdpPackageAdapter : UdpDataHandlingAdapter
|
||
|
|
{
|
||
|
|
private readonly SnowflakeIDGenerator m_iDGenerator;
|
||
|
|
private readonly ConcurrentDictionary<long, UdpPackage> revStore;
|
||
|
|
private int m_mtu = 1472;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 构造函数
|
||
|
|
/// </summary>
|
||
|
|
public UdpPackageAdapter()
|
||
|
|
{
|
||
|
|
this.revStore = new ConcurrentDictionary<long, UdpPackage>();
|
||
|
|
this.m_iDGenerator = new SnowflakeIDGenerator(4);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override bool CanSendRequestInfo => false;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
public override bool CanSplicingSend => true;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 最大传输单元
|
||
|
|
/// </summary>
|
||
|
|
public int MTU
|
||
|
|
{
|
||
|
|
get => this.m_mtu + 11;
|
||
|
|
set => this.m_mtu = value > 11 ? value : 1472;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 接收超时时间,默认5000ms
|
||
|
|
/// </summary>
|
||
|
|
public int Timeout { get; set; } = 5000;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="remoteEndPoint"></param>
|
||
|
|
/// <param name="byteBlock"></param>
|
||
|
|
protected override void PreviewReceived(EndPoint remoteEndPoint, ByteBlock byteBlock)
|
||
|
|
{
|
||
|
|
var udpFrame = new UdpFrame();
|
||
|
|
if (udpFrame.Parse(byteBlock.Buffer, 0, byteBlock.Len))
|
||
|
|
{
|
||
|
|
UdpPackage udpPackage = this.revStore.GetOrAdd(udpFrame.ID, (i) => new UdpPackage(i, this.Timeout, this.revStore));
|
||
|
|
udpPackage.Add(udpFrame);
|
||
|
|
if (udpPackage.Length > this.MaxPackageSize)
|
||
|
|
{
|
||
|
|
this.revStore.TryRemove(udpPackage.ID, out _);
|
||
|
|
this.m_owner?.Logger.Error("数据长度大于设定的最大值。");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (udpPackage.IsComplated)
|
||
|
|
{
|
||
|
|
if (this.revStore.TryRemove(udpPackage.ID, out _))
|
||
|
|
{
|
||
|
|
using (var block = new ByteBlock(udpPackage.Length))
|
||
|
|
{
|
||
|
|
if (udpPackage.TryGetData(block))
|
||
|
|
{
|
||
|
|
this.GoReceived(remoteEndPoint, block, null);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="endPoint"></param>
|
||
|
|
/// <param name="buffer"></param>
|
||
|
|
/// <param name="offset"></param>
|
||
|
|
/// <param name="length"></param>
|
||
|
|
protected override void PreviewSend(EndPoint endPoint, byte[] buffer, int offset, int length)
|
||
|
|
{
|
||
|
|
if (length > this.MaxPackageSize)
|
||
|
|
{
|
||
|
|
throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送");
|
||
|
|
}
|
||
|
|
long id = this.m_iDGenerator.NextID();
|
||
|
|
int off = 0;
|
||
|
|
int surLen = length;
|
||
|
|
int freeRoom = this.m_mtu - 11;
|
||
|
|
ushort sn = 0;
|
||
|
|
/*|********|**|*|n|*/
|
||
|
|
/*|********|**|*|**|*/
|
||
|
|
while (surLen > 0)
|
||
|
|
{
|
||
|
|
byte[] data = new byte[this.m_mtu];
|
||
|
|
Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(id), 0, data, 0, 8);
|
||
|
|
Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(sn++), 0, data, 8, 2);
|
||
|
|
if (surLen > freeRoom)//有余
|
||
|
|
{
|
||
|
|
Buffer.BlockCopy(buffer, off, data, 11, freeRoom);
|
||
|
|
off += freeRoom;
|
||
|
|
surLen -= freeRoom;
|
||
|
|
this.GoSend(endPoint, data, 0, this.m_mtu);
|
||
|
|
}
|
||
|
|
else if (surLen + 2 <= freeRoom)//结束且能容纳Crc
|
||
|
|
{
|
||
|
|
byte flag = 0;
|
||
|
|
data[10] = flag.SetBit(7, 1);//设置终结帧
|
||
|
|
|
||
|
|
Buffer.BlockCopy(buffer, off, data, 11, surLen);
|
||
|
|
Buffer.BlockCopy(Crc.Crc16(buffer, offset, length), 0, data, 11 + surLen, 2);
|
||
|
|
|
||
|
|
this.GoSend(endPoint, data, 0, surLen + 11 + 2);
|
||
|
|
|
||
|
|
off += surLen;
|
||
|
|
surLen -= surLen;
|
||
|
|
}
|
||
|
|
else//结束但不能容纳Crc
|
||
|
|
{
|
||
|
|
Buffer.BlockCopy(buffer, off, data, 11, surLen);
|
||
|
|
this.GoSend(endPoint, data, 0, surLen + 11);
|
||
|
|
off += surLen;
|
||
|
|
surLen -= surLen;
|
||
|
|
|
||
|
|
byte[] finData = new byte[13];
|
||
|
|
Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(id), 0, finData, 0, 8);
|
||
|
|
Buffer.BlockCopy(TouchSocketBitConverter.Default.GetBytes(sn++), 0, finData, 8, 2);
|
||
|
|
byte flag = 0;
|
||
|
|
finData[10] = flag.SetBit(7, 1);
|
||
|
|
Buffer.BlockCopy(Crc.Crc16(buffer, offset, length), 0, finData, 11, 2);
|
||
|
|
this.GoSend(endPoint, finData, 0, finData.Length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="endPoint"></param>
|
||
|
|
/// <param name="transferBytes"></param>
|
||
|
|
protected override void PreviewSend(EndPoint endPoint, IList<ArraySegment<byte>> transferBytes)
|
||
|
|
{
|
||
|
|
int length = 0;
|
||
|
|
foreach (ArraySegment<byte> item in transferBytes)
|
||
|
|
{
|
||
|
|
length += item.Count;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (length > this.MaxPackageSize)
|
||
|
|
{
|
||
|
|
throw new OverlengthException("发送数据大于设定值,相同解析器可能无法收到有效数据,已终止发送");
|
||
|
|
}
|
||
|
|
|
||
|
|
using (var byteBlock = new ByteBlock(length))
|
||
|
|
{
|
||
|
|
foreach (ArraySegment<byte> item in transferBytes)
|
||
|
|
{
|
||
|
|
byteBlock.Write(item.Array, item.Offset, item.Count);
|
||
|
|
}
|
||
|
|
this.PreviewSend(endPoint, byteBlock.Buffer, 0, byteBlock.Len);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="requestInfo"></param>
|
||
|
|
protected override void PreviewSend(IRequestInfo requestInfo)
|
||
|
|
{
|
||
|
|
throw new NotImplementedException();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// <inheritdoc/>
|
||
|
|
/// </summary>
|
||
|
|
protected override void Reset()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|