You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.8 KiB

1 month ago
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;
}
/// <summary>
/// 一定需要等待回应的消息发送器
/// 邮件之类需要严格处理逻辑的可以使用
/// </summary>
public class WaitAckStructRequestSender : Singleton<WaitAckStructRequestSender>
{
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<long, WaitAckStructRequest> m_sendAllPacket = new Dictionary<long, WaitAckStructRequest>();
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<T>(long uniqueID, uint serverID, int iMsgID, ref T structMessage, long iObjectID, bool resend, int timeout)
where T : struct, IStructMessage<T>
{
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<T>(long uniqueID, uint serverID, int iMsgID, ref T structMessage, long iObjectID, int timeout = 30*1000)
where T : struct, IStructMessage<T>
{
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<long> 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<long>();
}
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);
}
}
}