介绍开源的.net通信框架NetworkComms框架之五 心跳检测

时间:2023-03-01 10:13:50

原文网址: 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