using HslCommunication.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using HslCommunication.Core.Net;
using System.Net;
using System.Net.Sockets;
namespace HslCommunication.Enthernet
{
///
/// 一个基于异步高性能的客户端网络类,支持主动接收服务器的消息
///
public class NetComplexClient : NetworkXBase
{
#region Constructor
///
/// 实例化一个对象
///
public NetComplexClient( )
{
}
#endregion
#region Private Member
///
/// 客户端的核心连接块
///
private AppSession stateone = new AppSession( );
///
/// 指示客户端是否处于正在连接服务器中
///
private bool IsClientConnecting = false;
///
/// 登录服务器的判断锁
///
private object lock_connecting = new object( );
#endregion
#region 基本属性块
///
/// 客户端系统是否启动
///
public bool IsClientStart { get; set; } = false;
///
/// 重连接失败的次数
///
public int ConnectFailedCount { get; set; } = 0;
///
/// 客户端登录的标识名称,可以为ID号,也可以为登录名
///
public string ClientAlias { get; set; } = "";
///
/// 远程服务器的IP地址和端口
///
public IPEndPoint EndPointServer { get; set; } = new IPEndPoint( IPAddress.Any, 0 );
///
/// 服务器的时间,自动实现和服务器同步
///
public DateTime ServerTime { get; private set; } = DateTime.Now;
///
/// 系统与服务器的延时时间,单位毫秒
///
public int DelayTime { get; private set; }
#endregion
#region 事件委托块
///
/// 客户端启动成功的事件,重连成功也将触发此事件
///
public event Action LoginSuccess;
///
/// 连接失败时触发的事件
///
public event Action LoginFailed;
///
/// 服务器的异常,启动,等等一般消息产生的时候,出发此事件
///
public event Action MessageAlerts;
///
/// 在客户端断开后并在重连服务器之前触发,用于清理系统资源
///
public event Action BeforReConnected;
///
/// 当接收到文本数据的时候,触发此事件
///
public event Action AcceptString;
///
/// 当接收到字节数据的时候,触发此事件
///
public event Action AcceptByte;
#endregion
#region 启动停止重连块
private bool IsQuie { get; set; } = false;
///
/// 关闭该客户端引擎
///
public void ClientClose( )
{
IsQuie = true;
if (IsClientStart)
SendBytes( stateone, HslProtocol.CommandBytes( HslProtocol.ProtocolClientQuit, 0, Token, null ) );
thread_heart_check?.Abort( );
IsClientStart = false;
Thread.Sleep( 5 );
LoginSuccess = null;
LoginFailed = null;
MessageAlerts = null;
AcceptByte = null;
AcceptString = null;
stateone.WorkSocket?.Close( );
LogNet?.WriteDebug( ToString(), "Client Close." );
}
///
/// 启动客户端引擎,连接服务器系统
///
public void ClientStart( )
{
if (IsClientStart) return;
Thread thread_login = new Thread( new ThreadStart( ThreadLogin ) );
thread_login.IsBackground = true;
thread_login.Start( );
LogNet?.WriteDebug( ToString( ), "Client Start." );
if (thread_heart_check == null)
{
thread_heart_check = new Thread( new ThreadStart( ThreadHeartCheck ) );
thread_heart_check.IsBackground = true;
thread_heart_check.Start( );
}
}
private void ThreadLogin( )
{
lock (lock_connecting)
{
if (IsClientConnecting) return;
IsClientConnecting = true;
}
if (ConnectFailedCount == 0)
{
MessageAlerts?.Invoke( "正在连接服务器..." );
}
else
{
int count = 10;
while (count > 0)
{
if (IsQuie) return;
MessageAlerts?.Invoke( "连接断开,等待" + count-- + "秒后重新连接" );
Thread.Sleep( 1000 );
}
MessageAlerts?.Invoke( "正在尝试第" + ConnectFailedCount + "次连接服务器..." );
}
stateone.HeartTime = DateTime.Now;
LogNet?.WriteDebug( ToString( ), "Begin Connect Server, Times: " + ConnectFailedCount );
OperateResult result = new OperateResult( );
OperateResult connectResult = CreateSocketAndConnect( EndPointServer, 10000 );
if (!connectResult.IsSuccess)
{
ConnectFailedCount++;
IsClientConnecting = false;
LoginFailed?.Invoke( ConnectFailedCount );
LogNet?.WriteDebug( ToString( ), "Connected Failed, Times: " + ConnectFailedCount );
// 连接失败,重新连接服务器
ReconnectServer( );
return;
}
// 连接成功,发送数据信息
OperateResult sendResult = SendStringAndCheckReceive( connectResult.Content, 1, ClientAlias );
if (!sendResult.IsSuccess)
{
ConnectFailedCount++;
IsClientConnecting = false;
LogNet?.WriteDebug( ToString( ), "Login Server Failed, Times: " + ConnectFailedCount );
LoginFailed?.Invoke( ConnectFailedCount );
// 连接失败,重新连接服务器
ReconnectServer( );
return;
}
// 登录成功
ConnectFailedCount = 0;
stateone.IpEndPoint = (IPEndPoint)connectResult.Content.RemoteEndPoint;
stateone.LoginAlias = ClientAlias;
stateone.WorkSocket = connectResult.Content;
stateone.WorkSocket.BeginReceive( stateone.BytesHead, stateone.AlreadyReceivedHead,
stateone.BytesHead.Length - stateone.AlreadyReceivedHead, SocketFlags.None,
new AsyncCallback( HeadBytesReceiveCallback ), stateone );
// 发送一条验证消息
// SendBytes(stateone, CommunicationCode.CommandBytes(CommunicationCode.Hsl_Protocol_Check_Secends));
byte[] bytesTemp = new byte[16];
BitConverter.GetBytes( DateTime.Now.Ticks ).CopyTo( bytesTemp, 0 );
SendBytes( stateone, HslProtocol.CommandBytes( HslProtocol.ProtocolCheckSecends, 0, Token, bytesTemp ) );
stateone.HeartTime = DateTime.Now;
IsClientStart = true;
LoginSuccess?.Invoke( );
LogNet?.WriteDebug( ToString( ), "Login Server Success, Times: " + ConnectFailedCount );
IsClientConnecting = false;
Thread.Sleep( 1000 );
}
// private bool Is_reconnect_server = false;
// private object lock_reconnect_server = new object();
private void ReconnectServer( )
{
// 是否连接服务器中,已经在连接的话,则不再连接
if (IsClientConnecting) return;
// 是否退出了系统,退出则不再重连
if (IsQuie) return;
LogNet?.WriteDebug( ToString( ), "Prepare ReConnect Server." );
// 触发连接失败,重连系统前错误
BeforReConnected?.Invoke( );
stateone.WorkSocket?.Close( );
Thread thread_login = new Thread( new ThreadStart( ThreadLogin ) )
{
IsBackground = true
};
thread_login.Start( );
}
#endregion
#region 发送接收块
///
/// 通信出错后的处理
///
///
///
internal override void SocketReceiveException( AppSession receive, Exception ex )
{
if (ex.Message.Contains( StringResources.SocketRemoteCloseException ))
{
// 异常掉线
ReconnectServer( );
}
else
{
// MessageAlerts?.Invoke("数据接收出错:" + ex.Message);
}
LogNet?.WriteDebug( ToString( ), "Socket Excepiton Occured." );
}
///
/// 服务器端用于数据发送文本的方法
///
/// 用户自定义的命令头
/// 发送的文本
public void Send( NetHandle customer, string str )
{
if (IsClientStart)
{
SendBytes( stateone, HslProtocol.CommandBytes( customer, Token, str ) );
}
}
///
/// 服务器端用于发送字节的方法
///
/// 用户自定义的命令头
/// 实际发送的数据
public void Send( NetHandle customer, byte[] bytes )
{
if (IsClientStart)
{
SendBytes( stateone, HslProtocol.CommandBytes( customer, Token, bytes ) );
}
}
private void SendBytes( AppSession stateone, byte[] content )
{
SendBytesAsync( stateone, content );
}
#endregion
#region 信息处理中心
///
/// 客户端的数据处理中心
///
///
///
///
///
internal override void DataProcessingCenter( AppSession session, int protocol, int customer, byte[] content )
{
if (protocol == HslProtocol.ProtocolCheckSecends)
{
DateTime dt = new DateTime( BitConverter.ToInt64( content, 0 ) );
ServerTime = new DateTime( BitConverter.ToInt64( content, 8 ) );
DelayTime = (int)(DateTime.Now - dt).TotalMilliseconds;
stateone.HeartTime = DateTime.Now;
// MessageAlerts?.Invoke("心跳时间:" + DateTime.Now.ToString());
}
else if (protocol == HslProtocol.ProtocolClientQuit)
{
// 申请了退出
}
else if (protocol == HslProtocol.ProtocolUserBytes)
{
// 接收到字节数据
AcceptByte?.Invoke( stateone, customer, content );
}
else if (protocol == HslProtocol.ProtocolUserString)
{
// 接收到文本数据
string str = Encoding.Unicode.GetString( content );
AcceptString?.Invoke( stateone, customer, str );
}
}
#endregion
#region 心跳线程块
private Thread thread_heart_check { get; set; } = null;
///
/// 心跳线程的方法
///
private void ThreadHeartCheck( )
{
Thread.Sleep( 2000 );
while (true)
{
Thread.Sleep( 1000 );
if (!IsQuie)
{
byte[] send = new byte[16];
BitConverter.GetBytes( DateTime.Now.Ticks ).CopyTo( send, 0 );
SendBytes( stateone, HslProtocol.CommandBytes( HslProtocol.ProtocolCheckSecends, 0, Token, send ) );
double timeSpan = (DateTime.Now - stateone.HeartTime).TotalSeconds;
if (timeSpan > 1 * 8)//8次没有收到失去联系
{
LogNet?.WriteDebug( ToString( ), $"Heart Check Failed int {timeSpan} Seconds." );
ReconnectServer( );
Thread.Sleep( 1000 );
}
}
else
{
break;
}
}
}
#endregion
#region Object Override
///
/// 返回对象的字符串表示形式
///
///
public override string ToString( )
{
return "NetComplexClient";
}
#endregion
}
}