private void Serialize(MemoryStream ms, ProtoMessage msg) { if (msg.Data != null) { Serializer.Serialize <IExtensible> (ms, msg.Data); } }
public void Enqueue(ProtoMessage msg) { lock (this) { q.Enqueue(msg); Monitor.Pulse(this); } }
// Update method is called by outside MonoBehaviour object's Update method public void Update() { // 定期检查心跳,分发消息处理,由外部的MonoBehaviour对象驱动 if (_running) { if (_needHB) { long nowms = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; if (nowms - _lastRecvHBTime > Constants.CORPC_MAX_NO_HEARTBEAT_TIME) { // 无心跳,断线 Debug.LogError("heartbeat timeout"); Close(); } else if (nowms - _lastSendHBTime > Constants.CORPC_HEARTBEAT_PERIOD) { Send(Constants.CORPC_MSG_TYPE_HEARTBEAT, null); _lastSendHBTime = nowms; } } // 心跳和断线消息需要特殊处理 ProtoMessage pmsg = _recvMsgQueue.Dequeue(); while (pmsg != null) { switch (pmsg.Type) { case Constants.CORPC_MSG_TYPE_DISCONNECT: { Close(); // 清理收发队列(主要是发送队列) // 注意:此时收发线程已经退出,对收发队列的处理没有线程同步的问题 _recvMsgQueue.Clear(); _sendMsgQueue.Clear(); Dispatch(Constants.CORPC_MSG_TYPE_DISCONNECT, null); break; } case Constants.CORPC_MSG_TYPE_HEARTBEAT: { _lastRecvHBTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; break; } default: { Dispatch(pmsg.Type, pmsg.Data); break; } } pmsg = _recvMsgQueue.Dequeue(); } } }
protected byte[] Serialize(ProtoMessage msg) { if (msg.Data != null) { return(msg.Data.ToByteArray()); } Debug.LogErrorFormat("Serialize empty msg [{0}]!!!", msg.Type); return(null); }
private void SendMsgLoop() { while (true) { ProtoMessage msg = null; try { msg = _sendMsgQueue.Dequeue(); Debug.Assert(msg != null); if (msg.Type == Constants.CORPC_MSG_TYPE_DISCONNECT) { return; } else { // 构造要发出的消息数据 MemoryStream ms = new MemoryStream(); Serialize(ms, msg); int dataLength = (int)ms.Length; byte[] buf = new byte[8 + dataLength]; // 设置头部 buf[0] = (byte)((dataLength >> 24) & 0xFF); buf[1] = (byte)((dataLength >> 16) & 0xFF); buf[2] = (byte)((dataLength >> 8) & 0xFF); buf[3] = (byte)(dataLength & 0xFF); buf[4] = (byte)((msg.Type >> 24) & 0xFF); buf[5] = (byte)((msg.Type >> 16) & 0xFF); buf[6] = (byte)((msg.Type >> 8) & 0xFF); buf[7] = (byte)(msg.Type & 0xFF); ms.Position = 0; int remainLen = dataLength; while (remainLen > 0) { remainLen -= ms.Read(buf, 8 + dataLength - remainLen, remainLen); } _udpSocket.Send(buf); } } catch (System.Exception ex) { Debug.LogError("SendMsgLoop error!!! --- "); Debug.LogError(ex.ToString()); Debug.LogError(ex.StackTrace); return; } } }
private void SendMsgLoop() { byte[] buf = new byte[Constants.CORPC_MAX_UDP_MESSAGE_SIZE]; while (true) { ProtoMessage msg = null; try { msg = _sendMsgQueue.Dequeue(); Debug.Assert(msg != null); switch (msg.Type) { case Constants.CORPC_MSG_TYPE_DISCONNECT: { return; } case Constants.CORPC_MSG_TYPE_HEARTBEAT: { _udpSocket.Send(_heartbeatmsg, (int)Constants.CORPC_MESSAGE_HEAD_SIZE, SocketFlags.None); break; } default: { // 构造要发出的消息数据 byte[] data = Serialize(msg); uint dataLength = (uint)data.Length; if (Constants.CORPC_MESSAGE_HEAD_SIZE + dataLength > Constants.CORPC_MAX_UDP_MESSAGE_SIZE) { Debug.LogError("send message size too large!!!"); _recvMsgQueue.Enqueue(new ProtoMessage(Constants.CORPC_MSG_TYPE_DISCONNECT, 0, null, false)); return; } ushort flag = 0; if (dataLength > 0) { // 加密 if (msg.NeedCrypter) { _crypter.encrypt(data, 0, buf, Constants.CORPC_MESSAGE_HEAD_SIZE, dataLength); flag |= Constants.CORPC_MESSAGE_FLAG_CRYPT; } else { Array.Copy(data, 0, buf, Constants.CORPC_MESSAGE_HEAD_SIZE, dataLength); } } // 设置头部 buf[0] = (byte)((dataLength >> 24) & 0xFF); buf[1] = (byte)((dataLength >> 16) & 0xFF); buf[2] = (byte)((dataLength >> 8) & 0xFF); buf[3] = (byte)(dataLength & 0xFF); buf[4] = (byte)((msg.Type >> 8) & 0xFF); buf[5] = (byte)(msg.Type & 0xFF); buf[6] = (byte)((msg.Tag >> 8) & 0xFF); buf[7] = (byte)(msg.Tag & 0xFF); buf[8] = (byte)((flag >> 8) & 0xFF); buf[9] = (byte)(flag & 0xFF); if (_enableSerial) { // _lastRecvSerial是否会导致线程同步问题? buf[10] = (byte)((_lastRecvSerial >> 24) & 0xFF); buf[11] = (byte)((_lastRecvSerial >> 16) & 0xFF); buf[12] = (byte)((_lastRecvSerial >> 8) & 0xFF); buf[13] = (byte)(_lastRecvSerial & 0xFF); _lastSendSerial++; buf[14] = (byte)((_lastSendSerial >> 24) & 0xFF); buf[15] = (byte)((_lastSendSerial >> 16) & 0xFF); buf[16] = (byte)((_lastSendSerial >> 8) & 0xFF); buf[17] = (byte)(_lastSendSerial & 0xFF); } if (_enableSendCRC) { ushort crc = CRC.CheckSum(buf, 0, 0xFFFF, Constants.CORPC_MESSAGE_HEAD_SIZE - 2); crc = CRC.CheckSum(buf, Constants.CORPC_MESSAGE_HEAD_SIZE, crc, dataLength); buf[18] = (byte)((crc >> 8) & 0xFF); buf[19] = (byte)(crc & 0xFF); } _udpSocket.Send(buf, (int)(Constants.CORPC_MESSAGE_HEAD_SIZE + dataLength), SocketFlags.None); break; } } } catch (System.Exception ex) { Debug.LogError("SendMsgLoop error!!! --- "); Debug.LogError(ex.ToString()); Debug.LogError(ex.StackTrace); return; } } }
// Update method is called by outside MonoBehaviour object's Update method public void Update() { // 定期检查心跳,分发消息处理,由外部的MonoBehaviour对象驱动 if (_running) { long nowms = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; if (nowms - _lastRecvHBTime > Constants.CORPC_MAX_NO_HEARTBEAT_TIME) { // 无心跳,断线 Debug.LogError("heartbeat timeout"); Close(); } else if (nowms - _lastSendHBTime > Constants.CORPC_HEARTBEAT_PERIOD) { if (_shakeOK) { Send(Constants.CORPC_MSG_TYPE_HEARTBEAT, 0, null, false); _lastSendHBTime = nowms; } } // 心跳和断线消息需要特殊处理 ProtoMessage pmsg = _recvMsgQueue.Dequeue(); while (pmsg != null) { switch (pmsg.Type) { case Constants.CORPC_MSG_TYPE_DISCONNECT: case Constants.CORPC_MSG_TYPE_UDP_UNSHAKE: { Close(); break; } case Constants.CORPC_MSG_TYPE_UDP_HANDSHAKE_2: { if (!_shakeOK) { // 重发handshake_3 try { _udpSocket.Send(_handshake3msg); } catch (System.Exception ex) { Debug.LogError("Send handshake3 failed"); Debug.LogError(ex.ToString()); Debug.LogError(ex.StackTrace); Close(); break; } } break; } case Constants.CORPC_MSG_TYPE_UDP_HANDSHAKE_4: { _shakeOK = true; Debug.Log("shake succeed"); // 启动发送线程 _sendMsgThread = new Thread(new ThreadStart(SendMsgLoop)); _sendMsgThread.Start(); break; } case Constants.CORPC_MSG_TYPE_HEARTBEAT: { _lastRecvHBTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; break; } default: { if (!_shakeOK) { Debug.LogError("recv msg when unshaked"); Close(); break; } HandleMessage(pmsg.Type, pmsg.Data); break; } } pmsg = _recvMsgQueue.Dequeue(); } } }
public void Enqueue(ProtoMessage msg) { lock (this) { q.Enqueue(msg); } }