using HslCommunication.Core.Net; using System; using System.Net; using System.Net.Sockets; using System.Text; namespace HslCommunication.Enthernet { /// <summary> /// Udp网络的服务器端类 /// </summary> public class NetUdpServer : NetworkServerBase { /// <summary> /// 获取或设置一次接收时的数据长度,默认2KB数据长度 /// </summary> public int ReceiveCacheLength { get; set; } = 2048; /// <summary> /// 根据指定的端口启动Upd侦听 /// </summary> /// <param name="port">端口号信息</param> public override void ServerStart(int port) { if (!IsStarted) { CoreSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //绑定网络地址 CoreSocket.Bind(new IPEndPoint(IPAddress.Any, port)); RefreshReceive(); LogNet?.WriteInfo(ToString(), StringResources.Language.NetEngineStart); IsStarted = true; } } /// <summary> /// 关闭引擎的操作 /// </summary> protected override void CloseAction() { AcceptString = null; AcceptByte = null; base.CloseAction(); } /// <summary> /// 重新开始接收数据 /// </summary> /// <exception cref="ArgumentNullException"></exception> private void RefreshReceive() { AppSession session = new AppSession(); session.WorkSocket = CoreSocket; session.UdpEndPoint = new IPEndPoint(IPAddress.Any, 0); session.BytesContent = new byte[ReceiveCacheLength]; // WorkSocket.BeginReceiveFrom(state.BytesHead, 0, 8, SocketFlags.None, ref state.UdpEndPoint, new AsyncCallback(ReceiveAsyncCallback), state); CoreSocket.BeginReceiveFrom(session.BytesContent, 0, ReceiveCacheLength, SocketFlags.None, ref session.UdpEndPoint, new AsyncCallback(AsyncCallback), session); } private void AsyncCallback(IAsyncResult ar) { if (ar.AsyncState is AppSession session) { try { int received = session.WorkSocket.EndReceiveFrom(ar, ref session.UdpEndPoint); // 释放连接关联 // session.WorkSocket = null; // 马上开始重新接收,提供性能保障 RefreshReceive(); // 处理数据 if (received >= HslProtocol.HeadByteLength) { // 检测令牌 if (CheckRemoteToken(session.BytesContent)) { session.IpEndPoint = (IPEndPoint)session.UdpEndPoint; int contentLength = BitConverter.ToInt32(session.BytesContent, HslProtocol.HeadByteLength - 4); if (contentLength == received - HslProtocol.HeadByteLength) { byte[] head = new byte[HslProtocol.HeadByteLength]; byte[] content = new byte[contentLength]; Array.Copy(session.BytesContent, 0, head, 0, HslProtocol.HeadByteLength); if (contentLength > 0) { Array.Copy(session.BytesContent, 32, content, 0, contentLength); } // 解析内容 content = HslProtocol.CommandAnalysis(head, content); int protocol = BitConverter.ToInt32(head, 0); int customer = BitConverter.ToInt32(head, 4); // 丢给数据中心处理 DataProcessingCenter(session, protocol, customer, content); } else { // 否则记录到日志 LogNet?.WriteWarn(ToString(), $"Should Rece:{(BitConverter.ToInt32(session.BytesContent, 4) + 8)} Actual:{received}"); } } else { LogNet?.WriteWarn(ToString(), StringResources.Language.TokenCheckFailed); } } else { LogNet?.WriteWarn(ToString(), $"Receive error, Actual:{received}"); } } catch (ObjectDisposedException) { //主程序退出的时候触发 } catch (Exception ex) { LogNet?.WriteException(ToString(), StringResources.Language.SocketEndReceiveException, ex); //重新接收,此处已经排除掉了对象释放的异常 RefreshReceive(); } finally { //state = null; } } } /*********************************************************************************************************** * * 无法使用如下的字节头接收来确认网络传输,总是报错为最小 * ***********************************************************************************************************/ //private void ReceiveAsyncCallback(IAsyncResult ar) //{ // if (ar.AsyncState is AsyncStateOne state) // { // try // { // state.AlreadyReceivedHead += state.WorkSocket.EndReceiveFrom(ar, ref state.UdpEndPoint); // if (state.AlreadyReceivedHead < state.HeadLength) // { // //接续接收头数据 // WorkSocket.BeginReceiveFrom(state.BytesHead, state.AlreadyReceivedHead, state.HeadLength - state.AlreadyReceivedHead, SocketFlags.None, // ref state.UdpEndPoint, new AsyncCallback(ReceiveAsyncCallback), state); // } // else // { // //开始接收内容 // int ReceiveLenght = BitConverter.ToInt32(state.BytesHead, 4); // if (ReceiveLenght > 0) // { // state.BytesContent = new byte[ReceiveLenght]; // WorkSocket.BeginReceiveFrom(state.BytesContent, state.AlreadyReceivedContent, state.BytesContent.Length - state.AlreadyReceivedContent, // SocketFlags.None, ref state.UdpEndPoint, new AsyncCallback(ContentReceiveAsyncCallback), state); // } // else // { // //没有内容了 // ThreadDealWithReveice(state, BitConverter.ToInt32(state.BytesHead, 0), state.BytesContent); // state = null; // RefreshReceive(); // } // } // } // catch(Exception ex) // { // LogHelper.SaveError(StringResources.Language.异步数据结束挂起发送出错, ex); // } // } //} //private void ContentReceiveAsyncCallback(IAsyncResult ar) //{ // if (ar.AsyncState is AsyncStateOne state) // { // try // { // state.AlreadyReceivedContent += state.WorkSocket.EndReceiveFrom(ar, ref state.UdpEndPoint); // if (state.AlreadyReceivedContent < state.BytesContent.Length) // { // //还需要继续接收 // WorkSocket.BeginReceiveFrom(state.BytesContent, state.AlreadyReceivedContent, state.BytesContent.Length - state.AlreadyReceivedContent, // SocketFlags.None, ref state.UdpEndPoint, new AsyncCallback(ContentReceiveAsyncCallback), state); // } // else // { // //接收完成了 // ThreadDealWithReveice(state, BitConverter.ToInt32(state.BytesHead, 0), new byte[0]); // state = null; // RefreshReceive(); // } // } // catch (Exception ex) // { // LogHelper.SaveError(StringResources.Language.异步数据结束挂起发送出错, ex); // } // } //} #region Data Process Center /// <summary> /// 数据处理中心 /// </summary> /// <param name="receive"></param> /// <param name="protocol"></param> /// <param name="customer"></param> /// <param name="content"></param> internal override void DataProcessingCenter(AppSession receive, int protocol, int customer, byte[] content) { if (protocol == HslProtocol.ProtocolUserBytes) { AcceptByte?.Invoke(receive, customer, content); } else if (protocol == HslProtocol.ProtocolUserString) { // 接收到文本数据 string str = Encoding.Unicode.GetString(content); AcceptString?.Invoke(receive, customer, str); } } /// <summary> /// 向指定的通信对象发送字符串数据 /// </summary> /// <param name="session">通信对象</param> /// <param name="customer">用户的指令头</param> /// <param name="str">实际发送的字符串数据</param> public void SendMessage(AppSession session, int customer, string str) { SendBytesAsync(session, HslProtocol.CommandBytes(customer, Token, str)); } /// <summary> /// 向指定的通信对象发送字节数据 /// </summary> /// <param name="session">连接对象</param> /// <param name="customer">用户的指令头</param> /// <param name="bytes">实际的数据</param> public void SendMessage(AppSession session, int customer, byte[] bytes) { SendBytesAsync(session, HslProtocol.CommandBytes(customer, Token, bytes)); } private new void SendBytesAsync(AppSession session, byte[] data) { try { session.WorkSocket.SendTo(data, data.Length, SocketFlags.None, session.UdpEndPoint); } catch (Exception ex) { LogNet?.WriteException("SendMessage", ex); } } #endregion #region Event Handle /// <summary> /// 当接收到文本数据的时候,触发此事件 /// </summary> public event Action<AppSession, NetHandle, string> AcceptString; /// <summary> /// 当接收到字节数据的时候,触发此事件 /// </summary> public event Action<AppSession, NetHandle, byte[]> AcceptByte; #endregion #region Object Override /// <summary> /// 获取本对象的字符串表示形式 /// </summary> /// <returns></returns> public override string ToString() { return "NetUdpServer"; } #endregion } }