原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
Connection NetworkComms.Net中的连接基类 用户交互时使用的类 是TCPConnection和 UDPConnection的基类
/// <summary> /// Global connection base class for NetworkComms.Net. Most user interactions happen using a connection object. /// Extended by <see cref="TCPConnection"/> and <see cref="UDPConnection"/>. /// NetworkComms.Net中的连接基类 用户交互时使用的类 是TCPConnection和 UDPConnection的基类 /// </summary> #endif public abstract partial class Connection { static ManualResetEvent workedThreadSignal = new ManualResetEvent(false); static volatile bool shutdownWorkerThreads = false; static object staticConnectionLocker = new object(); #if NETFX_CORE static Task connectionKeepAliveWorker; #else static Thread connectionKeepAliveWorker; #endif /// <summary> /// Private static constructor which sets the connection defaults /// 私有静态构造函数用来设置连接的一个默认参数 /// </summary> static Connection() { ConnectionKeepAlivePollIntervalSecs = ; MaxNumSendTimes = ; MinNumSendsBeforeConnectionSpecificSendTimeout = ; MinSendTimeoutMS = ; MinimumMSPerKBSendTimeout = ; DefaultMSPerKBSendTimeout = ; NumberOfStDeviationsForWriteTimeout = ; } /// <summary> /// The minimum number of milliseconds to allow per KB before a write timeout may occur. Default is 20.0. /// 发送每KB数据所使用的毫秒数 超过将会抛出超时异常 默认20 /// </summary> public static double MinimumMSPerKBSendTimeout { get; set; } /// <summary> /// The maximum number of writes intervals to maintain. Default is 100. /// 写入间隔的最大值 默认100 /// </summary> public static int MaxNumSendTimes { get; set; } /// <summary> /// The minimum number of writes before the connection specific write timeouts will be used. Default is 4. /// 在连接超时前写入的最小数量 默认是4 /// </summary> public static int MinNumSendsBeforeConnectionSpecificSendTimeout { get; set; } /// <summary> /// The default milliseconds per KB write timeout before connection specific values become available. Default is 1000. See <see cref="MinNumSendsBeforeConnectionSpecificSendTimeout"/>. /// 每KB数据发送的超时时间 默认1000毫秒 /// </summary> public static int DefaultMSPerKBSendTimeout { get; set; } /// <summary> /// The minimum timeout for any sized send in milliseconds. Prevents timeouts when sending less than 1KB. Default is 2000. /// 最小发送超时时间 防止发送小于1kb数据时超时 /// </summary> public static int MinSendTimeoutMS { get; set; } /// <summary> /// The interval between keep alive polls of all connections. Set to int.MaxValue to disable keep alive poll /// 发送心跳检测的间隔时间 /// </summary> public static int ConnectionKeepAlivePollIntervalSecs { get; set; } /// <summary> /// The number of standard deviations from the mean to use for write timeouts. Default is 3.0. /// 平均使用写入超时的标准方差 默认3.0 /// </summary> public static double NumberOfStDeviationsForWriteTimeout { get; set; } /// <summary> /// Starts the connectionKeepAliveWorker thread if it is not already started /// 开始心跳检测线程 /// </summary> 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 } } /// <summary> /// A single static worker thread which keeps connections alive /// 一个单一的静态工作者线程用来进行心跳检测 /// </summary> 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"); } } } /// <summary> /// Polls all existing connections based on ConnectionKeepAlivePollIntervalSecs value. Server side connections are polled /// slightly earlier than client side to help reduce potential congestion. /// 给所有连接发送空数据包进行心跳检测 服务器端发送心跳检测的时间小于客户端 /// </summary> /// <param name="returnImmediately">If true runs as task and returns immediately.</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(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 //UDP连接上我们不发送空数据包 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 //每个连接最多等待1秒 ) { #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."); } } /// <summary> /// Shutdown any static connection components /// 关闭静态连接组件 /// </summary> /// <param name="threadShutdownTimeoutMS"></param> ) { try { StopListening(); } catch (Exception ex) { LogTools.LogException(ex, "CommsShutdownError"); } try { shutdownWorkerThreads = true; #if NETFX_CORE if (connectionKeepAliveWorker != null && !connectionKeepAliveWorker.Wait(threadShutdownTimeoutMS)) throw new CommsSetupShutdownException("Connection keep alive worker failed to shutdown"); #else if (connectionKeepAliveWorker != null && !connectionKeepAliveWorker.Join(threadShutdownTimeoutMS)) connectionKeepAliveWorker.Abort(); #endif } catch (Exception ex) { LogTools.LogException(ex, "CommsShutdownError"); } finally { shutdownWorkerThreads = false; workedThreadSignal.Reset(); } } }