using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
public class ClientSocketController
{
Socket m_Socket;
public Socket socket {
get { return m_Socket; }
}
private int connectWaitTime = 2000; // 10秒
private Thread m_packageThread;
private byte[] bufferBytes = new byte[4096]; // 4K,单包字节数组缓存
private byte[] fragmentBytes; //留包后的内容
private long getBytesTotal = 0; //发送的数据总量
private long sendBytesTotal = 0; //发送的数据总量
public bool Connected { get { return m_Socket == null ? false : m_Socket.Connected; } }
public bool isStopTreading { get; private set; }
string ip;
int port;
Action onConnected = null;
public ClientSocketController()
{
}
public void Connect(string _ip, int _port, Action _onConnected)
{
try
{
ip = _ip;
port = _port;
onConnected = _onConnected;
Dns.BeginGetHostAddresses(_ip, OnGetHostAddresses, null);
}
catch (Exception e)
{
DebugEx.LogError(e.Message);
}
}
private void OnGetHostAddresses(IAsyncResult _result)
{
var ipAddresses = Dns.EndGetHostAddresses(_result);
if (ipAddresses[0].AddressFamily == AddressFamily.InterNetworkV6)
{
DebugEx.Log("当前使用的网络: IPV6");
m_Socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
}
else
{
DebugEx.Log("当前使用的网络: IPV4");
m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
var ipEndPoint = new IPEndPoint(ipAddresses[0], port);
if (ipEndPoint == null)
{
Debug.Log("IpEndPoint is null");
}
var state = new SocketAsyncState();
state.IsAsync = true;
m_Socket.BeginConnect(ipEndPoint, new AsyncCallback(ConnectCallBack), state);
}
///
/// 链接成功时的回调
///
///
private void ConnectCallBack(IAsyncResult _result)
{
if (!_result.IsCompleted)
{
DebugEx.Log("链接超时!");
CloseConnect();
}
else
{
if (m_Socket != null && m_Socket.Connected)
{
DebugEx.Log("确认的链接实现");
OnConnectSuccess();
if (onConnected != null)
{
onConnected();
onConnected = null;
}
}
else
{
if (m_Socket != null)
{
m_Socket.Disconnect(true);
}
onConnected = null;
}
}
}
///
/// 关闭链接
///
public void CloseConnect()
{
try
{
isStopTreading = true;
if (m_packageThread != null)
{
m_packageThread.Abort();
}
}
catch (System.Exception ex)
{
DebugEx.Log(ex);
}
try
{
if (m_Socket != null && m_Socket.Connected)
{
m_Socket.Shutdown(SocketShutdown.Both);
m_Socket.Close();
}
}
catch (System.Exception ex)
{
DebugEx.Log(ex);
}
sendQueue.Clear();
m_Socket = null;
}
///
/// 链接成功
///
private void OnConnectSuccess()
{
if (m_packageThread != null)
{
m_packageThread.Abort();
m_packageThread = null;
}
m_packageThread = new Thread(new ThreadStart(ReceiveInfo)); // 启动线程接收信息
m_packageThread.IsBackground = true;
m_packageThread.Start();
isStopTreading = false;
}
///
/// 接收信息
///
private void ReceiveInfo()
{
int vDataLeng;
byte[] vBytes;
while (!isStopTreading)
{
if (!m_Socket.Connected)
{
isStopTreading = true;
m_Socket.Shutdown(SocketShutdown.Both);
m_Socket.Close();
break;
}
try
{
vDataLeng = m_Socket.Receive(bufferBytes);
if (vDataLeng <= 0)
{
isStopTreading = true;
m_Socket.Shutdown(SocketShutdown.Both);
m_Socket.Close();
break;
}
getBytesTotal += vDataLeng;
vBytes = new byte[vDataLeng];
Array.Copy(bufferBytes, 0, vBytes, 0, vDataLeng);
ReadInfo(vBytes);
}
catch (Exception e)
{
DebugEx.Log(e);
}
}
}
static byte[] vCmdBytes = new byte[2];
///
/// 阅读信息
///
///
private void ReadInfo(byte[] vBytes)
{
try
{
byte[] fixBytes = vBytes;
// 如果存在留包,则并包
if (fragmentBytes != null && fragmentBytes.Length > 0)
{
Array.Resize(ref fixBytes, vBytes.Length + fragmentBytes.Length);
Array.Copy(fragmentBytes, 0, fixBytes, 0, fragmentBytes.Length);
Array.Copy(vBytes, 0, fixBytes, fragmentBytes.Length, vBytes.Length);
}
fragmentBytes = null; // 清理掉留包
// 分包
int vReadIndex = 0; // 初始指针
byte[] vPackBytes;
int vLeavingLeng = 0;
int vBodyLeng = 0;
int vTotalLeng = fixBytes.Length;
GameNetPackBasic vNetpack;
while (vReadIndex < vTotalLeng)
{
vLeavingLeng = vTotalLeng - vReadIndex;
if (vLeavingLeng < 6) // 未符合包的最低限度字节量, 留包
{
fragmentBytes = new byte[vLeavingLeng];
Array.Copy(fixBytes, vReadIndex, fragmentBytes, 0, vLeavingLeng);
break;
}
vBodyLeng = BitConverter.ToInt32(fixBytes, vReadIndex + 2);
if (vBodyLeng > vLeavingLeng - 6)// 未完整的包则留包
{
fragmentBytes = new byte[vLeavingLeng];
Array.Copy(fixBytes, vReadIndex, fragmentBytes, 0, vLeavingLeng);
break;
}
vPackBytes = new byte[vBodyLeng];
Array.Copy(fixBytes, vReadIndex + 6, vPackBytes, 0, vBodyLeng); // 提取包的字节内容
// 完整的包则读包
vPackBytes = GameNetEncode.BaseXorSub(vPackBytes);
Array.Copy(vPackBytes, 0, vCmdBytes, 0, 2);
var cmd = (ushort)((ushort)(vCmdBytes[0] << 8) + vCmdBytes[1]);
if (PackageRegedit.Contain(cmd))
{
vNetpack = PackageRegedit.TransPack(cmd, vPackBytes);
if (vNetpack != null)
{
if (DebugEx.EnableNetLog)
{
DebugEx.NetLogFormat("收包:{0}", vNetpack.GetType().Name);
}
GameNetSystem.Instance.PushPackage(vNetpack);
}
}
else
{
CSharpCallLua.OnRecieveLuaNetPackage(cmd, vPackBytes);
}
vReadIndex += 6 + vBodyLeng;
}
}
catch (Exception ex)
{
Debug.LogFormat("收包异常:{0}", ex);
}
}
///
/// 发送信息
///
///
public void SendInfo(GameNetPackBasic vNetPack)
{
if (!Connected)
return;
if (vNetPack == null)
{
DebugEx.LogError("要发的信息对象为空");
return;
}
if (DebugEx.EnableNetLog)
{
DebugEx.NetLogFormat("发包:{0}", vNetPack.GetType().Name);
}
if (vNetPack.cmd == (ushort)0x03FE || vNetPack.cmd == (ushort)0x1801)
{
}
if (vNetPack.combineBytes == null)
{
vNetPack.WriteToBytes();
}
vNetPack.CombineDatas();
#if UNITY_EDITOR
NetPkgCtl.AddNetPkg(vNetPack.vInfoCont, NetPkgType.Client, vNetPack.ToString(), FieldPrint.PrintFields(vNetPack), FieldPrint.PrintFieldsExpand(vNetPack, true));
#endif
sendBytesTotal += vNetPack.combineBytes.Length;
SendBytes(vNetPack.combineBytes);
}
///
/// 发送信息
///
///
public void SendInfo(byte[] vBytes)
{
if (!Connected)
{
DebugEx.LogError("尚未与该后端链接!无法发送信息");
return;
}
if (vBytes == null || vBytes.Length < 2)
{
DebugEx.LogError("要发的信息数据为空或数据不足");
return;
}
vBytes = GameNetEncode.BaseXorAdd(vBytes);
byte[] vFrameHead = new byte[] { 255, 204 };
byte[] vMsgBodyLength = BitConverter.GetBytes(vBytes.Length);
byte[] vTotal = new byte[vBytes.Length + 6];
Array.Copy(vFrameHead, 0, vTotal, 0, vFrameHead.Length);
Array.Copy(vMsgBodyLength, 0, vTotal, 2, vMsgBodyLength.Length);
Array.Copy(vBytes, 0, vTotal, 6, vBytes.Length);
SendBytes(vTotal);
}
///
/// 发送已加密字节
///
///
public void SendNoEncrypInfo(byte[] vBytes)
{
if (!Connected)
{
DebugEx.LogError("尚未与该后端链接!无法发送信息");
return;
}
if (vBytes == null || vBytes.Length < 2)
{
DebugEx.LogError("要发的信息数据为空或数据不足");
return;
}
SendBytes(vBytes);
}
Queue sendQueue = new Queue();
private void SendBytes(byte[] bytes)
{
try
{
if (sendQueue.Count > 0)
{
sendQueue.Enqueue(bytes);
}
else
{
m_Socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(SendInfoCallBack), m_Socket);
}
}
catch
{
DebugEx.LogError("发送时发生异常");
}
}
///
/// 发送完成的回调
///
///
private void SendInfoCallBack(IAsyncResult vAsyncSend)
{
try
{
if (sendQueue.Count > 0)
{
var bytes = sendQueue.Dequeue();
m_Socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, new AsyncCallback(SendInfoCallBack), m_Socket);
}
}
catch (Exception ex)
{
DebugEx.Log(ex);
}
}
internal class SocketAsyncState
{
///
/// 是否完成。
///
public bool Completed { get; set; }
///
/// 数据
///
public byte[] Data { get; set; }
///
/// 是否异步
///
public bool IsAsync { get; set; }
}
}