using Island.StandardLib.Exceptions;
using Island.StandardLib.Storage;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Island.StandardLib
{
public abstract class ConnectionClient
{
public string ServerAddress { get; private set; }
public int ServerPort { get; private set; }
public int MaxBitSize { get; private set; }
public bool DebugMode { get; set; }
public uint ClientVersion { get; private set; }
public ConnectionClient(string addr, int port, uint version = 1, bool debug = false, int maxbitsz = 524288)
{
ServerAddress = addr;
ServerPort = port;
ClientVersion = version;
MaxBitSize = maxbitsz;
DebugMode = debug;
}
public ConnectObjectFromClient CommandSendPool;
public Socket ClientSocket;
public bool IsConnected { get; private set; }
Thread clientLoop;
///
/// 自定义登录动作完成后调用此函数开启通信循环
///
public void KeepConnect()
{
if (clientLoop != null) if (clientLoop.IsAlive)
throw new PlayerSocketFatalException("client", PlayerSocketFatalExceptionType.InternalDuplicatePlayerThreadStart);
clientLoop = new Thread(ClientLoop) { IsBackground = true };
clientLoop.Start();
//KeepConnect()(default);
}
//public Func KeepConnect() where TIn : struct where TOut : class
//{
// return t =>
// {
// KeepConnect();
// Func func = () =>
// {
// return default(TOut);
// };
// };
//}
public LoginResult ConnectAsLogin(RequestType request)
where RequestType : ILoginOrRegisterRequest, IStorable, new()
{
try
{
request.ClientVersion = ClientVersion;
request.IsLogin = true;
IPAddress[] addr = Dns.GetHostAddresses(ServerAddress);
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ClientSocket.Connect(addr, ServerPort);
ClientSocket.SendOnce(request);
LoginCallback lcb = ClientSocket.ReceiveOnce(512);
if (lcb.Success)
{
KeepConnect();
}
else
{
try
{
ClientSocket.Close();
ClientSocket.Dispose();
}
catch { }
}
return lcb.Code;
}
catch (Exception)
{
try
{
ClientSocket?.Close();
ClientSocket?.Dispose();
}
catch { }
return LoginResult.ConnectionError;
}
}
public RegisterData ConnectAsRegister(RequestType request)
where RequestType : ILoginOrRegisterRequest, IStorable, new()
{
try
{
request.IsLogin = false;
IPAddress[] addr = Dns.GetHostAddresses(ServerAddress);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(addr, ServerPort);
sock.SendOnce(request);
RegisterCallback rcb = sock.ReceiveOnce(512);
try
{
sock.Close();
sock.Dispose();
}
catch { }
if (rcb.Success) return new RegisterData(RegisterResult.Success, rcb.Username);
else return new RegisterData((RegisterResult)rcb.Username, -1);
}
catch
{
return new RegisterData(RegisterResult.ConnectionError, -1);
}
}
public void ConnectAsRegister(RequestType request, out RegisterCallback rcb)
where RequestType : ILoginOrRegisterRequest, IStorable, new()
{
try
{
request.IsLogin = false;
IPAddress[] addr = Dns.GetHostAddresses(ServerAddress);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(addr, ServerPort);
sock.SendOnce(request);
rcb = sock.ReceiveOnce(512);
try
{
sock.Close();
sock.Dispose();
}
catch { }
}
catch
{
rcb = null;
}
}
public T ConnectManual(byte[] bSend) where T : IStorable, new()
{
try
{
IPAddress[] addr = Dns.GetHostAddresses(ServerAddress);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect(addr, ServerPort);
sock.SendOnce(bSend);
T ret = sock.ReceiveOnce(2048);
try
{
sock.Close();
sock.Dispose();
}
catch { }
return ret;
}
catch
{
return default;
}
}
//public LoginResult ConnectAsLogin(int userName, string password)
//{
// try
// {
// LoginOrRegisterRequest request = new LoginOrRegisterRequest(userName, password, ClientVersion);
// request.IsLogin = true;
// IPAddress[] addr = Dns.GetHostAddresses(ServerAddress);
// ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// ClientSocket.Connect(addr, ServerPort);
// ClientSocket.SendOnce(request);
// LoginCallback lcb = ClientSocket.ReceiveOnce(512);
// if (lcb.Success)
// {
// Thread clientLoop = new Thread(ClientLoop);
// clientLoop.IsBackground = true;
// clientLoop.Start();
// //Thread watchLoop = new Thread(WatcherLoop);
// //watchLoop.IsBackground = true;
// //watchLoop.Start();
// }
// else
// {
// try
// {
// ClientSocket.Close();
// ClientSocket.Dispose();
// }
// catch { }
// }
// return lcb.Code;
// }
// catch (Exception e)
// {
// try
// {
// ClientSocket?.Close();
// ClientSocket?.Dispose();
// }
// catch { }
// return LoginResult.ConnectionError;
// }
//}
//public RegisterData ConnectAsRegister(string nickname, string password)
//{
// try
// {
// LoginOrRegisterRequest request = new LoginOrRegisterRequest(0, password, ClientVersion);
// request.IsRegister = true;
// request.Nickname = nickname;
// IPAddress[] addr = Dns.GetHostAddresses(ServerAddress);
// Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// sock.Connect(addr, ServerPort);
// sock.SendOnce(request);
// RegisterCallback rcb = sock.ReceiveOnce(512);
// try
// {
// sock.Close();
// sock.Dispose();
// }
// catch { }
// if (rcb.Success) return new RegisterData(RegisterResult.Success, rcb.Username);
// else return new RegisterData((RegisterResult)rcb.Username, -1);
// }
// catch
// {
// return new RegisterData(RegisterResult.ConnectionError, -1);
// }
//}
//void WatcherLoop()
//{
// while (true)
// {
// contFlag = false;
// Thread.Sleep(5000);
// if (!contFlag)
// {
// IsConnected = false;
// OnConnectionBreaked(new Exception("Wait too long"));
// }
// }
//}
bool contFlag = true;
public void Shutdown() => contFlag = false;
public virtual void OnClientWillSendDataToServer(ConnectObjectFromServer serverData) { }
void ClientLoop()
{
Exception endWith;
CommandSendPool = new ConnectObjectFromClient();
IsConnected = true;
OnConnectionBegin();
ClientSocket.SendTimeout = 5000;
ClientSocket.ReceiveTimeout = 5000;
while (true)
{
try
{
ConnectObjectFromServer serverData = ClientSocket.ReceiveOnce(MaxBitSize);
if (!contFlag) throw new Exception("Shutdown flag enabled.");
bool recvCmds, sendCmds;
lock (CommandSendPool)
{
InnerCommandPass(serverData);
OnClientWillSendDataToServer(serverData);
ClientSocket.SendOnce(CommandSendPool);
recvCmds = serverData.Commands.Count != 0;
sendCmds = CommandSendPool.Commands.Count != 0;
CommandSendPool.ClearCommands();
}
if (DebugMode)
{
if (recvCmds && sendCmds)
{
Console.BackgroundColor = ConsoleColor.Red;
Console.Write("x");
}
else if (recvCmds)
{
Console.BackgroundColor = ConsoleColor.DarkBlue;
Console.Write("-");
}
else if (sendCmds)
{
Console.BackgroundColor = ConsoleColor.DarkGreen;
Console.Write("+");
}
else
{
Console.BackgroundColor = ConsoleColor.Black;
Console.Write("=");
}
}
}
catch (Exception e)
{
endWith = e;
break;
}
}
try
{
ClientSocket.Close();
ClientSocket.Dispose();
}
catch { }
IsConnected = false;
BreakedException = endWith;
OnConnectionBreaked(endWith);
}
public Exception BreakedException;
void InnerCommandPass(ConnectObjectFromServer serverData)
{
for (int i = 0; i < serverData.Commands.Length; i++)
{
ConnectCommand command = serverData.Commands[i];
PassCommand(command);
}
}
protected abstract void PassCommand(ConnectCommand command);
protected virtual void OnConnectionBegin() { }
protected virtual void OnConnectionBreaked(Exception reason) { }
}
public struct RegisterData
{
public RegisterData(RegisterResult r, int u)
{
result = r;
uid = u;
}
public RegisterResult result;
public int uid;
}
}