原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
我们知道TCP连接建立之后,如果没有心跳检测,连接一会就断开了。NetworkComms框架本身已经完美实现了心跳检测,我们在使用的时候不用再关心这个问题。
NetworkComms通信框架中服务器端设定的发送心跳消息的时间小于客户端发送心跳消息,所以发送心跳消息的工作主要由服务器端来完成。
如果服务器端超出常规时间没有发送心跳消息,客户端才会开始发送。
相关实现代码:
ConnectionStatic方法中:
protected static void TriggerConnectionKeepAliveThread() { lock (staticConnectionLocker) { #if NETFX_CORE if (!shutdownWorkerThreads && (connectionKeepAliveWorker == null || connectionKeepAliveWorker.IsCompleted)) { connectionKeepAliveWorker = new Task(ConnectionKeepAliveWorker, TaskCreationOptions.LongRunning); connectionKeepAliveWorker.Start(); } #else if (!shutdownWorkerThreads && (connectionKeepAliveWorker == null || connectionKeepAliveWorker.ThreadState == ThreadState.Stopped)) { connectionKeepAliveWorker = new Thread(ConnectionKeepAliveWorker); connectionKeepAliveWorker.Name = "ConnectionKeepAliveWorker"; connectionKeepAliveWorker.IsBackground = true; connectionKeepAliveWorker.Start(); } #endif } }
private static void ConnectionKeepAliveWorker() { if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Connection keep alive polling thread has started."); DateTime lastPollCheck = DateTime.Now; while (!shutdownWorkerThreads) { try { #if NET2 //We have a short sleep here so that we can exit the thread fairly quickly if we need too if (ConnectionKeepAlivePollIntervalSecs == int.MaxValue) workedThreadSignal.WaitOne(, false); else workedThreadSignal.WaitOne(, false); #else //We have a short sleep here so that we can exit the thread fairly quickly if we need too if (ConnectionKeepAlivePollIntervalSecs == int.MaxValue) workedThreadSignal.WaitOne(); else workedThreadSignal.WaitOne(); #endif //Check for shutdown here if (shutdownWorkerThreads) break; //Any connections which we have not seen in the last poll interval get tested using a null packet if (ConnectionKeepAlivePollIntervalSecs < int.MaxValue && (DateTime.Now - lastPollCheck).TotalSeconds > (double)ConnectionKeepAlivePollIntervalSecs) { AllConnectionsSendNullPacketKeepAlive(); lastPollCheck = DateTime.Now; } } catch (Exception ex) { LogTools.LogException(ex, "ConnectionKeepAlivePollError"); } } }
private static void AllConnectionsSendNullPacketKeepAlive(bool returnImmediately = false) { if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Starting AllConnectionsSendNullPacketKeepAlive"); //Loop through all connections and test the alive state List<Connection> allConnections = NetworkComms.GetExistingConnection(ApplicationLayerProtocolStatus.Enabled); int remainingConnectionCount = allConnections.Count; QueueItemPriority nullSendPriority = QueueItemPriority.AboveNormal; ManualResetEvent allConnectionsComplete = new ManualResetEvent(false); ; i < allConnections.Count; i++) { //We don't send null packets to unconnected UDP connections UDPConnection asUDP = allConnections[i] as UDPConnection; if (asUDP != null && asUDP.ConnectionUDPOptions == UDPOptions.None) { ) allConnectionsComplete.Set(); continue; } else { int innerIndex = i; NetworkComms.CommsThreadPool.EnqueueItem(nullSendPriority, new WaitCallback((obj) => { try { //If the connection is server side we poll preferentially if (allConnections[innerIndex] != null) { if (allConnections[innerIndex].ConnectionInfo.ServerSide) { //We check the last incoming traffic time //In scenarios where the client is sending us lots of data there is no need to poll if ((DateTime.Now - allConnections[innerIndex].ConnectionInfo.LastTrafficTime).TotalSeconds > ConnectionKeepAlivePollIntervalSecs) allConnections[innerIndex].SendNullPacket(); } else { //If we are client side we wait up to an additional 3 seconds to do the poll //This means the server will probably beat us if ((DateTime.Now - allConnections[innerIndex].ConnectionInfo.LastTrafficTime).TotalSeconds > ConnectionKeepAlivePollIntervalSecs + 1.0 + (NetworkComms.randomGen.NextDouble() * 2.0)) allConnections[innerIndex].SendNullPacket(); } } } catch (Exception) { } finally { ) allConnectionsComplete.Set(); } }), null); } } //Max wait is 1 seconds per connection ) { #if NET2 , false)) #else )) #endif //This timeout should not really happen so we are going to log an error if it does //LogTools.LogException(new TimeoutException("Timeout after " + allConnections.Count.ToString() + " seconds waiting for null packet sends to finish. " + remainingConnectionCount.ToString() + " connection waits remain. This error indicates very high send load or a possible send deadlock."), "NullPacketKeepAliveTimeoutError"); if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Warn("Timeout after " + allConnections.Count.ToString() + " seconds waiting for null packet sends to finish. " + remainingConnectionCount.ToString() + " connection waits remain. This error indicates very high send load or a possible send deadlock."); } }
原文网址: http://www.cnblogs.com/csdev