c#網路通訊架構networkcomms核心解析之四 心跳檢測

來源:互聯網
上載者:User

標籤:

在網路通訊程式中,心跳檢測是必不可少的,我們來看一下networkcomms中是如何?的

以networkcomms2.3.1為例:

在伺服器端,會有一個線程專門用來發送心跳訊息

代碼如下:

  protected static void TriggerConnectionKeepAliveThread()        {            lock (staticConnectionLocker)            {                if (!shutdownWorkerThreads && (connectionKeepAliveWorker == null || connectionKeepAliveWorker.ThreadState == ThreadState.Stopped))                {
//建立一個新的線程,專門負責心跳檢測 connectionKeepAliveWorker = new Thread(ConnectionKeepAliveWorker); connectionKeepAliveWorker.Name = "ConnectionKeepAliveWorker"; connectionKeepAliveWorker.Start(); } } }

相關方法:

  private static void ConnectionKeepAliveWorker()        {            if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Connection keep alive polling thread has started.");            DateTime lastPollCheck = DateTime.Now;            while (!shutdownWorkerThreads)            {                try                {                    //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(5000);                    else                        workedThreadSignal.WaitOne(100);                    //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)                {                    NetworkComms.LogError(ex, "ConnectionKeepAlivePollError");                }            }        }
  /// <summary>        /// Polls all existing connections based on ConnectionKeepAlivePollIntervalSecs value. Serverside connections are polled slightly earlier than client side to help reduce potential congestion.        /// </summary>        /// <param name="returnImmediately"></param>        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();            int remainingConnectionCount = allConnections.Count;#if WINDOWS_PHONE            QueueItemPriority nullSendPriority = QueueItemPriority.High;#else            QueueItemPriority nullSendPriority = QueueItemPriority.AboveNormal;#endif            ManualResetEvent allConnectionsComplete = new ManualResetEvent(false);            for (int i = 0; i < allConnections.Count; i++)            {                //We don‘t send null packets to unconnected udp connections                UDPConnection asUDP = allConnections[i] as UDPConnection;                if (asUDP != null && asUDP.UDPOptions == UDPOptions.None)                {                    if (Interlocked.Decrement(ref remainingConnectionCount) == 0)                        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 upto 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                        {                            if (Interlocked.Decrement(ref remainingConnectionCount) == 0)                                allConnectionsComplete.Set();                        }                    }), null);                }            }            //Max wait is 1 seconds per connection            if (!returnImmediately && allConnections.Count > 0)            {                if (!allConnectionsComplete.WaitOne(allConnections.Count * 2500))                    //This timeout should not really happen so we are going to log an error if it does                    NetworkComms.LogError(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");            }        }
   protected override void SendNullPacket()        {            try            {                //Only once the connection has been established do we send null packets                if (ConnectionInfo.ConnectionState == ConnectionState.Established)                {                    //Multiple threads may try to send packets at the same time so we need this lock to prevent a thread cross talk                    lock (sendLocker)                    {                        if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Sending null packet to " + ConnectionInfo);                        //Send a single 0 byte                        double maxSendTimePerKB = double.MaxValue;                        if (!NetworkComms.DisableConnectionSendTimeouts)                        {                            if (SendTimesMSPerKBCache.Count > MinNumSendsBeforeConnectionSpecificSendTimeout)                                maxSendTimePerKB = Math.Max(MinimumMSPerKBSendTimeout, SendTimesMSPerKBCache.CalculateMean() + NumberOfStDeviationsForWriteTimeout * SendTimesMSPerKBCache.CalculateStdDeviation());                            else                                maxSendTimePerKB = DefaultMSPerKBSendTimeout;                        }#if WINDOWS_PHONE                        var stream = socket.OutputStream.AsStreamForWrite();                        StreamWriteWithTimeout.Write(new byte[] { 0 }, 1, stream, 1, maxSendTimePerKB, MinSendTimeoutMS);                        stream.Flush();#else                        StreamWriteWithTimeout.Write(new byte[] { 0 }, 1, tcpClientNetworkStream, 1, maxSendTimePerKB, MinSendTimeoutMS);#endif                        //Update the traffic time after we have written to netStream                        ConnectionInfo.UpdateLastTrafficTime();                    }                }                //If the connection is shutdown we should call close                if (ConnectionInfo.ConnectionState == ConnectionState.Shutdown) CloseConnection(false, -8);            }            catch (Exception)            {                CloseConnection(true, 19);            }        }
SendNullPacket()

 

在上面的方法中,我們可以看到在網路通訊的伺服器端和用戶端中,由於伺服器端設定的發送心跳訊息的時間小於用戶端發送心跳訊息,所以發送心跳訊息的工作主要由伺服器端來完成。

如果伺服器端超出常規時間沒有發送心跳訊息,用戶端才會開始發送。

 

http://www.cnblogs.com/networkcomms

c#網路通訊架構networkcomms核心解析之四 心跳檢測

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.