using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using HslCommunication.Core; using HslCommunication.Core.Net; namespace HslCommunication.Enthernet { /// /// Udp网络的服务器端类 /// public class NetUdpServer : NetworkServerBase { /// /// 获取或设置一次接收时的数据长度,默认2KB数据长度 /// public int ReceiveCacheLength { get; set; } = 2048; /// /// 根据指定的端口启动Upd侦听 /// /// 端口号信息 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; } } /// /// 关闭引擎的操作 /// protected override void CloseAction( ) { AcceptString = null; AcceptByte = null; base.CloseAction( ); } /// /// 重新开始接收数据 /// /// 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 /// /// 数据处理中心 /// /// /// /// /// 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 ); } } /// /// 向指定的通信对象发送字符串数据 /// /// 通信对象 /// 用户的指令头 /// 实际发送的字符串数据 public void SendMessage( AppSession session, int customer, string str ) { SendBytesAsync( session, HslProtocol.CommandBytes( customer, Token, str ) ); } /// /// 向指定的通信对象发送字节数据 /// /// 连接对象 /// 用户的指令头 /// 实际的数据 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 /// /// 当接收到文本数据的时候,触发此事件 /// public event Action AcceptString; /// /// 当接收到字节数据的时候,触发此事件 /// public event Action AcceptByte; #endregion #region Object Override /// /// 获取本对象的字符串表示形式 /// /// public override string ToString( ) { return "NetUdpServer"; } #endregion } }