介绍开源的.net通信框架NetworkComms框架 源码分析(十四)StreamTools
原文网址: http://www.cnblogs.com/csdev
Networkcomms 是一款C# 语言编写的TCP/UDP通信框架 作者是英国人 以前是收费的 目前作者已经开源 许可是:Apache License v2
开源地址是:https://github.com/MarcFletcher/NetworkComms.Net
数据流相关工具
public static class StreamTools
{
#region Static Stream Tools
/// <summary>
/// Write the provided sendbuffer to the destination stream in chunks of writeBufferSize. Throws exception if any write takes longer than timeoutPerByteWriteMS.
/// 把发送缓冲区中的数据写入目标数据流中 每次写入的大小为 writeBufferSize.
/// 如果写入的时间超过 timeoutPerByteWriteMS 将抛出异常
/// </summary>
/// <param name="sendBuffer">发送缓冲区Buffer containing data to write</param>
/// <param name="inputStart">开始位置 The start position in sendBuffer</param>
/// <param name="bufferLength">需要写入的字节的大小 The number of bytes to write</param>
/// <param name="destinationStream">目标数据流 The destination stream</param>
/// <param name="writeBufferSize">每次写入的缓冲区大小 The size in bytes of each successive write</param>
/// <param name="timeoutMSPerKBWrite">每KB写入的超时时间 The maximum time to allow for write to complete per KB</param>
/// <param name="minTimeoutMS">最小超时时间 The minimum time to allow for any sized write</param>
/// <returns>每KB数据的平均发送时间 The average time in milliseconds per KB written</returns>
public static double Write(byte[] sendBuffer, int inputStart, int bufferLength, Stream destinationStream, int writeBufferSize, double timeoutMSPerKBWrite, int minTimeoutMS)
{
if (sendBuffer == null) throw new ArgumentNullException("sendBuffer");
if (destinationStream == null) throw new ArgumentNullException("destinationStream");
using (MemoryStream ms = new MemoryStream(sendBuffer))
{
return Write(ms, inputStart, bufferLength, destinationStream, writeBufferSize, timeoutMSPerKBWrite, minTimeoutMS);
}
}
/// <summary>
/// Write the provided input stream to the destination stream in chunks of writeBufferSize. Throws exception if any write takes longer than timeoutPerByteWriteMS.
///把发送缓冲区中的数据写入目标数据流中 每次写入的大小为 writeBufferSize.
/// 如果写入的时间超过 timeoutPerByteWriteMS 将抛出异常
/// </summary>
/// <param name="inputStream">输入的数据流 Input stream containing data to send</param>
/// <param name="inputStart">输入数据流的开始位置 The start position in inputStream</param>
/// <param name="inputLength">需写入的数据的大小 The number of bytes to write</param>
/// <param name="destinationStream">目标数据流 The destination stream</param>
/// <param name="writeBufferSize">写入数据的缓冲区大小 The size in bytes of each successive write, recommended 8K</param>
/// <param name="timeoutMSPerKBWrite">每KB数据的超时时间 The maximum time to allow for write to complete per KB</param>
/// <param name="minTimeoutMS">最小超时时间 The minimum time to wait per write, this takes priority over other values.</param>
/// <returns>数据的平均发送时间 The average time in milliseconds per KB written</returns>
public static double Write(Stream inputStream, long inputStart, long inputLength, Stream destinationStream, int writeBufferSize, double timeoutMSPerKBWrite, int minTimeoutMS)
{
if (inputStream == null) throw new ArgumentNullException("source");
if (destinationStream == null) throw new ArgumentNullException("destination");
//Make sure we start in the right place
//确保我们开始于正确的位置
inputStream.Seek(inputStart, SeekOrigin.Begin);
;
long bytesRemaining = inputLength;
int writeWaitTimeMS = Math.Max(minTimeoutMS, (int)((writeBufferSize / 1024.0) * timeoutMSPerKBWrite));
System.Diagnostics.Stopwatch timerTotal = new System.Diagnostics.Stopwatch();
timerTotal.Start();
byte[] bufferA = new byte[writeBufferSize];
byte[] bufferB = new byte[writeBufferSize];
AutoResetEvent readCanStartSignal = new AutoResetEvent(true);
AutoResetEvent allDataWritten = new AutoResetEvent(false);
Exception innerException = null;
#if NETFX_CORE
Action readAction = null; Action<int> writeAction = null;
Stream input = inputStream;
Stream output = destinationStream;
readAction = new Action(async () =>
{
try
{
while (true) {
, (writeBufferSize > bytesRemaining ? (int)bytesRemaining : writeBufferSize));
#else
AsyncCallback readCompleted = null, writeCompleted = null;
readCompleted = new AsyncCallback((IAsyncResult ar) =>
{
try
{
var streams = ar.AsyncState as Stream[];
];
];
// input read asynchronously completed
//完成异步读取输入的数据
int bytesRead = input.EndRead(ar);
#endif
#if NET2
if (!readCanStartSignal.WaitOne(writeWaitTimeMS, false))
#else
if (!readCanStartSignal.WaitOne(writeWaitTimeMS))
#endif
innerException = new TimeoutException("Write timed out after " + writeWaitTimeMS.ToString() + "ms");
|| innerException != null)
{
allDataWritten.Set();
return;
}
var temp = bufferA;
bufferA = bufferB;
bufferB = temp;
// write asynchronously
//异步写入
#if NETFX_CORE
writeAction(bytesRead);
#else
output.BeginWrite(bufferB, , bytesRead, writeCompleted, streams);
#endif
//start the next read straight away
//开始下一阶段的读取
totalBytesCompleted += bytesRead;
bytesRemaining = inputLength - totalBytesCompleted;
#if NETFX_CORE
}
#else
input.BeginRead(bufferA, , (writeBufferSize > bytesRemaining ? (int)bytesRemaining : writeBufferSize), readCompleted, streams);
#endif
}
catch (Exception ex)
{
innerException = ex;
allDataWritten.Set();
return;
}
});
#if NETFX_CORE
writeAction = new Action<int>(async (bytesRead) =>
{
try
{
, bytesRead);
#else
writeCompleted = new AsyncCallback((IAsyncResult ar) =>
{
try
{
var streams = ar.AsyncState as Stream[];
];
];
try
{
output.EndWrite(ar);
}
catch (Exception ex)
{
innerException = ex;
}
#endif
readCanStartSignal.Set();
}
catch (Exception ex)
{
innerException = ex;
allDataWritten.Set();
return;
}
});
#if NETFX_CORE
readAction();
#else
inputStream.BeginRead(bufferA, , (writeBufferSize > bytesRemaining ? (int)bytesRemaining : writeBufferSize), readCompleted, new Stream[] { inputStream, destinationStream });
#endif
allDataWritten.WaitOne();
timerTotal.Stop();
if (innerException != null)
throw innerException;
;
)
writeTimePerKBms = (double)timerTotal.ElapsedMilliseconds * 1024.0 / inputLength;
return writeTimePerKBms;
}
/// <summary>
/// Write the provided input stream to the destination stream
/// 根据参数 把输入流中的数据写入到输出流中
/// </summary>
/// <param name="inputStream">输入流 Input stream containing data to send</param>
/// <param name="destinationStream">输出流 The destination stream</param>
/// <returns>每KB数据的平均发送时间 The average time in milliseconds per KB written</returns>
public static double Write(Stream inputStream, Stream destinationStream)
{
, inputStream.Length, destinationStream, , , int.MaxValue);
}
/// <summary>
/// Locker for LogError() which ensures thread safe saves.
/// 同步锁 用于确保线程安全
/// </summary>
static object errorLocker = new object();
/// <summary>
/// Appends the provided logString to end of fileName.txt. If the file does not exist it will be created.
/// 把日志写入到日志文件中
/// </summary>
/// <param name="fileName">文件名称 The filename to use. The extension .txt will be appended automatically</param>
/// <param name="logString">写入的信息 The string to append.</param>
static void AppendStringToLogFile(string fileName, string logString)
{
try
{
lock (errorLocker)
{
#if NETFX_CORE
string toWrite = DateTime.Now.Hour.ToString() + "." + DateTime.Now.Minute.ToString() + "." + DateTime.Now.Second.ToString() + "." + DateTime.Now.Millisecond.ToString() + " [" + Environment.CurrentManagedThreadId.ToString() + "] " + logString + Environment.NewLine;
Func<Task> writeTask = new Func<Task>(async () =>
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync(fileName + ".txt", CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, toWrite);
});
writeTask().Wait();
#else
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(fileName + ".txt", true))
sw.WriteLine(DateTime.Now.Hour.ToString() + "." + DateTime.Now.Minute.ToString() + "." + DateTime.Now.Second.ToString() + "." + DateTime.Now.Millisecond.ToString() + " [" + Thread.CurrentThread.ManagedThreadId.ToString() + "] " + logString);
#endif
}
}
catch (Exception)
{
//If an error happens here, such as if the file is locked then we lucked out.
//错误发生在这里,比如日志文件被锁定
}
}
/// <summary>
/// Return the MD5 hash of the provided memory stream as a string. Stream position will be equal to the length of stream on
/// return, this ensures the MD5 is consistent.
/// 返回参数中内存流的MD5哈希值
/// 流的位置与返回的流的长度相等
/// 这样确保md5 是一致的
/// </summary>
/// <param name="streamToMD5">数据流 The bytes which will be checksummed</param>
/// <param name="start">开始位置 The start position in the stream</param>
/// <param name="length">长度 The length in the stream to MD5</param>
/// <returns>生成的MD5字符型检验和 The MD5 checksum as a string</returns>
public static string MD5(Stream streamToMD5, long start, int length)
{
if (streamToMD5 == null) throw new ArgumentNullException("streamToMD5", "Provided Stream cannot be null.");
using (MemoryStream stream = new MemoryStream(length))
{
StreamTools.Write(streamToMD5, start, length, stream, , , );
return MD5(stream);
}
}
/// <summary>
/// Return the MD5 hash of the provided byte array as a string
/// 根据参数中的字节数组MD5哈希值
/// </summary>
/// <param name="bytesToMd5">字节数组 The bytes which will be checksummed</param>
/// <returns>返回的Md5值 The MD5 checksum as a string</returns>
public static string MD5(byte[] bytesToMd5)
{
if (bytesToMd5 == null) throw new ArgumentNullException("bytesToMd5", "Provided byte[] cannot be null.");
, bytesToMd5.Length, false))
return MD5(stream);
}
/// <summary>
/// Return the MD5 hash of the provided memory stream as a string. Stream position will be equal to the length of stream on
/// return, this ensures the MD5 is consistent.
/// 返回参数中内存流的MD5哈希值
/// 流的位置与返回的流的长度相等
/// 这样确保md5 是一致的
/// </summary>
/// <param name="streamToMD5">数据流 The bytes which will be checksummed</param>
/// <returns>返回的Md5哈希值 The MD5 checksum as a string</returns>
public static string MD5(Stream streamToMD5)
{
if (streamToMD5 == null) throw new ArgumentNullException("streamToMD5", "Provided Stream cannot be null.");
string resultStr;
#if NETFX_CORE
var alg = Windows.Security.Cryptography.Core.HashAlgorithmProvider.OpenAlgorithm(Windows.Security.Cryptography.Core.HashAlgorithmNames.Md5);
var buffer = (new Windows.Storage.Streams.DataReader(streamToMD5.AsInputStream())).ReadBuffer((uint)streamToMD5.Length);
var hashedData = alg.HashData(buffer);
resultStr = Windows.Security.Cryptography.CryptographicBuffer.EncodeToHexString(hashedData).Replace("-", "");
#else
using (System.Security.Cryptography.HashAlgorithm md5 =
#if WINDOWS_PHONE
new Tools.MD5Managed())
#else
System.Security.Cryptography.MD5.Create())
#endif
{
//If we don't ensure the position is consistent the MD5 changes
streamToMD5.Seek(, SeekOrigin.Begin);
resultStr = BitConverter.ToString(md5.ComputeHash(streamToMD5)).Replace("-", "");
}
#endif
return resultStr;
}
#endregion
介绍开源的.net通信框架NetworkComms框架 源码分析(十四)StreamTools的更多相关文章
- 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 ...
随机推荐
- 3、CC2541芯片中级教程-OSAL操作系统(ADC光敏电阻和修改串口波特率)
本文根据一周CC2541笔记汇总得来—— 适合概览和知识快速索引—— 全部链接: 中级教程-OSAL操作系统\OSAL操作系统-实验01 OSAL初探 [插入]SourceInsight-工程建立方法 ...
- MVVM架构~knockoutjs系列之扩展ajax验证~验证输入数据是否与后台数据相等
返回目录 在看这篇文章之前,你有必要先看我之前的文章,之前文章是将一个方法以参数的形式传给KO,然后返回一个真假值,去做验证,这类似于面向对象语言里的委托,在JS里我们叫它回调方法,本篇文章与前一文章 ...
- 手打的笔记,java语法中的输入输出,语句,及注释。
手打的笔记: () 内的则为注意事项或者提示 public static void main (String[] args) ******(用一个方法)****{ int i = 10; int j ...
- fir.im Weekly - 600个 Android 开源项目汇总
本期 Weekly 收集了一些热度资源,包含 Android.iOS 开发工具与源码分享,程序员也应该了解的产品运营.设计等 Tips ,希望对你有帮助. 600个Android开源项目汇总 勤劳的 ...
- apache多站点配置
apache多站点配置 临时需要个测试站,然后就到apache中配置vhosts,结果这货总是显示"拒绝了你的请求",找半天发现居然还要添加端口监听 vhosts.conf 添加v ...
- KlayGE 4.4中渲染的改进(三):高质量无限地形
转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2761 本系列的上一篇讲了DR中的一些改进.本篇开始将描述这个版本加入的新功能,高质量地形 ...
- OpenCascade Modeling Algorithms Fillets and Chamfers
Modeling Algorithms Fillets and Chamfers 造型算法——倒圆与倒角 eryar@163.com 一.倒圆Fillet Constructor 1. BRepFil ...
- timus_1007_bfs
图像编码 题目描述: 有这样一副图,它有黑白像素,黑像素的坐标在1-10之间.有很多种方法来编码这个图.例如下面的图: 一种表示方法是只描述黑像素,并按x坐标的增序描述,如果x相同,则按y的增序描述, ...
- [转载]UML时序图总结
前言 在我的工作中,用的最多的就是时序图了.可能由于工作的原因,我也是最喜欢画时序图了,很清楚,很明了,什么时候发送什么消息,到达什么状态,一下子就展示在你的脑海里,对于消息驱动的程序来说,是再好不过 ...
- Robot Framework自动化测试(六)--- robotremoteserver使用
robotremoteserver 是什么? Python Remote Server for Robot Framework 下载地址:https://pypi.python.org/pypi/ro ...