miduo_client/Assets/LuaFramework/Scripts/Network/SocketClient.cs

797 lines
23 KiB
C#
Raw Normal View History

2020-05-09 13:31:21 +08:00
using UnityEngine;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;
using GameLogic;
using System.Text;
using LuaInterface;
//using System.Runtime.InteropServices;
public enum NetworkStateType
{
Connected,
ConnectFail,
Reconnected,
ReconnectFail,
Exception,
Disconnect,
}
static class IPAddressExtensions
{
public static IPAddress MapToIPv6(this IPAddress addr)
{
if (addr.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Must pass an IPv4 address to MapToIPv6");
string ipv4str = addr.ToString();
return IPAddress.Parse("::ffff:" + ipv4str);
}
public static bool IsIPv4MappedToIPv6(this IPAddress addr)
{
bool pass1 = addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6, pass2;
try
{
pass2 = (addr.ToString().StartsWith("0000:0000:0000:0000:0000:ffff:") ||
addr.ToString().StartsWith("0:0:0:0:0:ffff:") ||
addr.ToString().StartsWith("::ffff:")) &&
IPAddress.Parse(addr.ToString().Substring(addr.ToString().LastIndexOf(":") + 1)).AddressFamily == AddressFamily.InterNetwork;
}
catch
{
return false;
}
return pass1 && pass2;
}
}
public class SocketClient
{
public NetworkManager netMgr;
private TcpClient client = null;
private NetworkStream outStream = null;
private MemoryStream _memStream;
public MemoryStream CurMemoryStream
{
get
{
if (_memStream == null)
_memStream = new MemoryStream();
return _memStream;
}
}
private BinaryReader _reader;
public BinaryReader CurReader
{
get
{
if (_reader == null)
_reader = new BinaryReader(_memStream);
return _reader;
}
}
static readonly int HeaderSize= sizeof(ushort)+sizeof(int);
private const int MAX_READ = 8192;
private byte[] byteBuffer = new byte[MAX_READ];
static TEA crypto = new TEA();
Queue<NetMsg> mEvents = new Queue<NetMsg>();
Stack<NetworkStateInfo> stateInfoStack = new Stack<NetworkStateInfo>();
Dictionary<int, IDispatcher> dispatchers = new Dictionary<int, IDispatcher>();
Dictionary<int, IDispatcher> callbacks = new Dictionary<int, IDispatcher>();
int m_serialId;
int m_indicationSid;
bool m_isConnected = false;
bool m_isConnecting = false;
private const int INDICATION_RESPONSE = 10046;
private const int INDICATION_ERROR_CODE = 10400;
public string IpAddress { get; private set; }
public int Port { get; private set; }
// Use this for initialization
public SocketClient(string ipAddress, int port)
{
IpAddress = ipAddress;
Port = port;
_memStream = new MemoryStream();
_reader = new BinaryReader(_memStream);
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient SocketClient ipAddress: " + ipAddress + " port: " + port);
2020-05-09 13:31:21 +08:00
}
public void SetIpAddress(string ipAddress, int port)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient SetIpAddress ipAddress: " + ipAddress + " port: " + port);
2020-05-09 13:31:21 +08:00
if (!IsConnected())
{
IpAddress = ipAddress;
Port = port;
m_indicationSid = 0;
m_serialId = 1;
}
}
/// <summary>
/// 连接服务器
/// </summary>
public void Connect()
{
Close();
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient Connect ipAddress: " + IpAddress);
2020-05-09 13:31:21 +08:00
try
{
var ipType = GetIPAddressType(IpAddress);
client = null;
client = new TcpClient(ipType);
client.SendTimeout = 1000;
client.ReceiveTimeout = 1000;
client.NoDelay = true;
client.BeginConnect(IpAddress, Port, new AsyncCallback(OnConnect), null);
}
catch (Exception e)
{
OnConnectFail();
2020-09-16 20:45:41 +08:00
Debug.LogError("SocketClient Connect catch: " + e.Message);
2020-05-09 13:31:21 +08:00
}
}
public void OnConnectFail()
{
2020-09-16 20:45:41 +08:00
AddStateInfo(NetworkStateType.ConnectFail, "OnConnectFail");
2020-05-09 13:31:21 +08:00
}
/// <summary>
/// 连接上服务器
/// </summary>
void OnConnect(IAsyncResult asr)
{
2020-09-16 20:45:41 +08:00
Debug.LogError("SocketClient OnConnect");
2020-05-09 13:31:21 +08:00
outStream = client.GetStream();
client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
2020-09-16 20:45:41 +08:00
AddStateInfo(NetworkStateType.Connected, "OnConnect");
2020-05-09 13:31:21 +08:00
}
/// <summary>
/// 写数据
/// </summary>
void WriteMessage(byte[] message)
{
MemoryStream ms = null;
using (ms = new MemoryStream())
{
ms.Position = 0;
BinaryWriter writer = new BinaryWriter(ms);
short msglen = (short)message.Length;
msglen = IPAddress.HostToNetworkOrder(msglen);
byte[] tempBuffer = new byte[message.Length];
Buffer.BlockCopy(message, 0, tempBuffer, 0, message.Length);
if (crypto != null)
tempBuffer = crypto.Encode(tempBuffer);
writer.Write(tempBuffer);
writer.Flush();
if (client != null && client.Connected)
{
//NetworkStream stream = client.GetStream();
byte[] payload = ms.ToArray();
outStream.BeginWrite(payload, 0, payload.Length, new AsyncCallback(OnWrite), ms);
}
else
{
2020-09-16 20:45:41 +08:00
Debug.LogError("SocketClient WriteMessage !connected");
2020-05-09 13:31:21 +08:00
}
}
}
/// <summary>
/// 读取消息
/// </summary>
void OnRead(IAsyncResult asr)
{
int bytesRead = 0;
//try
{
lock (client.GetStream())
{
//读取字节流到缓冲区
bytesRead = client.GetStream().EndRead(asr);
}
if (bytesRead < 1)
{
//包尺寸有问题,断线处理
AddStateInfo(NetworkStateType.Disconnect, "bytesRead < 1");
return;
}
OnReceive(byteBuffer, bytesRead); //分析数据包内容,抛给逻辑层
lock (client.GetStream())
{
//分析完,再次监听服务器发过来的新消息
Array.Clear(byteBuffer, 0, byteBuffer.Length); //清空数组
client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
}
}
//catch (Exception ex)
//{
// //PrintBytes();
// AddStateInfo(NetworkStateType.Exception, ex.Message);
//}
}
/// <summary>
/// 丢失链接
/// </summary>
public void AddStateInfo(NetworkStateType dis, string msg)
{
NetworkStateInfo info = new NetworkStateInfo();
info.type = dis;
info.msg = msg;
stateInfoStack.Push(info);
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient AddStateInfo dis: " + dis + " msg: " + msg);
2020-05-09 13:31:21 +08:00
}
/// <summary>
/// 打印字节
/// </summary>
/// <param name="bytes"></param>
void PrintBytes()
{
string returnStr = string.Empty;
for (int i = 0; i < byteBuffer.Length; i++)
{
returnStr += byteBuffer[i].ToString("X2");
}
2020-09-16 20:45:41 +08:00
Debug.LogError("SocketClient PrintBytes Str: " + returnStr);
2020-05-09 13:31:21 +08:00
}
/// <summary>
/// 向链接写入数据流
/// </summary>
void OnWrite(IAsyncResult r)
{
try
{
MemoryStream stream = (MemoryStream)r.AsyncState;
outStream.EndWrite(r);
if(stream!=null)
{
stream.Close();
}
}
catch (Exception ex)
{
2020-09-16 20:45:41 +08:00
Debug.LogError("SocketClient OnWrite catch: " + ex.Message.ToString());
2020-05-09 13:31:21 +08:00
}
}
/// <summary>
/// 接收到消息
/// </summary>
void OnReceive(byte[] bytes, int length)
{
try
{
var stream = CurMemoryStream;
var reader = CurReader;
stream.Seek(0, SeekOrigin.End);
stream.Write(bytes, 0, length);
//Reset to beginning
stream.Seek(0, SeekOrigin.Begin);
while (RemainingBytes() > 4)
{
short messageLen = reader.ReadInt16();
messageLen = IPAddress.NetworkToHostOrder(messageLen);
//memStream.Seek(0, SeekOrigin.Begin);
//TEA解密需要补齐8位
int decodeMessageLen = (messageLen + 7) / 8 * 8;
if (RemainingBytes() >= decodeMessageLen) //粘包处理
{
var msgBytes = reader.ReadBytes(decodeMessageLen);
if (crypto != null)
msgBytes = crypto.Decode(msgBytes, messageLen);
OnReceivedMessage(new ByteBuffer(msgBytes));
}
else
{
//Back up the position two bytes
stream.Position = stream.Position - 2;
break;
}
}
//Create a new stream with any leftover bytes
byte[] leftover = reader.ReadBytes((int)RemainingBytes());
stream.SetLength(0); //Clear
stream.Write(leftover, 0, leftover.Length);
}
catch (Exception e)
{
2020-09-16 20:45:41 +08:00
Debug.LogError("SocketClient OnReceive catch: " + e.ToString());
2020-05-09 13:31:21 +08:00
AddStateInfo(NetworkStateType.Disconnect, "Network Read Exception: " + e.ToString());
}
}
/// <summary>
/// 剩余的字节
/// </summary>
private long RemainingBytes()
{
return CurMemoryStream.Length - CurMemoryStream.Position;
}
/// <summary>
/// 接收到消息
/// </summary>
/// <param name="ms"></param>
void OnReceivedMessage(ByteBuffer buffer)
{
//user id
buffer.ReadIntToByte();
//token
buffer.ReadIntToByte();
//协议号
int msgid = buffer.ReadIntToByte();
//收到心跳包
if (msgid == 1001)
{
lock (mEvents)
{
mEvents.Enqueue(new NetMsg(msgid, 0, 0, buffer));
}
return;
}
//消息index
int sId = buffer.ReadIntToByte();
//结果码
int result = buffer.ReadIntToByte();
lock (mEvents)
{
mEvents.Enqueue(new NetMsg(msgid, sId, result, buffer));
}
}
private void indicationErrorAction(ByteBuffer buffer)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient indicationErrorAction");
2020-05-09 13:31:21 +08:00
Util.CallMethod("SocketManager", "ReceiveErrorInfo", this, buffer);
}
/// <summary>
/// 关闭链接
/// </summary>
public void Close()
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient Close");
2020-05-09 13:31:21 +08:00
UnregistNetMessage(INDICATION_ERROR_CODE, indicationErrorAction);
m_isConnected = false;
m_isConnecting = false;
lock (mEvents)
{
mEvents.Clear();
}
dispatchers.Clear();
callbacks.Clear();
stateInfoStack.Clear();
if (client != null)
{
client.Close();
client = null;
}
2020-09-16 20:45:41 +08:00
else {
Debug.Log("SocketClient Close client==null");
}
2020-05-09 13:31:21 +08:00
if (_memStream != null)
{
_memStream.Dispose();
_memStream = null;
}
if (_reader != null)
{
_reader.Close();
_reader = null;
}
Array.Clear(byteBuffer, 0, byteBuffer.Length);
}
bool testConnect;
public void Update()
{
if (stateInfoStack.Count > 0)
{
var info = stateInfoStack.Pop();
if (info.type == NetworkStateType.Connected)
{
m_isConnected = true;
RegistNetMessage(INDICATION_ERROR_CODE, indicationErrorAction);
Util.CallMethod("SocketManager", "OnConnect", this);
}
else if (info.type == NetworkStateType.ConnectFail)
{
Util.CallMethod("SocketManager", "OnConnectFail", this);
}
else if (info.type == NetworkStateType.Reconnected)
{
m_isConnected = true;
RegistNetMessage(INDICATION_ERROR_CODE, indicationErrorAction);
Util.CallMethod("SocketManager", "OnReconnect", this);
}
else if (info.type == NetworkStateType.ReconnectFail)
{
Util.CallMethod("SocketManager", "OnReconnectFail", this);
}
else if (info.type == NetworkStateType.Disconnect)
{
Disconnect();
}
else if (info.type == NetworkStateType.Exception)
{
Disconnect();
}
return;
}
lock (mEvents)
{
while (mEvents.Count > 0)
{
DispatchMessage(mEvents.Dequeue());
}
}
testConnect = Input.GetKeyDown(KeyCode.F1);
if (testConnect)
{
Debug.Log("~~~~~~~~~~~~~测试掉线~~~~~~~~~~~~~~~");
}
if (m_isConnecting && !testConnect)
{
return;
}
if ((testConnect || !IsConnected()) && m_isConnected)
{
Disconnect();
}
}
void DispatchMessage(NetMsg _event)
{
int msgId = _event.msgId;
ByteBuffer msg = _event.msg;
//处理心跳包回调
if (msgId == 1001)
{
Util.CallMethod("SocketManager", "ReceiveClientHeartBeat", this, msg);
return;
}
//处理错误码
if (_event.result == 0)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient DispatchMessage result == 0 msgID: " + msgId + " msg: " + msg);
2020-05-09 13:31:21 +08:00
m_serialId++;
Util.CallMethod("SocketManager", "ReceiveErrorInfo", this, msg);
if (callbacks.ContainsKey(msgId))
{
callbacks.Remove(msgId);
}
return;
}
//处理推送消息当序列号比本地游标大1处理推送信息否则不处理
if (dispatchers.ContainsKey(msgId))
{
if (m_indicationSid == _event.sid - 1)
{
m_indicationSid++;
if (!dispatchers[msgId].Process(msg))
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient DispatchMessage Failed to process message. msgId : " + msgId);
2020-05-09 13:31:21 +08:00
}
}
if (_event.sid <= m_indicationSid)
{
m_SendMessage(INDICATION_RESPONSE, null, _event.sid);
}
}
//处理请求回应消息
if (callbacks.ContainsKey(msgId))
{
var call = callbacks[msgId];
callbacks.Remove(msgId);
m_serialId++;
if (!call.Process(msg))
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient DispatchMessage Failed to process message2. msgId : " + msgId);
2020-05-09 13:31:21 +08:00
}
}
}
public void Disconnect()
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient Disconnect");
2020-05-09 13:31:21 +08:00
Close(); //关掉客户端链接
Util.CallMethod("SocketManager", "OnDisconnect", this);
}
private Coroutine checkConnect_co;
IEnumerator CheckConnect_Co()
{
yield return new WaitForEndOfFrame();
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient CheckConnect_Co IP: " + IpAddress + " Port: " + Port);
2020-05-09 13:31:21 +08:00
Connect();
m_isConnecting = true;
yield return new WaitForSeconds(AppConst.ConnectTimeout);
if (!IsConnected())
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient CheckConnect_Co connect Fail");
2020-05-09 13:31:21 +08:00
OnConnectFail();
}
m_isConnecting = false;
checkConnect_co = null;
}
/// <summary>
/// 发送连接请求
/// </summary>
public void TryConnect()
{
if (IsConnected())
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient TryConnect isConnected");
2020-05-09 13:31:21 +08:00
NetworkStateInfo info = new NetworkStateInfo();
info.type = NetworkStateType.Connected;
info.msg = null;
stateInfoStack.Push(info);
return;
}
if (m_isConnecting)
2020-09-16 20:45:41 +08:00
{
Debug.Log("SocketClient TryConnect m_isConnecting");
2020-05-09 13:31:21 +08:00
return;
2020-09-16 20:45:41 +08:00
}
2020-05-09 13:31:21 +08:00
if (checkConnect_co != null)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient TryConnect checkConnect_co != nul");
2020-05-09 13:31:21 +08:00
netMgr.StopCoroutine(checkConnect_co);
}
checkConnect_co = netMgr.StartCoroutine(CheckConnect_Co());
}
private Coroutine reconnect_co;
IEnumerator CheckReconnect_Co()
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient TryConnect CheckReconnect_Co");
2020-05-09 13:31:21 +08:00
yield return new WaitForEndOfFrame();
Reconnect();
m_isConnecting = true;
yield return new WaitForSeconds(AppConst.ConnectTimeout);
if (!IsConnected())
2020-09-16 20:45:41 +08:00
{
Debug.Log("SocketClient CheckReconnect_Co connect Fail");
2020-05-09 13:31:21 +08:00
OnReconnectFail();
2020-09-16 20:45:41 +08:00
}
2020-05-09 13:31:21 +08:00
m_isConnecting = false;
reconnect_co = null;
}
public void TryReconnect()
{
if (IsConnected())
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient TryReconnect IsConnected");
2020-05-09 13:31:21 +08:00
NetworkStateInfo info = new NetworkStateInfo();
info.type = NetworkStateType.Reconnected;
info.msg = null;
stateInfoStack.Push(info);
return;
}
if (m_isConnecting)
2020-09-16 20:45:41 +08:00
{
Debug.Log("SocketClient TryReconnect m_isConnecting");
2020-05-09 13:31:21 +08:00
return;
2020-09-16 20:45:41 +08:00
}
2020-05-09 13:31:21 +08:00
if (reconnect_co != null)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient TryReconnect reconnect_co != nul");
2020-05-09 13:31:21 +08:00
netMgr.StopCoroutine(reconnect_co);
}
reconnect_co = netMgr.StartCoroutine(CheckReconnect_Co());
}
public void Reconnect()
{
Close();
try
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient Reconnect");
2020-05-09 13:31:21 +08:00
var ipType = GetIPAddressType(IpAddress);
client = null;
client = new TcpClient(ipType);
//client.SendTimeout = 1000;
//client.ReceiveTimeout = 1000;
client.NoDelay = true;
client.BeginConnect(IpAddress, Port, new AsyncCallback(OnReconnect), null);
}
catch (Exception e)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient Reconnect catch " + e.Message);
2020-05-09 13:31:21 +08:00
OnReconnectFail();
}
}
public AddressFamily GetIPAddressType(string ip)
{
bool hasIpv4 = false;
bool hasIpv6 = false;
try
{
IPAddress[] address = Dns.GetHostAddresses(ip);
for (int i = 0; i < address.Length; i++)
{
//从IP地址列表中筛选出IPv4类型的IP地址
//AddressFamily.InterNetwork表示此IP为IPv4,
//AddressFamily.InterNetworkV6表示此地址为IPv6类型
if (address[i].AddressFamily == AddressFamily.InterNetwork)
{
hasIpv4 = true;
}
else if (address[i].AddressFamily == AddressFamily.InterNetworkV6)
{
hasIpv6 = true;
}
Util.Log("Network IPAddresssFamily " + address[i].AddressFamily.ToString() + " IP: " + address[i].ToString());
}
}
catch (Exception ex)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient GetIPAddressType catch " + ex.Message);
2020-05-09 13:31:21 +08:00
return AddressFamily.InterNetwork;
}
if (hasIpv4)
return AddressFamily.InterNetwork;
if (hasIpv6)
return AddressFamily.InterNetworkV6;
return AddressFamily.InterNetwork;
}
public void OnReconnectFail()
{
2020-09-16 20:45:41 +08:00
AddStateInfo(NetworkStateType.ReconnectFail, "OnReconnectFail");
2020-05-09 13:31:21 +08:00
}
void OnReconnect(IAsyncResult result)
{
outStream = client.GetStream();
client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
2020-09-16 20:45:41 +08:00
AddStateInfo(NetworkStateType.Reconnected, "OnReconnect");
2020-05-09 13:31:21 +08:00
}
/// <summary>
/// 发送消息
/// </summary>
public void SendMessage(int msgId, ByteBuffer msg)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient SendMessage msgID: " + msgId);
2020-05-09 13:31:21 +08:00
m_serialId++;
m_SendMessage(msgId, msg, m_serialId);
}
void m_SendMessage(int msgId, ByteBuffer msg, int sn)
{
if (!IsConnected())
{
return;
}
ByteBuffer buffer = new ByteBuffer();
buffer.WriteIntToByte(AppConst.UserId);
buffer.WriteIntToByte(AppConst.Token);
buffer.WriteIntToByte(msgId);
buffer.WriteIntToByte(sn);
if (msg != null)
{
buffer.WriteBuffer(new LuaInterface.LuaByteBuffer(msg.ToBytes()));
msg.Close();
}
WriteMessage(buffer.ToBytes());
buffer.Close();
}
/// <summary>
/// 发送心跳
/// </summary>
public void SendHeartBeat()
{
ByteBuffer buffer = new ByteBuffer();
buffer.WriteIntToByte(AppConst.UserId);
buffer.WriteIntToByte(AppConst.Token);
buffer.WriteIntToByte(1000);
WriteMessage(buffer.ToBytes());
buffer.Close();
}
public bool IsConnected()
{
return client != null && client.Connected;
}
public void RegistNetMessage(int msgId, Action<ByteBuffer> handle)
{
if (!dispatchers.ContainsKey(msgId))
dispatchers.Add(msgId, new SimpleDispatcher());
SimpleDispatcher find = (SimpleDispatcher)dispatchers[msgId];
find.processor += handle;
}
public void UnregistNetMessage(int msgId, Action<ByteBuffer> handle)
{
if (!dispatchers.ContainsKey(msgId))
return;
SimpleDispatcher find = (SimpleDispatcher)dispatchers[msgId];
find.processor -= handle;
}
public void SendMessageWithCallBack(int msgId, int receiveMsgId, ByteBuffer message, LuaFunction callback)
{
2020-09-16 20:45:41 +08:00
Debug.Log("SocketClient SendMessageWithCallBack msgID:" + msgId.ToString());
2020-05-09 13:31:21 +08:00
if (!IsConnected())
{
UnityEngine.Debug.LogErrorFormat("Try to send message with invalid connection.");
AddStateInfo(NetworkStateType.Disconnect, "bytesRead < 1");
}
else
{
SimpleDispatcher cb = new SimpleDispatcher();
cb.processor += b => callback.Call(b);
if (!callbacks.ContainsKey(receiveMsgId))
{
callbacks.Add(receiveMsgId, cb);
}
m_SendMessage(msgId, message, m_serialId);
}
}
2020-09-16 20:45:41 +08:00
2020-05-09 13:31:21 +08:00
}