由于unity中的UI只能在主线程中访问,在网络线程中接收到的协议,无法直接用来处理UI方面显示逻辑。因此,可以先将网络线程接收到的协议缓存起来,在从主线程中一条一条取出来处理。
static void OnReceiveData()
{
if (buffCount<2)
{
return;//收到数据小于字节长度描述
}
int bodyLength = BitConverter.ToInt16(readBuff,0);
if (buffCount < 2 + bodyLength)
{
Debug.Log("收到数据不完整");
return;//长度不够一条完整消息
}
string recStr = Encoding.Default.GetString(readBuff,2, bodyLength);
Debug.Log("收到服务器消息" + recStr);
MsgBase msgBase = MsgBase.Decode(recStr);
lock (MsgHandler.Instance.msgList)//多线程访问,加锁
{
MsgHandler.Instance.msgList.Add(msgBase);
}
int start = 2 + bodyLength;
int count = buffCount - start;
Array.Copy(readBuff,start,readBuff,0,count);
buffCount -= start;
OnReceiveData();
}
在MsgHandler中接收协议,在主线程的Update中取协议进行处理,根据由协议名称注册的事件去触发相应的操作。
class MsgHandler
{
public delegate void MsgDelegate(MsgBase msg);
private Dictionary<string, MsgDelegate> listeners = new Dictionary<string, MsgDelegate>();
public List<MsgBase> msgList = new List<MsgBase>();
private static MsgHandler instance;
public static MsgHandler Instance
{
get
{
if (instance == null)
instance = new MsgHandler();
return instance;
}
}
public void AddListener(string msgName, MsgDelegate listener)
{
if (!listeners.ContainsKey(msgName))
{
listeners.Add(msgName, listener);
}
else
{
listeners[msgName] = listener;
}
}
public void Start()
{
AddListeners();
}
public void Update()//在主线程中取协议
{
if (!NetManager.isConnected) return;
if (msgList.Count <= 0)
{
return;
}
MsgBase msg = msgList[0];
msgList.RemoveAt(0);
if (listeners.ContainsKey(msg.protoName))
{
listeners[msg.protoName](msg);//根据协议名称触发事件
}
}
void AddListeners()
{
AddListener("MsgHeartbeat", OnHeartbeat);//根据协议名称注册相应事件
}
void OnHeartbeat(MsgBase msg)//心跳检测
{
Debug.Log("收到服务器心跳包");
GameManager.Instance.ResetTimer();
}
}