366 lines
11 KiB
C#
366 lines
11 KiB
C#
/*
|
||
********************************************************************************
|
||
*Copyright(C),coolae.net
|
||
*Author: chenbin
|
||
*Version: 2.0
|
||
*Date: 2017-01-09
|
||
*Description: tcp
|
||
*Others:
|
||
*History:
|
||
*********************************************************************************
|
||
*/
|
||
|
||
using UnityEngine;
|
||
using System.Collections;
|
||
using System.IO;
|
||
using XLua;
|
||
|
||
namespace Coolape
|
||
{
|
||
#if !UNITY_WEBGL
|
||
public delegate void TcpDispatchDelegate(object data, Tcp tcp);
|
||
public class Tcp : MonoBehaviour
|
||
{
|
||
public string host;
|
||
public int port;
|
||
public bool connected = false;
|
||
public bool serializeInMainThread = true;
|
||
//是否连接
|
||
public bool isStopping = false;
|
||
const int MaxReConnectTimes = 0;
|
||
public static int __maxLen = 1024 * 1024;
|
||
|
||
System.Threading.Timer timer;
|
||
public USocket socket;
|
||
int reConnectTimes = 0;
|
||
public const string CONST_Connect = "connectCallback";
|
||
public const string CONST_OutofNetConnect = "outofNetConnect";
|
||
TcpDispatchDelegate mDispatcher;
|
||
byte[] tmpBuffer = new byte[__maxLen];
|
||
|
||
public virtual void init(string host, int port)
|
||
{
|
||
this.host = host;
|
||
this.port = port;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Init the specified host, port and dispatcher.
|
||
/// </summary>
|
||
/// <param name="host">Host.</param>
|
||
/// <param name="port">Port.</param>
|
||
/// <param name="dispatcher">Dispatcher,当接收到数据并解析成功后将调用该方法.</param>
|
||
public virtual void init(string host, int port, TcpDispatchDelegate dispatcher)
|
||
{
|
||
mDispatcher = dispatcher;
|
||
this.host = host;
|
||
this.port = port;
|
||
}
|
||
|
||
public void connect()
|
||
{
|
||
connect(null);
|
||
}
|
||
public void connect(object obj)
|
||
{
|
||
if (socket != null)
|
||
{
|
||
stop();
|
||
}
|
||
isStopping = false;
|
||
socket = new USocket(host, port);
|
||
|
||
#if UNITY_EDITOR
|
||
Debug.Log("connect ==" + host + ":" + port);
|
||
#endif
|
||
//异步连接
|
||
socket.connectAsync(onConnectStateChg);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Ons the connect state chg. 当连接状态发生变化时
|
||
/// </summary>
|
||
/// <param name="s">S.</param>
|
||
/// <param name="result">Result. 其实是bool类型,
|
||
/// 当为true表示连接成功,false时表示没有连接成功或连接断开</param>
|
||
public virtual void onConnectStateChg(USocket s, object result)
|
||
{
|
||
ArrayList list = result as ArrayList;
|
||
bool isConnected = (bool)list[0];
|
||
int retCode = (int)list[1];
|
||
string msg = (string)list[2];
|
||
if (isConnected)
|
||
{
|
||
#if UNITY_EDITOR
|
||
Debug.Log("connectCallback success");
|
||
#endif
|
||
connected = true;
|
||
reConnectTimes = 0;
|
||
socket.ReceiveAsync(onReceive);
|
||
enqueueData(CONST_Connect);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning("connectCallback fail" + host + ":" + port + "," + isStopping);
|
||
connected = false;
|
||
if (!isStopping)
|
||
{
|
||
outofNetConnect(retCode, msg);
|
||
}
|
||
}
|
||
}
|
||
|
||
public void outofNetConnect(int code, string msg)
|
||
{
|
||
if (isStopping)
|
||
return;
|
||
if (reConnectTimes < MaxReConnectTimes)
|
||
{
|
||
reConnectTimes++;
|
||
Debug.LogWarning("reconnect times=" + reConnectTimes);
|
||
if (timer != null)
|
||
{
|
||
timer.Dispose();
|
||
}
|
||
timer = TimerEx.schedule(connect, null, 5000);
|
||
}
|
||
else
|
||
{
|
||
if (timer != null)
|
||
{
|
||
timer.Dispose();
|
||
}
|
||
timer = null;
|
||
outofLine(socket, null);
|
||
}
|
||
}
|
||
|
||
public void outofLine(USocket s, object obj)
|
||
{
|
||
if (!isStopping)
|
||
{
|
||
stop();
|
||
//CLMainBase.self.onOffline();
|
||
enqueueData(CONST_OutofNetConnect);
|
||
}
|
||
}
|
||
|
||
public virtual void stop()
|
||
{
|
||
isStopping = true;
|
||
connected = false;
|
||
if (socket != null)
|
||
{
|
||
socket.close();
|
||
}
|
||
socket = null;
|
||
}
|
||
|
||
//==========================================
|
||
public bool send(object obj)
|
||
{
|
||
if (socket == null)
|
||
{
|
||
Debug.LogWarning("Socket is null");
|
||
return false;
|
||
}
|
||
object ret = packMessage(obj);
|
||
if (isStopping || !connected)
|
||
{
|
||
Debug.LogWarning("isStopping =" + isStopping + "|| !connected=" + !connected);
|
||
return false;
|
||
}
|
||
if (ret != null)
|
||
{
|
||
socket.SendAsync(ret as byte[]);
|
||
}
|
||
else
|
||
{
|
||
//这种情况可能是在组包的时候就已经发送了,还有种情况就是异常,不过其实不太可能异常,先不处理
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public object packMessage(object obj)
|
||
{
|
||
try
|
||
{
|
||
return encodeData(obj);
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
MemoryStream os = new MemoryStream();
|
||
MemoryStream os2 = new MemoryStream();
|
||
|
||
/// <summary>
|
||
/// Encodes the data.数据组包准备发送
|
||
/// </summary>
|
||
/// <returns>The data.</returns>
|
||
/// <param name="obj">Object.</param>
|
||
public virtual byte[] encodeData(object obj)
|
||
{
|
||
os.Position = 0;
|
||
os2.Position = 0;
|
||
|
||
B2OutputStream.writeObject(os, obj);
|
||
int len = (int)os.Position;
|
||
B2OutputStream.writeInt(os2, len);
|
||
os2.Write(os.ToArray(), 0, len);
|
||
int pos = (int)os2.Position;
|
||
byte[] result = new byte[pos];
|
||
os2.Position = 0;
|
||
os2.Read(result, 0, pos);
|
||
return result;
|
||
}
|
||
|
||
//==========================================
|
||
MemoryStreamPool memorystreamPool = new MemoryStreamPool();
|
||
public void onReceive(USocket s, byte[] bytes, int len)
|
||
{
|
||
MemoryStream buffer = memorystreamPool.borrowObject();
|
||
buffer.Write(bytes, 0, len);
|
||
buffer.SetLength(len);
|
||
enqueueData(buffer);
|
||
}
|
||
|
||
object netData = null;
|
||
MemoryStream memoryBuff = null;
|
||
MemoryStream receivedBuffer = new MemoryStream();
|
||
public IEnumerator wrapBuffer2Unpack()
|
||
{
|
||
yield return null;
|
||
while (receivedDataQueue.Count > 0)
|
||
{
|
||
netData = receivedDataQueue.Dequeue();
|
||
if (netData != null)
|
||
{
|
||
if (netData is string)
|
||
{
|
||
if (mDispatcher != null)
|
||
{
|
||
mDispatcher(netData, this);
|
||
}
|
||
continue;
|
||
}
|
||
memoryBuff = netData as MemoryStream;
|
||
receivedBuffer.Write(memoryBuff.ToArray(), 0, (int)(memoryBuff.Length));
|
||
memorystreamPool.returnObject(memoryBuff);
|
||
}
|
||
}
|
||
if (receivedBuffer.Length > 0)
|
||
{
|
||
receivedBuffer.SetLength(receivedBuffer.Position);
|
||
unpackMsg(receivedBuffer);
|
||
}
|
||
}
|
||
|
||
public void unpackMsg(MemoryStream buffer)
|
||
{
|
||
bool isLoop = true;
|
||
object o = null;
|
||
long usedLen = 0;
|
||
while (isLoop)
|
||
{
|
||
long totalLen = buffer.Length;
|
||
if (totalLen > 2)
|
||
{
|
||
usedLen = 0;
|
||
o = parseRecivedData(buffer);
|
||
usedLen = buffer.Position;
|
||
if (usedLen > 0)
|
||
{
|
||
int leftLen = (int)(totalLen - usedLen);
|
||
if (leftLen > 0)
|
||
{
|
||
buffer.Read(tmpBuffer, 0, leftLen);
|
||
buffer.Position = 0;
|
||
buffer.Write(tmpBuffer, 0, leftLen);
|
||
buffer.SetLength(leftLen);
|
||
}
|
||
else
|
||
{
|
||
buffer.Position = 0;
|
||
buffer.SetLength(0);
|
||
isLoop = false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//buffer.Position = totalLen;
|
||
isLoop = false;
|
||
}
|
||
|
||
if (o != null && mDispatcher != null)
|
||
{
|
||
mDispatcher(o, this);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
isLoop = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Parses the recived data.解析接收的数据,解析成功后发送给dispatcher
|
||
/// </summary>
|
||
/// <returns>The recived data.</returns>
|
||
/// <param name="buffer">Buffer.</param>
|
||
public virtual object parseRecivedData(MemoryStream buffer)
|
||
{
|
||
object ret = null;
|
||
long oldPos = buffer.Position;
|
||
buffer.Position = 0;
|
||
long tatolLen = buffer.Length;
|
||
long needLen = B2InputStream.readInt(buffer);
|
||
if (needLen <= 0 || needLen > __maxLen)
|
||
{
|
||
// 网络Number据错误。断isOpen网络
|
||
outofLine(this.socket, false);
|
||
//this.stop();
|
||
return null;
|
||
}
|
||
long usedLen = buffer.Position;
|
||
if (usedLen + needLen <= tatolLen)
|
||
{
|
||
ret = B2InputStream.readObject(buffer);
|
||
}
|
||
else
|
||
{
|
||
//说明长度不够
|
||
buffer.Position = oldPos;
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
//======================================================================
|
||
//======================================================================
|
||
//======================================================================
|
||
public Queue receivedDataQueue = new Queue();
|
||
|
||
public void enqueueData(object obj)
|
||
{
|
||
receivedDataQueue.Enqueue(obj);
|
||
if (!serializeInMainThread)
|
||
{
|
||
StartCoroutine(wrapBuffer2Unpack());
|
||
}
|
||
}
|
||
|
||
public virtual void Update()
|
||
{
|
||
if (serializeInMainThread && receivedDataQueue.Count > 0)
|
||
{
|
||
StartCoroutine(wrapBuffer2Unpack());
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
}
|