介绍开源的.net通信框架NetworkComms框架 源码分析(十六 ) ConnectionStatic
原文网址: 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(); } } }
介绍开源的.net通信框架NetworkComms框架 源码分析(十六 ) ConnectionStatic的更多相关文章
- DotNetty网络通信框架学习之源码分析
DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...
- 深入理解分布式调度框架TBSchedule及源码分析
简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...
- 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)
1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...
- 设计模式(二十一)——解释器模式(Spring 框架中SpelExpressionParser源码分析)
1 四则运算问题 通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输入表达式的形式,比如 a+b+c-d+e, 要求表达式的字母不能重复 2) 在分别输入 a ,b, c, ...
- $Django cbv源码分析 djangorestframework框架之APIView源码分析
1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...
- ④NuPlayer播放框架之Renderer源码分析
[时间:2016-11] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,渲染器,render] 0 导读 之前我们分析了NuPlayer的实现代码,本文将重点聚 ...
- ⑤NuPlayer播放框架之GenericSource源码分析
[时间:2017-01] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,GenericSource] 0 导读 GenericSource是NuPlayer:: ...
- ③NuPlayer播放框架之类NuPlayer源码分析
[时间:2016-10] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架] 0 引言 差不多一个月了,继续分析AOSP的播放框架的源码.这次我们需要深入分析的是N ...
- Laravel开发:Laravel框架门面Facade源码分析
前言 这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facades(读音:/fəˈsäd/ )为应用程序的服务容器中可用的类提供了一个「静态」接口.Lara ...
- Android 应用框架层 SQLite 源码分析
概述 Android 在应用框架层为开发者提供了 SQLite 相关操作接口,其归属于android.database.sqlite包底下,主要包含SQLiteProgram, SQLiteDat ...
随机推荐
- 什么是P3O?
P3O(Portfolio, Programme and Project Offices)项目组合.项目群和项目办公室资格认证. 是由英国商务部 OGC 于2008年10月28日发布的最新的最佳实践指 ...
- WebApi系列~实际项目中如何使用HttpClient向web api发异步Get和Post请求并且参数于具体实体类型
回到目录 本讲比较实际,在WEB端有一个Index和Create方法,用来从web api显示实体列表数据和向api插入实体对象,这就是以往的网站,只不过是把数据持久化过程放到了web pai上面,它 ...
- SDN跟网络虚拟化的完美结合
SDN跟网络虚拟化的完美结合 之前说过,所谓的“SDN最适合的领域是数据中心”的说法,笔者认为更准确的说法应该是SDN最适合的领域是数据中心中的网络虚拟化应用.为什么说SDN 非常适合用在网络虚拟化中 ...
- salesforce 零基础学习(三十六)通过Process Builder以及Apex代码实现锁定记录( Lock Record)
上一篇内容是通过Process Builder和Approval Processes实现锁定记录的功能,有的时候,往往锁定一条记录需要很多的限制条件,如果通过Approval Processes的条件 ...
- Struts2中Action取得表单数据的几种方法
Struts2中Action取得表单数据的几种方法 Struts2中Action获得表单数据的几种方法struts2 Action获取表单传值 1.通过属性驱动式JSP: <form act ...
- TSql Output 用法
第一部分:TSql Output 关键字有两种应用场景 1,作为存储过程的参数类型,从存储过程中返回数据 2,返回受 INSERT.UPDATE.DELETE 或 MERGE 语句影响的各行中的信息, ...
- javase基础复习攻略《八》
进入第八篇,我们开始讨论JAVA的IO初步.在JAVA程序中,对数据的输入\输出操作以"流"(stream)方式进行,J2SDK提供了各种各样的"流"类,用于获 ...
- 在IIS中部署ASP.NET 5应用程序遭遇的问题
用VS2015中创建了一个非常简单的ASP.NET5程序: 在Startup.cs中只输入一行代码: using System; using Microsoft.AspNet.Builder; usi ...
- 邻接表有向图(二)之 C++详解
本章是通过C++实现邻接表有向图. 目录 1. 邻接表有向图的介绍 2. 邻接表有向图的代码说明 3. 邻接表有向图的完整源码 转载请注明出处:http://www.cnblogs.com/skywa ...
- 使用bokeh-scala进行数据可视化
目录 前言 bokeh简介及胡扯 bokeh-scala基本代码 我的封装 总结 一.前言 最近在使用spark集群以及geotrellis框架(相关文章见http://www.cnbl ...