using System.Net; using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Text; using DotNext; using DotNext.Threading; using Newtonsoft.Json; /// UDP接受数据包格式 public class UDPData { /// /// 接受到的时间 /// public required DateTime DateTime { get; set; } /// /// 发送来源的IP地址 /// public required string Address { get; set; } /// /// 发送来源的端口号 /// public required int Port { get; set; } /// /// 接受到的数据 /// public required byte[] Data { get; set; } /// /// 是否被读取过 /// public required bool HasRead { get; set; } /// /// 深度拷贝对象 /// /// UDPData public UDPData DeepClone() { var cloneData = new byte[this.Data.Length]; Buffer.BlockCopy(this.Data, 0, cloneData, 0, this.Data.Length); return new UDPData() { DateTime = this.DateTime, Address = new string(this.Address), Port = this.Port, Data = cloneData, HasRead = this.HasRead }; } /// /// 将UDP Data 转化为Json 格式字符串 /// /// json字符串 public override string ToString() { return JsonConvert.SerializeObject(this); } } /// /// UDP Server /// /// /// UDP 服务器 /// public class UDPServer { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private int listenPort; private UdpClient listener; private IPEndPoint groupEP; private Dictionary> udpData = new Dictionary>(); private AsyncReaderWriterLock udpDataLock = new AsyncReaderWriterLock(1); /// /// Construct a udp server with fixed port /// /// Device UDP Port /// UDPServer class public UDPServer(int port) { // Construction listenPort = port; try { listener = new UdpClient(listenPort); groupEP = new IPEndPoint(IPAddress.Any, listenPort); } catch (Exception e) { Console.WriteLine(e.ToString()); throw new ArgumentException( $"Not currect port num: {port}", nameof(port) ); } } /// /// Find UDP Receive Data According to ip address /// /// IP Address /// Read and Write Wait for Milliseconds /// 调用函数名称 /// 调用函数位置 /// UDP Data public Optional FindData( string ipAddr, int timeout = 1000, [CallerMemberName] string callerName = "", [CallerLineNumber] int callerLineNum = 0) { UDPData? data = null; logger.Debug($"Caller \"{callerName}|{callerLineNum}\": Try to find {ipAddr} UDP Data"); var startTime = DateTime.Now; var isTimeout = false; var timeleft = TimeSpan.FromMilliseconds(timeout); while (!isTimeout) { using (udpDataLock.AcquireWriteLock(timeleft)) { if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0) { data = udpData[ipAddr][0].DeepClone(); udpData[ipAddr].RemoveAt(0); logger.Debug($"Find UDP Data: {data.ToString()}"); break; } } timeleft = DateTime.Now.Subtract(startTime); isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout); } if (data == null) { logger.Trace("Get nothing even after time out"); return Optional.None(); } else { return Optional.Some((UDPData)data); } } /// /// 异步寻找目标发送的内容 /// /// 目标IP地址 /// 超时时间 /// 调用函数名称 /// 调用函数位置 /// /// 异步Optional 数据包: /// Optional 为空时,表明找不到数据; /// Optional 存在时,为最先收到的数据 /// public async ValueTask> FindDataAsync( string ipAddr, int timeout = 1000, [CallerMemberName] string callerName = "", [CallerLineNumber] int callerLineNum = 0) { UDPData? data = null; logger.Debug($"Caller \"{callerName}|{callerLineNum}\": Try to find {ipAddr} UDP Data"); var startTime = DateTime.Now; var isTimeout = false; var timeleft = TimeSpan.FromMilliseconds(timeout); while (!isTimeout) { using (await udpDataLock.AcquireWriteLockAsync(timeleft)) { if (udpData.ContainsKey(ipAddr) && udpData[ipAddr].Count > 0) { data = udpData[ipAddr][0].DeepClone(); udpData[ipAddr].RemoveAt(0); logger.Debug($"Find UDP Data: {data.ToString()}"); break; } } timeleft = DateTime.Now.Subtract(startTime); isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout); } if (data is null) { logger.Trace("Get nothing even after time out"); return Optional.None(); } else { return Optional.Some((UDPData)data); } } /// /// 获取还未被读取的数据列表 /// /// IP地址 /// 超时时间 /// 数据列表 public async ValueTask>> GetDataArrayAsync(string ipAddr, int timeout = 1000) { List? data = null; var startTime = DateTime.Now; var isTimeout = false; var timeleft = TimeSpan.FromMilliseconds(timeout); while (!isTimeout) { using (await udpDataLock.AcquireReadLockAsync(timeleft)) { if (udpData.ContainsKey(ipAddr)) { data = udpData[ipAddr]; logger.Debug($"Find UDP Data Array: {data.ToString()}"); break; } } timeleft = DateTime.Now.Subtract(startTime); isTimeout = timeleft >= TimeSpan.FromMilliseconds(timeout); } if (data is null) { logger.Trace("Get nothing even after time out"); return Optional.None>(); } else { return Optional.Some((List)data); } } /// /// 异步等待写响应 /// /// IP地址 /// UDP 端口 /// 超时时间范围 /// 接收响应包 public async ValueTask> WaitForAckAsync (string address, int port, int timeout = 1000) { var data = await FindDataAsync(address, timeout); if (!data.HasValue) throw new Exception("Get None even after time out!"); var recvData = data.Value; if (recvData.Address != address || recvData.Port != port) throw new Exception("Receive Data From Wrong Board!"); var retPack = WebProtocol.RecvRespPackage.FromBytes(recvData.Data); if (!retPack.IsSuccessful) throw new Exception("Not RecvDataPackage!", retPack.Error); return retPack.Value; } /// /// 异步等待数据 /// /// IP地址 /// UDP 端口 /// 超时时间范围 /// 接收数据包 public async ValueTask> WaitForDataAsync (string address, int port, int timeout = 1000) { var data = await FindDataAsync(address, timeout); if (!data.HasValue) throw new Exception("Get None even after time out!"); var recvData = data.Value; if (recvData.Address != address || recvData.Port != port) throw new Exception("Receive Data From Wrong Board!"); var retPack = WebProtocol.RecvDataPackage.FromBytes(recvData.Data); if (!retPack.IsSuccessful) throw new Exception("Not RecvDataPackage!", retPack.Error); return retPack.Value; } private void ReceiveHandler(IAsyncResult res) { logger.Trace("Enter handler"); var remoteEP = new IPEndPoint(IPAddress.Any, listenPort); byte[] bytes = listener.EndReceive(res, ref remoteEP); // Handle RemoteEP if (remoteEP is null) { logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:"); logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}"); goto BEGIN_RECEIVE; } // Handle Package PrintData(RecordUDPData(bytes, remoteEP)); BEGIN_RECEIVE: listener.BeginReceive(new AsyncCallback(ReceiveHandler), null); } private bool SendBytes(IPEndPoint endPoint, byte[] buf) { var sendLen = listener.Send(buf, endPoint); if (sendLen == buf.Length) { return true; } else { return false; } } private bool SendString(IPEndPoint endPoint, string text) { byte[] buf = Encoding.ASCII.GetBytes(text); var sendLen = listener.Send(buf, endPoint); if (sendLen == buf.Length) { return true; } else { return false; } } private UDPData RecordUDPData(byte[] bytes, IPEndPoint remoteEP) { using (udpDataLock.AcquireWriteLock()) { var remoteAddress = remoteEP.Address.ToString(); var remotePort = remoteEP.Port; var data = new UDPData() { Address = remoteAddress, Port = remotePort, Data = bytes, DateTime = DateTime.Now, HasRead = false, }; // Record UDP Receive Data if (udpData.ContainsKey(remoteAddress)) { var listData = udpData[remoteAddress]; listData.Add(data); logger.Trace("Receive data from old client"); } else { var list = new List(); list.Add(data); udpData.Add(remoteAddress, list); logger.Trace("Receive data from new client"); } return data; } } /// /// 输出UDP Data到log中 /// /// UDP数据 public void PrintData(UDPData data) { var bytes = data.Data; var sign = bytes[0]; string recvData = ""; if (sign == (byte)WebProtocol.PackSign.SendAddr) { var resData = WebProtocol.SendAddrPackage.FromBytes(bytes); if (resData.IsSuccessful) recvData = resData.Value.ToString(); else recvData = resData.Error.ToString(); } else if (sign == (byte)WebProtocol.PackSign.SendData) { } else if (sign == (byte)WebProtocol.PackSign.RecvData) { var resData = WebProtocol.RecvDataPackage.FromBytes(bytes); if (resData.IsSuccessful) recvData = resData.Value.Options.ToString(); else recvData = resData.Error.ToString(); } else if (sign == (byte)WebProtocol.PackSign.RecvResp) { var resData = WebProtocol.RecvRespPackage.FromBytes(bytes); if (resData.IsSuccessful) recvData = resData.Value.Options.ToString(); else recvData = resData.Error.ToString(); } else { recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length); } logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:"); logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}"); if (recvData.Length != 0) logger.Debug($" Decoded Data : {recvData}"); } /// /// 将所有数据输出到log中 /// /// void public void PrintAllData() { using (udpDataLock.AcquireReadLock()) { logger.Debug("Ready Data:"); foreach (var ip in udpData) { foreach (var data in ip.Value) { logger.Debug(data.ToString()); } } } } /// /// Start UDP Server /// /// None public void Start() { try { listener.BeginReceive(new AsyncCallback(ReceiveHandler), null); } catch (Exception e) { Console.WriteLine(e.ToString()); } finally { } } /// /// Close UDP Server /// /// None public void Stop() { listener.Close(); } }