using XGame.Framework.Time; using System; using XGame.Framework.Interfaces; namespace XGame.Framework.Network { internal class Heartbeat : IHeartbeat, IDisposable { private IHeartbeatListener _listener; private ISessionContext _context; public bool Started => _started; private bool _started = false; private bool _isTimeout = false; public int Timeout { get; set; } = 12000; public int Interval { get; set; } = 6000; private ITimer _timeoutTimer; private ITimer _intervalTimer; public Heartbeat(IHeartbeatListener listener, ISessionContext context) { _listener = listener; _context = context; } public void Start() { if (_started) return; Log.Debug("Heartbeat Start."); _started = true; _intervalTimer = _context.Time.AddLooperTimer(Interval, Send); Send(0); } public void Stop() { if (!_started) return; Log.Debug("Heartbeat Stop."); _started = false; _isTimeout = false; _timeoutTimer?.Cancel(); _timeoutTimer = null; _intervalTimer?.Cancel(); _intervalTimer = null; } public void Receive() { if (!_started) return; _timeoutTimer?.Cancel(); _timeoutTimer = null; _isTimeout = false; // 重置心跳的定时器,减少心跳次数,若服务器需要固定心跳间隔,则取消该步骤 (_intervalTimer as IReset)?.Reset(); } private void Send(int times) { _timeoutTimer?.Cancel(); _timeoutTimer = _context.Time.AddDelayTimer(Timeout, OnTimeout); //心跳Type默认就是0 var bytes = SessionBufferPool.Acquire();//会在Remote那里回收 bytes[0] = NetDefine.MAGIC; bytes[1] = 0; _context.Session.Send(bytes, 0, 2); } private void OnTimeout() { if (!_started) return; if (_isTimeout) { Log.Warn("Heartbeat 心跳第二次超时"); Stop(); _listener?.OnTimeout(); } else { Log.Warn("Heartbeat 心跳第一次超时"); _isTimeout = true; Send(0); //再次尝试发送 } } //private void AddObservable() //{ // _sessionNode.AddListener(EventDefine.SESSION_RECV_ERROR, OnError); // _sessionNode.AddListener(EventDefine.SESSION_SEND_ERROR, OnError); // _sessionNode.AddListener(EventDefine.SESSION_REMOTE_CLOSED, OnError); // _sessionNode.AddListener(EventDefine.SESSION_PUSH_RECVED, OnError); // _sessionNode.AddListener(EventDefine.SESSION_RESPONSE_RECVED, OnError); //} //private void RemoveObservable() //{ // _sessionNode.RemoveListener(EventDefine.SESSION_RECV_ERROR, OnError); // _sessionNode.RemoveListener(EventDefine.SESSION_SEND_ERROR, OnError); // _sessionNode.RemoveListener(EventDefine.SESSION_REMOTE_CLOSED, OnError); // _sessionNode.RemoveListener(EventDefine.SESSION_PUSH_RECVED, OnError); // _sessionNode.RemoveListener(EventDefine.SESSION_RESPONSE_RECVED, OnError); //} //private void OnError(int eventId, object args) //{ // switch (eventId) // { // case EventDefine.SESSION_RECV_ERROR: // case EventDefine.SESSION_SEND_ERROR: // case EventDefine.SESSION_REMOTE_CLOSED: // Stop(); // break; // case EventDefine.SESSION_PUSH_RECVED: // case EventDefine.SESSION_RESPONSE_RECVED: // timeoutTimer?.Cancel(); // break; // } //} void IDisposable.Dispose() { Stop(); _listener = null; _context = null; } } }