介绍开源的.net通信框架NetworkComms框架 源码分析(十九 )ConnectionIncomingData
原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
用于处理接收到的二级制数据,生成相关的数据包,并进一步进行解析
namespace NetworkCommsDotNet.Connections
{
public abstract partial class Connection
{
/// <summary>
/// The <see cref="PacketBuilder"/> for this connection
/// 数据包创建器
/// </summary>
protected PacketBuilder packetBuilder;
/// <summary>
/// The total bytes read so far within dataBuffer
/// 已经读取的数据长度
/// </summary>
protected int totalBytesRead;
#if !NETFX_CORE
/// <summary>
/// The thread listening for incoming data should we be using synchronous methods.
/// 数据监听线程
/// </summary>
protected Thread incomingDataListenThread = null;
#endif
/// <summary>
/// True if async listen has started
/// 是否为异步监听
/// </summary>
protected bool asyncListenStarted = false;
/// <summary>
/// True if the async listen method is in a beginRead
/// 是否为同步监听
/// </summary>
protected volatile bool asyncListenerInRead = false;
/// <summary>
/// A connection specific method which triggers any requisites for accepting incoming data
/// 开始监听传入的数据
/// </summary>
protected abstract void StartIncomingDataListen();
/// <summary>
/// Attempts to use the data provided in packetBuilder to recreate something useful. If we don't have enough data
/// yet that value is set in packetBuilder.
/// 处理"数据包创建器"(packetBuilder)中已经接收的二进制数据
/// </summary>
/// <param name="packetBuilder">The <see cref="PacketBuilder"/> containing incoming cached data</param>
protected void IncomingPacketHandleHandOff(PacketBuilder packetBuilder)
{
;
try
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... checking for completed packet with " + packetBuilder.TotalBytesCached.ToString() + " bytes read.");
)
throw new Exception("Executing IncomingPacketHandleHandOff when no packets exist in packetbuilder.");
//Loop until we are finished with this packetBuilder
//循环 直到我们完成对此packetBuilder上数据的处理
while (true)
{
//If we have ended up with a null packet at the front, probably due to some form of concatenation we can pull it off here
//It is possible we have concatenation of several null packets along with real data so we loop until the firstByte is greater than 0
//如果收到的数据的第一个字节的内容是0 则一般为心跳检测消息 删除之就行
)
{
#region Ignore Null Packet
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandleHandOff() from " + ConnectionInfo + ", loop index - " + loopCounter.ToString());
packetBuilder.ClearNTopBytes();
//Reset the expected bytes to 0 so that the next check starts from scratch
//重新设置 期待的字节数
packetBuilder.TotalBytesExpected = ;
//If we have run out of data completely then we can return immediately
//如果packetBuilder中只有一个字节 没有更多的数据 则可以返回了
) return;
#endregion
}
else
{
;
PacketHeader topPacketHeader;
#region Set topPacketHeader
if (ConnectionInfo.ApplicationLayerProtocol == ApplicationLayerProtocolStatus.Enabled)
{
//First determine the expected size of a header packet
//数据包包头的长度 =第一个字节的内容 +1 (这个加1是加上第一个字节的长度)
packetHeaderSize = packetBuilder.FirstByte() + ;
//Do we have enough data to build a header?
//如果我们没有足够的数据来创建数据包包头
if (packetBuilder.TotalBytesCached < packetHeaderSize)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... require " + packetHeaderSize + " bytes for packet header, only " + packetBuilder.TotalBytesCached + " bytes cached.");
//Set the expected number of bytes and then return
// 设定packetBuilder中期待的数据位数据包包头的大小
packetBuilder.TotalBytesExpected = packetHeaderSize;
return;
}
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... deserializing header using " + packetHeaderSize + " bytes, " + packetBuilder.TotalBytesCached + " bytes cached.");
//We have enough for a header
//有足够的数据 解析出数据包包头
, packetHeaderSize - ))
topPacketHeader = new PacketHeader(headerStream, NetworkComms.InternalFixedSendReceiveOptions);
}
else
topPacketHeader = new PacketHeader(Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged), packetBuilder.TotalBytesCached);
#endregion
//Idiot test
if (topPacketHeader.PacketType == null)
throw new SerialisationException("packetType value in packetHeader should never be null");
//We can now use the header to establish if we have enough payload data
//First case is when we have not yet received enough data
//如果packetBuilder中已经接收的数据 小于 (包头的长度+数据包的长度)
if (packetBuilder.TotalBytesCached < packetHeaderSize + topPacketHeader.TotalPayloadSize)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... more data required for complete packet payload. Expecting " + (packetHeaderSize + topPacketHeader.TotalPayloadSize).ToString() + " total packet bytes.");
//Set the expected number of bytes and then return
//设定packetBuilder中期待的字节数
packetBuilder.TotalBytesExpected = packetHeaderSize + topPacketHeader.TotalPayloadSize;
return;
}
//Second case is we have enough data
//此处 我们已经有足够的数据解析出数据包
else if (packetBuilder.TotalBytesCached >= packetHeaderSize + topPacketHeader.TotalPayloadSize)
{
#region Handle Packet
//We can either have exactly the right amount or even more than we were expecting
//We may have too much data if we are sending high quantities and the packets have been concatenated
//packetBuilder中已经接收的数据,可能比我们预期的数据还要多 这没有关系 我们先处理当期数据包所属的数据
SendReceiveOptions incomingPacketSendReceiveOptions = IncomingPacketSendReceiveOptions(topPacketHeader);
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Debug("Received packet of type '" + topPacketHeader.PacketType + "' from " + ConnectionInfo + ", containing " + packetHeaderSize.ToString() + " header bytes and " + topPacketHeader.TotalPayloadSize.ToString() + " payload bytes.");
bool isReservedPacketType = (topPacketHeader.PacketType != Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.Unmanaged) &&
NetworkComms.ReservedPacketTypeNames.ContainsKey(topPacketHeader.PacketType));
//Get the packet sequence number if logging
//获取数据包的顺序号
string packetSeqNumStr = "";
if (NetworkComms.LoggingEnabled)
packetSeqNumStr = (topPacketHeader.ContainsOption(PacketHeaderLongItems.PacketSequenceNumber) ? ". pSeq#-" + topPacketHeader.GetOption(PacketHeaderLongItems.PacketSequenceNumber).ToString() + "." : "");
//Only reserved packet types get completed inline by default
//如果数据包为通信框架保留类型 在当前线程直接处理
if (isReservedPacketType)
{
#if WINDOWS_PHONE || NETFX_CORE
QueueItemPriority priority = QueueItemPriority.Normal;
#else
QueueItemPriority priority = (QueueItemPriority)Thread.CurrentThread.Priority;
#endif
PriorityQueueItem item = new PriorityQueueItem(priority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.TotalPayloadSize), incomingPacketSendReceiveOptions);
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr);
NetworkComms.CompleteIncomingItemTask(item);
}
else
{
QueueItemPriority itemPriority = (incomingPacketSendReceiveOptions.Options.ContainsKey("ReceiveHandlePriority") ? (QueueItemPriority)Enum.Parse(typeof(QueueItemPriority), incomingPacketSendReceiveOptions.Options["ReceiveHandlePriority"]) : QueueItemPriority.Normal);
PriorityQueueItem item = new PriorityQueueItem(itemPriority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.TotalPayloadSize), incomingPacketSendReceiveOptions);
//QueueItemPriority.Highest is the only priority that is executed inline
//只有优先级为最高级的数据包 在当前线程进行处理
if (itemPriority == QueueItemPriority.Highest)
{
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' with priority HIGHEST inline. Loop index - " + loopCounter.ToString() + packetSeqNumStr);
NetworkComms.CompleteIncomingItemTask(item);
}
else
{
#if NETFX_CORE
NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item);
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ") with priority " + itemPriority.ToString() + ". Loop index=" + loopCounter.ToString() + packetSeqNumStr);
#else
int threadId = NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item);
? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + packetSeqNumStr);
#endif
}
}
//We clear the bytes we have just handed off
//从packetBuilder中删除我们已经处理过的数据
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Trace("Removing " + (packetHeaderSize + topPacketHeader.TotalPayloadSize).ToString() + " bytes from incoming packet builder from connection with " + ConnectionInfo +".");
packetBuilder.ClearNTopBytes(packetHeaderSize + topPacketHeader.TotalPayloadSize);
//Reset the expected bytes to 0 so that the next check starts from scratch
//重置 packetBuilder期待的数据为0
packetBuilder.TotalBytesExpected = ;
//If we have run out of data completely then we can return immediately
//如果packetBuilder中没有更多的数据需要处理 返回即可
) return;
#endregion
}
else
throw new CommunicationException("This should be impossible!");
}
loopCounter++;
}
}
catch (Exception ex)
{
//Any error, throw an exception.错误 抛出异常
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Fatal("A fatal exception occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. See log file for more information.");
if (this is IPConnection)
{
//Log the exception in DOS protection if enabled 如果启用了DOS攻击防御 进行相关记录
if (IPConnection.DOSProtection.Enabled && ConnectionInfo.RemoteEndPoint.GetType() == typeof(IPEndPoint))
IPConnection.DOSProtection.LogMalformedData(ConnectionInfo.RemoteIPEndPoint.Address);
}
LogTools.LogException(ex, "CommsError", "A fatal exception occurred in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. Loop counter " + loopCounter.ToString() + ". Packet builder contained " + packetBuilder.TotalBytesCached + " total cached bytes.");
CloseConnection();
}
}
/// <summary>
/// Handle an incoming CheckSumFailResend packet type
/// 处理检测和失败需要重发的数据
/// </summary>
/// <param name="packetDataSection"></param>
internal void CheckSumFailResendHandler(MemoryStream packetDataSection)
{
//If we have been asked to resend a packet then we just go through the list and resend it.
//如果我们被要求重新发送数据包 我们就通过列表重发相关数据。
SentPacket packetToReSend;
lock (sentPacketsLocker)
{
string checkSumRequested = NetworkComms.InternalFixedSendReceiveOptions.DataSerializer.DeserialiseDataObject<string>(packetDataSection,
NetworkComms.InternalFixedSendReceiveOptions.DataProcessors, NetworkComms.InternalFixedSendReceiveOptions.Options);
if (sentPackets.ContainsKey(checkSumRequested))
packetToReSend = sentPackets[checkSumRequested];
else
throw new CheckSumException("There was no packet sent with a matching check sum");
}
//If we have already tried resending the packet 10 times something has gone horribly wrong
//如果重发超过10此 抛出异常
) throw new CheckSumException("Packet sent resulted in a catastrophic checksum check exception.");
if (NetworkComms.LoggingEnabled) NetworkComms.Logger.Warn(" ... resending packet due to MD5 mismatch.");
//Increment send count and then resend
//增加重发的次数 并进行重发
packetToReSend.IncrementSendCount();
SendPacket<object>(packetToReSend.Packet);
}
}
}
介绍开源的.net通信框架NetworkComms框架 源码分析(十九 )ConnectionIncomingData的更多相关文章
- 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 ...
随机推荐
- 由ASP.NET所谓前台调用后台、后台调用前台想到HTTP——理论篇
工作两年多了,我会经常尝试给公司小伙伴儿们解决一些问题,几个月下来我发现初入公司的小朋友最爱问的问题就三个 1. 我想前台调用后台的XXX方法怎么弄啊? 2. 我想后台调用前台的XXX JavaScr ...
- CSS media queries
最近在做一些页面打印时的特殊处理接触到了media queries,想系统学习一下,在MOZILLA DEVELOPER NETWORK看到一篇文章讲的很不错,结合自己的使用总结一下. CSS2/me ...
- Java用来进行批量文件重命名,批量提取特定类型文件
原因: 因为在网上下载视频教程,有的名字特别长,一般都是机构或者网站的宣传,不方便直接看到视频的简介,所以做了下面的第一个功能. 因为老师发的课件中,文件夹太多,想把docx都放在同一个文件夹下面,一 ...
- js定时器的时间最小值-setTimeout、setInterval
HTML5标准规定 setTimeout的最短时间间隔是4毫秒: setInterval的最短间隔时间是10毫秒,也就是说,小于10毫秒的时间间隔会被调整到10毫秒 书和MDC 在John Resig ...
- C++中如何定义类和对象?
在C++语言中,对象的类型被称为类,类代表了某一批对象的共性和特征. 类是对象的抽象,而对象是类的具体实例.如同C中的结构体一样,我们要先定义一个结构体,再使用结构体去定义一个变量.同一个结构体可以定 ...
- ASP.NET MVC中使用FluentValidation验证实体
1.FluentValidation介绍 FluentValidation是与ASP.NET DataAnnotataion Attribute验证实体不同的数据验证组件,提供了将实体与验证分离开来的 ...
- Oracle 11g系列:函数与存储过程
1.函数 Oracle中的函数分为两类:系统函数和自定义行数.对于自定义函数,函数的传入参数可以没有,如果有,一定要明确其数据类型.函数传入参数不能在函数内部进行修改.函数必须有返回值,并且返回值必须 ...
- Introduction of Open CASCADE Foundation Classes
Open CASCADE Foundation Classes Open CASCADE基础类 eryar@163.com 一.简介 1. 基础类概述 Foundation Classes Overv ...
- Android线程机制——AsyncTask
对于Android为什么要使用多线程,因为从Android4.0之后,谷歌规定了网络操作不允许放在主线程中执行,由此就有了多线程的机制,有个JAVA学习经验的朋友一定知道多线程指的是什么,简单来讲就是 ...
- Java多线程系列--“JUC原子类”01之 框架
根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类. 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: AtomicIn ...