目录为:Assets/Scripts/Common/目录下,
NetworkManger.cs
当然看名字就知道啥意思了.
下面的代码里我注释了一些,以便可以在下一篇文章单独测试一下.
这里面最重要的就是Init方法,Update方法,SendMsg方法,
因为这三个方法是在外面要用的。
下一篇测试一下.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Net;
//using ProtoBuf;
using System.Net.Sockets;
using System.Threading;
//继承单例
public class NetworkManager: Singleton
{
//Server type
public enum ServerType
{
GateServer = 0,
BalanceServer,
LoginServer
}
//client
private TcpClient m_Client = null;
private TcpClient m_Connecting = null;
//服务器IP
private string m_IP = "127.0.0.1";
//端口号
private Int32 m_Port = 40001;
private Int32 m_n32ConnectTimes = 0;
//Server Type
private ServerType serverType = ServerType.BalanceServer;
private float m_CanConnectTime = 0f;
//超时
private float m_RecvOverTime = 0f;
private float mRecvOverDelayTime = 2f;
private Int32 m_ConnectOverCount = 0;
private float m_ConnectOverTime = 0f;
private Int32 m_RecvOverCount = 0;
private bool canReconnect =false;
//这里和CMemBuffer有点像
//m_RecvBuffer:第一个四字节:length,length包括了length和type所占用的8个字节
//m_RecvBuffer:第二个四字节:type
//m_RecvBuffer:再后面就是data了
public byte[] m_RecvBuffer = new byte[2 * 1024 * 1024];
public Int32 m_RecvPos = 0;
//Error时会赋值成null
IAsyncResult mRecvResult;
IAsyncResult mConnectResult;
//发送数据stream
public System.IO.MemoryStream mSendStream = new System.IO.MemoryStream ();
//MsgIds
public List<int> mReceiveMsgIDs = new List<int> ();
//接收数据stream
public List mReceiveStreams = new List ();
//MemoryStream pool
public List mReceiveStreamsPool = new List ();
//构造函数
public NetworkManager()
{
//pool里放50个MemoryStream
for (int i = 0; i < 50; i++)
{
mReceiveStreamsPool.Add (new System.IO.MemoryStream ());
}
/*
//下面全是用工具生成的
//预先创建消息RuntimeTypeModel运行时类型模型
//A
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
//B
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
//C
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
//D
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
//E
ProtoBuf.Serializer.PrepareSerializer();
//F
ProtoBuf.Serializer.PrepareSerializer();
//G
ProtoBuf.Serializer.PrepareSerializer();
//H
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
//L
ProtoBuf.Serializer.PrepareSerializer();
//M
ProtoBuf.Serializer.PrepareSerializer();
//N
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
//P
ProtoBuf.Serializer.PrepareSerializer();
//S
ProtoBuf.Serializer.PrepareSerializer();
//R
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
ProtoBuf.Serializer.PrepareSerializer();
//U
ProtoBuf.Serializer.PrepareSerializer();
*/
}
//析构函数
~NetworkManager()
{
//接收stream
foreach (System.IO.MemoryStream one in mReceiveStreams)
{
one.Close ();
}
//MemoryStream池释放掉
foreach(System.IO.MemoryStream one in mReceiveStreamsPool)
{
one.Close ();
}
//发送stream
if (mSendStream != null)
{
mSendStream.Close ();
}
//client
if (m_Client != null)
{
m_Client.Client.Shutdown (SocketShutdown.Both);
//NetworkStream关闭
m_Client.GetStream ().Close ();
//TcpClient
m_Client.Close ();
m_Client = null;
}
}
public void Init(string ip, Int32 port, ServerType type)
{
Debug.Log ("set network ip:" + ip + " port:" + port + "type" + type);
m_IP = ip;
m_Port = port;
serverType = type;
m_n32ConnectTimes = 0;
canReconnect = true;
m_RecvPos = 0;
#if UNITY_EDITOR
mRecvOverDelayTime = 20000f;
#endif
}
public void UnInit ()
{
canReconnect = false;
}
//连接
public void Connect ()
{
if (!canReconnect)
{
return;
}
//mCanConnectTime = 0.0f
if (m_CanConnectTime > Time.time)
{
return;
}
if (m_Client != null)
{
throw new Exception("fuck, The socket is connecting, can not connect again!");
}
if (m_Connecting != null)
{
throw new Exception ("fuckm The socket is connecting, can not connect again!");
}
Debug.Log ("IClientSession Connect");
//ip
IPAddress ipAddress = IPAddress.Parse (m_IP);
try
{
m_Connecting = new TcpClient();
//开始对一个远程主机连接的异步请求。远程主机由IPAddress和端口号(Int32)指定
mConnectResult = m_Connecting.BeginConnect(m_IP, m_Port, null, null);
m_ConnectOverCount = 0;
m_ConnectOverTime = Time.time + 2;
}
catch (Exception exc)
{
Debug.Log (exc.ToString ());
m_Client = m_Connecting;
m_Connecting = null;
mConnectResult = null;
OnConnectError (m_Client, null);
}
}
//关闭
public void Close()
{
if (m_Client != null)
{
OnClosed (m_Client, null);
}
}
public void Update(float fDeltaTime)
{
if (m_Client != null)
{
//Msg操作
DealWithMsg ();
if (mRecvResult != null)
{
//接收超时
if (m_RecvOverCount > 200 && Time.time > m_RecvOverTime)
{
Debug.LogError ("recv data over 200, so close network!");
Close ();
return;
}
++m_RecvOverCount;
//获取一个值,该值指示异步操作是否已完成。
//当此属性是true, 你可以假定为安全地放弃用于分配由异步操作的任何资源.
if (mRecvResult.IsCompleted)
{
//-------------------------------------------------------
try
{
//EndRead:处理异步读取的结束
//返回读取的字节数量
Int32 n32BytesRead = m_Client.GetStream().EndRead(mRecvResult);
m_RecvPos += n32BytesRead;
if (n32BytesRead == 0)
{
Debug.LogError("cannot recv data now, so close network 2");
Close();
return;
}
}
catch (Exception exc)
{
Debug.LogError (exc.ToString ());
Close ();
return;
}
OnDataReceived (null, null);
//-------------------------------------------------------
if (m_Client != null)
{
try
{
mRecvResult = m_Client.GetStream().BeginRead(m_RecvBuffer, m_RecvPos, m_RecvBuffer.Length - m_RecvPos, null, null);
m_RecvOverTime = Time.time + mRecvOverDelayTime;
m_RecvOverCount = 0;
}
catch (Exception exc)
{
Debug.LogError (exc.ToString ());
Close ();
return;
}
}
}
}
if (m_Client != null && m_Client.Connected == false)
{
Debug.LogError ("client is close by system, so close it now.");
Close ();
return;
}
}
//m_RecvResult == null时
else if (m_Connecting != null)
{
if (m_ConnectOverCount > 200 && Time.time > m_ConnectOverTime)
{
Debug.LogError ("cant connect, so close network.");
m_Client = m_Connecting;
m_Connecting = null;
mConnectResult = null;
OnConnectError (m_Client, null);
return;
}
++m_ConnectOverCount;
if (mConnectResult.IsCompleted)
{
m_Client = m_Connecting;
m_Connecting = null;
mConnectResult = null;
if (m_Client.Connected)
{
try
{
m_Client.NoDelay = true;
m_Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 2000);
m_Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000);
m_Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
//从0开始填m_RecvBuffer
mRecvResult = m_Client.GetStream().BeginRead(m_RecvBuffer, 0, m_RecvBuffer.Length, null, null);
//每次加2毫秒
m_RecvOverTime = Time.time + mRecvOverDelayTime;
m_RecvOverCount = 0;
OnConneted(m_Client, null);
}
catch (Exception exc)
{
Debug.LogError (exc.ToString ());
Close ();
return;
}
}
else
{
OnConnectError (m_Client, null);
}
}
}
else
{
//这里重新连接
Connect ();
}
}
//发送数据
//ProtoBuf
public void SendMsg(/*ProtoBuf.IExtensible pMsg, Int32 n32MsgID*/ byte[] bytes, int bytesLength)
{
if (m_Client != null)
{
//这个mSendStream反复使用
//清除stream
mSendStream.SetLength (0);
mSendStream.Position = 0;
//序列到stream
//ProtoBuf.Serializer.Serialize (mSendStream, pMsg);
//CMsg pcMsg = new CMsg ((int)mSendStream.Length);
//pcMsg.setProtocalID (n32MsgId);
//数据写进pcMsg
//pcMsg.Add (mSendStream.ToArray (), 0, (int)mSendStream.Length);
#if UNITY_EDITOR
#else
try
{
#endif
#if LOG_FILE && UNITY_EDITOR
if (n32MsgID != 8192 && n32MsgID != 16385)
{
string msgName = "";
if (Enum.IsDefined(typeof(GCToBS.MsgNum), n32MsgID))
{
msgName = ((GCToBS.MsgNum)n32MsgID).ToString();
}
else if (Enum.IsDefined(typeof(GCToCS.MsgNum), n32MsgID))
{
msgName = ((GCToCS.MsgNum)n32MsgID).ToString();
}
else if (Enum.IsDefined(typeof(GCToLS.MsgID), n32MsgID))
{
msgName = ((GCToLS.MsgID)n32MsgID).ToString();
}
else if (Enum.IsDefined(typeof(GCToSS.MsgNum), n32MsgID))
{
msgName = ((GCToSS.MsgNum)n32MsgID).ToString();
}
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(@"E:\Log.txt", true))
{
sw.WriteLine(Time.time + " 发送消息:\t" + n32MsgID + "\t" + msgName);
}
}
#endif
//把pcMsg写进NetworkStream
//写进去,然后就会发送
//m_Client.GetStream().Write(pcMsg.GetMsgBuffer(), 0, (int)pcMsg.GetMsgSize());
m_Client.GetStream().Write(bytes, 0, bytesLength);
#if UNITY_EDITOR
#else
}
catch (Exception exc)
{
Debug.logError(exc.ToString());
Close();
}
#endif
}
}
public void OnConneted(object sender, EventArgs e)
{
switch (serverType)
{
case ServerType.BalanceServer:
{
//CGLCtrl_GameLogic.Instance.BsOneClientLogin ();
}
break;
case ServerType.GateServer:
{
++m_n32ConnectTimes;
if (m_n32ConnectTimes > 1) {
//CGLCtrl_GameLogic.Instance.EmsgTocsAskReconnect ();
} else {
//CGLCtrl_GameLogic.Instance.GameLogin ();
}
EventCenter.Broadcast (EGameEvent.eGameEvent_ConnectServerSuccess);
}
break;
case ServerType.LoginServer:
{
//这里面会有发送msg信息的操作
//CGLCtrl_GameLogic.Instance.EmsgToLs_AskLogin ();
}
break;
}
}
//连接错误
public void OnConnectError(object sender, ErrorEventArgs e)
{
Debug.Log ("OnConnectError begin");
try
{
m_Client.Client.Shutdown(SocketShutdown.Both);
m_Client.GetStream().Close();
m_Client.Close();
m_Client = null;
}
catch (Exception exc)
{
Debug.Log (exc.ToString ());
}
mRecvResult = null;
m_Client = null;
m_RecvPos = 0;
m_RecvOverCount = 0;
m_ConnectOverCount = 0;
EventCenter.Broadcast (EGameEvent.eGameEvent_ConnectServerFail);
Debug.Log ("OnConnectError end");
}
public void OnClosed(object sender, EventArgs e)
{
EventCenter.Broadcast (EGameEvent.eGameEvent_ConnectServerFail);
try
{
m_Client.Client.Shutdown(SocketShutdown.Both);
m_Client.GetStream().Close();
m_Client.Close();
m_Client = null;
}
catch (Exception exc)
{
Debug.Log (exc.ToString ());
}
mRecvResult = null;
m_Client = null;
m_RecvPos = 0;
m_RecvOverCount = 0;
m_ConnectOverCount = 0;
mReceiveStreams.Clear ();
mReceiveMsgIDs.Clear ();
}
//处理Msg
public void DealWithMsg()
{
while (mReceiveMsgIDs.Count > 0 && mReceiveStreams.Count > 0)
{
int type = mReceiveMsgIDs [0];
System.IO.MemoryStream iostream = mReceiveStreams [0];
//当您调用RemoveAt要删除某个项,在列表中其余项目会重新编号来替换已移除的项.
mReceiveMsgIDs.RemoveAt (0);
mReceiveStreams.RemoveAt (0);
try
{
//CGLCtrl_GameLogic.Instance.HandleNetMsg(iostream, type);
if (mReceiveStreamsPool.Count < 100)
{
mReceiveStreamsPool.Add(iostream);
}
else
{
iostream = null;
}
}
catch (Exception exc)
{
Debug.LogError("Handle error msgid: " + type);
}
}
}
public void OnDataReceived(object sender, DataEventArgs e)
{
int m_CurPos = 0;
//因为length和type就占了8字节,所以要大于等于8
while (m_RecvPos - m_CurPos >= 8)
{
//这里和CMemBuffer有点像
//m_RecvBuffer:第一个四字节:length,length包括了length和type所占用的8个字节
//m_RecvBuffer:第二个四字节:type
//m_RecvBuffer:再后面就是data了
int len = BitConverter.ToInt32 (m_RecvBuffer, m_CurPos);
int type = BitConverter.ToInt32 (m_RecvBuffer, m_CurPos + 4);
if (len > m_RecvBuffer.Length)
{
Debug.LogError ("cannot pause message" + " type= " + type + " len= " + len);
break;
}
if (len > m_RecvPos - m_CurPos)
{
//这时候,data还没接受完
break;//wait ne recv more buffer to parse.
}
//获取stream
System.IO.MemoryStream tempStream = null;
if (mReceiveStreamsPool.Count > 0)
{
tempStream = mReceiveStreamsPool [0];
tempStream.SetLength (0);
tempStream.Position = 0;
mReceiveStreamsPool.RemoveAt (0);
}
else
{
tempStream = new System.IO.MemoryStream ();
}
//往stream填充网络数据
tempStream.Write (m_RecvBuffer, m_CurPos + 8, len - 8);
tempStream.Position = 0;
m_CurPos += len;
mReceiveMsgIDs.Add (type);
mReceiveStreams.Add (tempStream);
}
if (m_CurPos > 0)
{
//m_RecvPos减去已经读取的字节
m_RecvPos = m_RecvPos - m_CurPos;
if (m_RecvPos < 0)
{
Debug.LogError ("m_RecvPos < 0");
}
if (m_RecvPos > 0)
{
Buffer.BlockCopy (m_RecvBuffer, m_CurPos, m_RecvBuffer, 0, m_RecvPos);
}
}
}
}