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
}
}