using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using ProtoCSStruct; namespace Sog { public class WaitAckStructRequest { public long UniqueID; public uint ServerID; public bool TimeoutResend; public int TimeoutMs; public long SendTime; public MessageData Message; } /// /// 一定需要等待回应的消息发送器 /// 邮件之类需要严格处理逻辑的可以使用 /// public class WaitAckStructRequestSender : Singleton { private ServerApp m_app; private StructPacketSender m_packetSender; private uint m_serverID; private long m_lastUniqueID = 0; private long m_lastTickTime = 0; private int m_sendCountThisTick = 0; //频率控制 private Dictionary m_sendAllPacket = new Dictionary(); public void Init(StructPacketSender packetSender, uint serverID, ServerApp app) { m_packetSender = packetSender; m_serverID = serverID; m_app = app; } public long GeneratorUniqueID() { if(m_lastUniqueID == 0) { //每次重启服务器不会重复,全局唯一,且保证是正数 m_lastUniqueID = m_serverID; m_lastUniqueID <<= 30; m_lastUniqueID += (AppTime.GetNowSysMs() << 4); } m_lastUniqueID++; return m_lastUniqueID; } public bool IsEmpty() { return m_sendAllPacket.Count == 0; } private void BeginSend(long uniqueID, uint serverID, int iMsgID, ref T structMessage, long iObjectID, bool resend, int timeout) where T : struct, IStructMessage { WaitAckStructRequest waitAckOne = new WaitAckStructRequest(); waitAckOne.UniqueID = uniqueID; waitAckOne.TimeoutResend = resend; waitAckOne.TimeoutMs = timeout; waitAckOne.SendTime = m_app.Time.GetTime(); waitAckOne.ServerID = serverID; MessageData messageData = new MessageData(); messageData.Header.Type = iMsgID; messageData.Header.ObjectID = iObjectID; bool bRet = ProtoPackerFactory.Instance.GetProtoCSStructPacker().PackMessage(ref structMessage, ref messageData); if (bRet == false) { //判断是不是sessionid,sessionid是个很大的数 if (Sog.Service.GateSessionID.IsGateSessionIDOrUserID(iObjectID)) { TraceLog.Error("WaitAckStructRequestSender PackMessage error server {0} msgId {1} iID {2} message:{3}" , ServerIDUtils.IDToString(serverID), iMsgID, iObjectID , structMessage.GetName()); } else { TraceLog.UserError(iObjectID, "WaitAckStructRequestSender PackMessage error server {0} msgId {1} iID {2} message:{3}" , ServerIDUtils.IDToString(serverID), iMsgID, iObjectID , structMessage.GetName()); } return; } waitAckOne.Message = messageData; m_sendAllPacket.Add(uniqueID, waitAckOne); m_packetSender.SendToServerByID(serverID, messageData.Clone()); /* * 测试数据库会不会有相同uniqueID多份邮件 if (OSUtils.IsWindows()) { m_packetSender.SendToServerByID(serverID, reqPacket); }*/ } public void BeginSendNeedResend(long uniqueID, uint serverID, int iMsgID, ref T structMessage, long iObjectID, int timeout = 30*1000) where T : struct, IStructMessage { BeginSend(uniqueID, serverID, iMsgID, ref structMessage, iObjectID, true, timeout); } public void OnReceiveSuccess(long uniqueID) { WaitAckStructRequest waitAckOne; if(m_sendAllPacket.TryGetValue(uniqueID,out waitAckOne)) { TraceLog.Trace("WaitAckStructRequestSender.OnReceiveSuccess uniqueID {0} MsgID {1}, removed" , uniqueID, waitAckOne.Message.Header.Type); m_sendAllPacket.Remove(uniqueID); waitAckOne.Message.FreeData(); } else { TraceLog.Trace("WaitAckStructRequestSender.OnReceiveSuccess no uniqueID {0}", uniqueID); } } public void Tick(long nowMs) { if(m_packetSender == null) { return; } //1秒一次 if(nowMs - m_lastTickTime < 1000) { return; } m_sendCountThisTick = 0; m_lastTickTime = nowMs; List deleteList = null; foreach(var one in m_sendAllPacket.Values) { //timeout if(nowMs - one.SendTime > one.TimeoutMs) { if(one.TimeoutResend) { one.SendTime = nowMs; m_packetSender.SendToServerByID(one.ServerID, one.Message.Clone()); m_sendCountThisTick++; //控制1秒最多100个请求,防止雪崩 if(m_sendCountThisTick > 100) { break; } TraceLog.Error("WaitAckStructRequestSender uniqueID {0} MsgID {1} timeout ,resend it, m_sendCountThisTick {2}" , one.UniqueID, one.Message.Header.Type, m_sendCountThisTick); } else { TraceLog.Error("WaitAckStructRequestSender uniqueID {0} MsgID {1} timeout ,delete it" , one.UniqueID, one.Message.Header.Type); if(deleteList == null) { deleteList = new List(); } deleteList.Add(one.UniqueID); } } } if(deleteList != null) { foreach(long uniqueid in deleteList) { m_sendAllPacket[uniqueid].Message.FreeData(); m_sendAllPacket.Remove(uniqueid); } } } public bool GetRequestByUniqueID(long uniqueId, out WaitAckStructRequest req) { return m_sendAllPacket.TryGetValue(uniqueId, out req); } } }