void _CheckHeartBeat(ref DaemonParameter daemonParameter) { if (!daemonParameter.daemonObject.SupportHeartBeat) { return; } // 连接器状态是连接上的,也没有处于重连过程中,那么可以检查心跳和发送心跳 if (daemonParameter.isConnected && !daemonParameter.isReconnecting && daemonParameter.daemonObject.state.state == EConnectorState.ExpectConnected) { // 只有发送过心跳了,并且还没有收到心跳反馈,才需要检查心跳反馈 if (daemonParameter.lastHeartBeatTime > 0 && daemonParameter.lastHeartBeatReturnTime <= daemonParameter.lastHeartBeatTime) { if (DateTimeUtil.NowMillisecond - daemonParameter.lastHeartBeatTime >= daemonParameter.daemonObject.HeartBeatReturnTimeout) { // 心跳超时,认为连接已经断开 _ProcessDisconnectUnexpected(ref daemonParameter); } } // 再次检查连接器状态,如果一切正常,那么就可以检查并发送心跳 if (daemonParameter.isConnected && !daemonParameter.isReconnecting && daemonParameter.daemonObject.state.state == EConnectorState.ExpectConnected) { if (DateTimeUtil.NowMillisecond - daemonParameter.lastHeartBeatTime >= daemonParameter.daemonObject.HeartBeatInterval) { // 发送心跳,并记录心跳发送时间 byte[] heartBeatPack = ProtocolDefine.ComposeHeartBeat(1); daemonParameter.daemonObject.Send(heartBeatPack, 0, heartBeatPack.Length); daemonParameter.lastHeartBeatTime = DateTimeUtil.NowMillisecond; } } } }
void _CheckDaemonObjectStateExpectConnected(ref DaemonParameter daemonParameter) { if (daemonParameter.daemonObject.state.IsDisconnected()) { // 如果连接器上一次检测时是连接上的,但是现在连接断开了,那么认为连接器刚刚断开连接 _ProcessDisconnected(ref daemonParameter); } }
void _CheckSendData(ref DaemonParameter daemonParameter) { if (daemonParameter.isConnected && !daemonParameter.isReconnecting && daemonParameter.daemonObject.state.state == EConnectorState.ExpectConnected && !daemonParameter.daemonObject.state.isSending) { // 连接器维持连接状态下,如果当前不忙碌,就立刻执行发送,将缓存的发送数据发送出去 _SendData(ref daemonParameter); } }
public void Init(IConnector connector, DaemonParameter initParam) { this.connector = connector; connected = connector.State == EConnectorState.ExpectConnected; sendHeartBeat = initParam.sendHeartBeat; heartBeatInterval = initParam.heartBeatInterval; autoReconnect = initParam.autoReconnect; autoReconnectRetryMax = initParam.autoReconnectRetryMax; autoReconnectRetryInterval = initParam.autoReconnectRetryInterval; eventHandler = initParam.eventHandler; }
void _CheckDaemonObjectState(ref DaemonParameter daemonParameter) { if (!daemonParameter.isConnected) { // 如果上一次检查时连接器状态是断开状态 _CheckDaemonObjectStateExpectDisconnected(ref daemonParameter); } else { // 如果上一次检查时连接器状态是连接状态 _CheckDaemonObjectStateExpectConnected(ref daemonParameter); } }
void _ProcessDisconnected(ref DaemonParameter daemonParameter) { daemonParameter.isConnected = false; if (!daemonParameter.isReconnecting) { // 非重连的情况下,触发断开连接成功的回调(重连状况下,不触发回调而是进入等待重连流程) if (daemonParameter.daemonObject.EventHandler != null) { daemonParameter.daemonObject.EventHandler.OnDisconnected(daemonParameter.daemonObject); } } daemonParameter.lastHeartBeatTime = 0; daemonParameter.lastHeartBeatReturnTime = 0; }
protected virtual void _ReceiveData(ref DaemonParameter daemonParameter) { StateObject s = daemonParameter.daemonObject.state; if (!s.IsAvailableForReceiveAndSend()) { if (EventHandler != null) { EventHandler.OnDataReceiveFailed(this, "连接器状态错误,无法接收网络数据,当前状态:" + s.state); } return; } if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("开始接收"); } try { s.isReceiving = true; if (s.workSocket != null) { s.workSocket.BeginReceive(s.receiveBuffer, 0, s.receiveBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), s); } } catch (ObjectDisposedException) { // Socket被关闭了,常见于网络连接丢失,或者连接器主动断开,此异常不需要转抛 s.isReceiving = false; if (EventHandler != null) { EventHandler.OnDataReceiveFailed(this, "接收数据失败,连接已被关闭"); } } catch (Exception ex) { // 接收失败的情况下,只将标识正在接收的标识位翻转,然后转抛异常 if (LogUtil.ShowException != null) { LogUtil.ShowException(new Exception("接收数据失败", ex)); } if (EventHandler != null) { EventHandler.OnDataReceiveFailed(this, "接收数据失败 " + ex.Message); } s.isReceiving = false; } }
void _CheckReceiveData(ref DaemonParameter daemonParameter) { if (!daemonParameter.daemonObject.state.isReceiving) { // 连接器不在接收状态,那么将当前buffer中已经接收到的数据进行处理 _ProcessReceivedData(ref daemonParameter); if (daemonParameter.isConnected && !daemonParameter.isReconnecting && daemonParameter.daemonObject.state.state == EConnectorState.ExpectConnected && daemonParameter.daemonObject.state.HasDataAvailable) { // 如果当前处于连接状态,而且网络通道里有数据等待接收,就再次发起接收 _ReceiveData(ref daemonParameter); } } }
// 守护线程的线程体 void DaemonProcedure(object param) { Connector daemonObject = param as Connector; if (daemonObject == null) { return; } if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("守护线程开始工作"); } DaemonParameter daemonParameter = new DaemonParameter { daemonObject = daemonObject, isConnected = daemonObject.state.state == EConnectorState.ExpectConnected, isReconnecting = false, autoReconnectRetryCount = 0, autoReconnectLastTime = 0, lastHeartBeatTime = 0, lastHeartBeatReturnTime = 0, }; while (!daemonObject.released) { // 守护线程该干的活 if (daemonObject.state != null) { _CheckHeartBeat(ref daemonParameter); _CheckDaemonObjectState(ref daemonParameter); _CheckSendData(ref daemonParameter); _CheckReceiveData(ref daemonParameter); } Thread.Sleep(daemonLoopInterval); //daemonObject.daemonSuspend.WaitOne(); // 如果信号被置为无信号状态,那么守护线程阻塞,直到恢复信号 } if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("守护线程退出"); } }
public void DaemonIt(IConnector connector, DaemonParameter daemonParam) { for (int i = 0; i < connectorsUnderWatchList.Count; ++i) { WatchObject tmp = connectorsUnderWatchList[i]; if (tmp != null && tmp.connector == connector) { if (LogUtil.ShowWarning != null) { LogUtil.ShowWarning("这个connector已经处于守护之下,不能重复添加"); } return; } } WatchObject wo = GetWatchObjectFromPool(); wo.Init(connector, daemonParam); connectorsUnderWatchList.Add(wo); }
void _TryReconnect(ref DaemonParameter daemonParameter) { if (daemonParameter.autoReconnectRetryCount >= daemonParameter.daemonObject.ReconnectMaxRetry) { // 已经超过最大重试次数,退出重连流程 daemonParameter.isReconnecting = false; // 触发重连失败的回调 if (daemonParameter.daemonObject.EventHandler != null) { daemonParameter.daemonObject.EventHandler.OnReconnectFailed(daemonParameter.daemonObject, "已达最大重试次数"); } } else if (DateTimeUtil.NowMillisecond - daemonParameter.autoReconnectLastTime > daemonParameter.daemonObject.ReconnectRetryTimeout) { // 重试超时已到,发起新一次的重连,并记录这一次重连的时间,重试次数加1 daemonParameter.autoReconnectLastTime = DateTimeUtil.NowMillisecond; ++daemonParameter.autoReconnectRetryCount; daemonParameter.daemonObject.Connect(); } }
void _ProcessDisconnectUnexpected(ref DaemonParameter daemonParameter) { // 触发意外断开回调 if (daemonParameter.daemonObject.EventHandler != null) { daemonParameter.daemonObject.EventHandler.OnConnectionLost(daemonParameter.daemonObject); } // 如果需要重连,标记重连 if (daemonParameter.daemonObject.SupportAutoReconnect) { daemonParameter.isReconnecting = true; // 重置参数 daemonParameter.autoReconnectRetryCount = 0; daemonParameter.autoReconnectLastTime = DateTimeUtil.NowMillisecond; // 注意,这里将上一次重连时间设置为当前时间,可以让重连流程在发现连接断开时等待一个重连间隔然后再重新连接,而不是一发现断开立刻重连 } daemonParameter.isConnected = false; // 主动断开连接,以便标志位状态同步 daemonParameter.daemonObject.Disconnect(); daemonParameter.lastHeartBeatTime = 0; daemonParameter.lastHeartBeatReturnTime = 0; }
void _ProcessConnected(ref DaemonParameter daemonParameter) { daemonParameter.isConnected = true; if (!daemonParameter.isReconnecting) { // 非重连的情况下,触发连接成功回调 if (daemonParameter.daemonObject.EventHandler != null) { daemonParameter.daemonObject.EventHandler.OnConnected(daemonParameter.daemonObject); } } else { // 重连状况下,触发重连成功回调,并退出重连流程 daemonParameter.isReconnecting = false; if (daemonParameter.daemonObject.EventHandler != null) { daemonParameter.daemonObject.EventHandler.OnReconnected(daemonParameter.daemonObject); } } }
void _CheckDaemonObjectStateExpectDisconnected(ref DaemonParameter daemonParameter) { if (daemonParameter.daemonObject.state.state == EConnectorState.ExpectHasIpAddress) { // 如果连接器已经解析好了IP地址,但是没有连接上,也没有在等待连接,那么认为连接器处在刚刚解析完域名等待调用连接的状态,调用连接 daemonParameter.daemonObject.Connect(); } else if (daemonParameter.daemonObject.state.state == EConnectorState.ExpectConnected) { // 如果连接器上一次检测时还没有连接上,但是现在已经连接上了,那么认为连接器刚刚连接成功 _ProcessConnected(ref daemonParameter); } else if (daemonParameter.daemonObject.state.IsDisconnected()) { // 连接器处于断开状态,并且已进入重连流程,那么按照参数指定的周期尝试连接 if (daemonParameter.isReconnecting) { _TryReconnect(ref daemonParameter); } } }
protected virtual void _SendData(ref DaemonParameter daemonParameter) { StateObject s = daemonParameter.daemonObject.state; if (!s.IsAvailableForReceiveAndSend()) { if (EventHandler != null) { EventHandler.OnDataSendFailed(daemonParameter.daemonObject, "连接器状态错误,无法接收网络数据,当前状态:" + s.state); } return; } // 没有缓存数据,放弃发送 if (s.sendCache == null || s.sendCache.IsEmpty) { return; } if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("开始发送缓存数据"); } if (s.sendBuffer == null) { if (EventHandler != null) { EventHandler.OnDataSendFailed(this, "发送数据失败,发送缓存没有初始化"); } return; } // 一次最多取出sendBuffer能够容纳的数据量 int sendBytes = Math.Min(s.sendBuffer.Length, s.sendCache.Length); if (!s.sendCache.TryPull(sendBytes, ref s.sendBuffer)) { s.sendCache.Clear(); if (EventHandler != null) { EventHandler.OnDataSendFailed(this, "发送数据失败,获取缓存的发送数据失败"); } return; } try { s.isSending = true; if (s.workSocket != null) { s.workSocket.BeginSend(s.sendBuffer, 0, sendBytes, SocketFlags.None, new AsyncCallback(SendCallback), s); } } catch (ObjectDisposedException) { // Socket被关闭了,常见于网络连接丢失,或者连接器主动断开,此异常不需要转抛 s.isSending = false; if (EventHandler != null) { EventHandler.OnDataSendFailed(this, "发送数据失败,连接已被关闭"); } } catch (Exception ex) { // 发送失败的情况下,只将标识正在发送的标识位翻转,然后转抛异常 if (LogUtil.ShowException != null) { LogUtil.ShowException(new Exception("发送数据失败", ex)); } if (EventHandler != null) { EventHandler.OnDataSendFailed(this, "发送数据失败 " + ex.Message); } s.isSending = false; } }
void _ProcessReceivedData(ref DaemonParameter daemonParameter) { RingBuffer <byte> dataBuffer = daemonParameter.daemonObject.receiveCache; while (!dataBuffer.IsEmpty) { // 拆包,按完整消息返回给Handler // 寻找魔数 if (dataBuffer.DiscardToFirstIndexOf(0xC8, 0xEF)) { byte headLength = 0; if (dataBuffer.Length >= 3) { // 找到了魔数,而且数据长度足够解析出消息头长度 // 解析出消息头长度 dataBuffer.Peek(2, out headLength); } else { // 消息接收长度还不够,继续接收 if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("消息头没收全,继续接收1"); } break; } // 进一步解析出整个消息头 if (headLength > 0 && dataBuffer.Length >= headLength) { if (headLength < ProtocolDefine.minimalHeadLength) { // 万一消息头长度不满足协议定义的最小长度,说明收到了一条非本系统能够处理的协议,抛弃(直接抛弃协议头即可,协议体会自然在下一个循环里被抛弃掉) dataBuffer.Discard(headLength); if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("收到的消息头不满足系统定义的最小消息头长度,抛弃"); } continue; } // 解析出了消息头长度,而且数据长度足够解析出整个消息头 // 解析出消息头里的必要数据 byte token; dataBuffer.Peek(5, out token); // 获得心跳标识位 bool heartBeat = (token & ProtocolDefine.heartBeatMask) != 0; /* * // 获得单向消息标识位 * bool oneWay = (token & ProtocolDefine.oneWayMask) != 0; * // 获得响应消息标识位 * bool response = (token & ProtocolDefine.responseMask) != 0; * // 获得加密标识位 * bool encrypt = (token & ProtocolDefine.encryptMask) != 0; * // 获得加密方式 * int encryptType = (token & ProtocolDefine.encryptTypeMask) >> ProtocolDefine.encryptTypeBitRightOffset; * // 获得压缩标识位 * bool compress = (token & ProtocolDefine.compressMask) != 0; * // 获得拆分标识位 * bool split = (token & ProtocolDefine.splitMask) != 0; */ // 如果是心跳消息,那么记录下收到的时间,抛弃消息头(心跳消息没有消息体,所以抛弃消息头就抛弃了整条心跳消息) if (heartBeat) { daemonParameter.lastHeartBeatReturnTime = DateTimeUtil.NowMillisecond; dataBuffer.Discard(headLength); continue; } // @TODO: 处理拆分的包,要将不完整的包临时放入一个为超大包准备的缓存,直到所有拆开的包体都收到了再合并成完整的包 byte[] bodyLengthBytes = new byte[2]; dataBuffer.Peek(10, out bodyLengthBytes[0]); dataBuffer.Peek(11, out bodyLengthBytes[1]); short bodyLength = BitConverterEx.GetShort(bodyLengthBytes, 0, true); if (dataBuffer.Length >= (headLength + bodyLength)) { // 数据长度满足协议头和协议体,即完整消息已经接收到了 byte[] msgBytes = new byte[headLength + bodyLength]; if (dataBuffer.TryPull(msgBytes.Length, ref msgBytes) && daemonParameter.daemonObject.DataHandler != null) { daemonParameter.daemonObject.DataHandler.OnDataReceived(daemonParameter.daemonObject, msgBytes); } } else { // 消息接收长度还不够,继续接收 if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("消息体没收全,继续接收"); } break; } } else { // 消息接收长度还不够,继续接收 if (LogUtil.ShowDebug != null) { LogUtil.ShowDebug("消息头没收全,继续接收2"); } break; } } else { dataBuffer.DiscardAll(); } } }