介绍开源的.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 ...
随机推荐
- [ACM_模拟] POJ1068 Parencodings (两种括号编码转化 规律 模拟)
Description Let S = s1 s2...s2n be a well-formed string of parentheses. S can be encoded in two diff ...
- Winform文件下载之断点续传
在本系列的前两篇文章中,分别向大家介绍了用于完成下载任务的 WebClinet 和 WinINet 的基本用法和一些实用技巧. 今天来为大家讲述下载过程中最常遇到的断点续传问题. 首先明确一点,本文所 ...
- ./在Linux下是什么意思
在网上找的答案: . 在这里表示的是当前目录,就像 .. 表示上级目录一样. 这个 / 表示的是目录级别的分隔符,他之前的就是目录名,./aaa/ 表明的就是 . (也就是当前目录)下面的 aaa 目 ...
- js中setTimeout()的使用bug
今天用setTimeout()时,遇到一个奇怪的现象,通过多方面的查询,最终解决了问题,这是setTimeout()设计的时候存在的一点点bug. 代码的作用主要是在三秒后自动关闭本浏览器窗口: 代码 ...
- Atitit usrQBM1603短信验证码规范
Atitit usrQBM1603短信验证码规范 短信验证码扩展至短信服务和验证码服务1 主要方法1 参考模板1 短信验证码扩展至短信服务和验证码服务 主要方法 Line 27: public cla ...
- C#学习系列-out与ref的区别
参考:http://www.microsoftvirtualacademy.com/Content/ViewContent.aspx?et=9851&m=9839&ct=31056 如 ...
- fir.im Weekly - 这是一份强大的 SwiftGuide
大新闻!Apple 10 亿美元融资滴滴!库克大叔对中国 iOS 开发者表达了高度认可,同时也传出 iOS 10 将内置滴滴 App 的消息.想像下,某个加班的深夜飙完代码,最性感的事情莫过于:「Si ...
- PHP_01之PHP概述、数据、语法
1.定义:PHP Hypertext Preprocessor,超文本预处理器,服务器端脚本语言:2.环境:WAMP:Window+Apache+PHP+MySQL: LAMP:Linux+Apach ...
- 关于JavaScript闭包的小问题
怎么说,闭包大体也就是作用域的问题.闭包的一个用途是用于模块化,保护函数体内的私有变量,如: var foo = function(){ var _num = 1; var sayHello = fu ...
- 百度地图 api
首先在百度开发者中心申请ak 在页面head中引用必要的css样式和js脚本 <script type="text/javascript" src="http:// ...