StreamWriteWithTimeout类(NetworkComms 2.3.1源码了解和学习)
networkComms.net2.3.1开源版本,基于gpl V3协议。因为不能公开3.x版本的源码,所以基于此版本进行学习。3.X版本进行了诸多改进和Bug修复,使用方法上两者相差不大。 /*请注意使用以下代码,需遵循GplV3协议*/ using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading; namespace DPSBase { /// <summary> /// 写入流的包装类---带超时判断 主要用来防止数据流写入时的死锁 /// </summary> public static class StreamWriteWithTimeout { /// 把数据流 SendBuffer中数据写入到目标数据流中,每次写入的大小为 WriteBufferSize,当数据写入超时时,抛出异常。 /// SendBuffer 包含数据的缓冲区 /// bufferLength 要写入的字节数 /// destinationStream 目标数据流 /// writeBufferSize 每次成功写入的字节数 /// timeoutMSPerKBWrite 每KB写入的最长时间 /// 允许写入的最小时间 /// 返回: 每KB数据写入的平均时间 public static double Write(byte[] sendBuffer, int bufferLength, Stream destinationStream, int writeBufferSize, double timeoutMSPerKBWrite, int minTimeoutMS) { if (sendBuffer == null) throw new ArgumentNullException("sendBuffer"); if (destinationStream == null) throw new ArgumentNullException("destinationStream"); int totalBytesCompleted = 0; Exception innerException = null; //信号 --无 AutoResetEvent writeCompletedEvent = new AutoResetEvent(false); //写入等待时间: (1) minTimeOutMS 写入最小时间 (2)每KB超时时间*KB数量 ====》取其中较大的值 //如果数据大小小于缓冲区的大小,则数据长度为数据大小 否则为 数据缓冲区大小 int writeWaitTimeMS = Math.Max(minTimeoutMS, (int)(((bufferLength < writeBufferSize ? bufferLength : writeBufferSize) / 1024.0) * timeoutMSPerKBWrite)); System.Diagnostics.Stopwatch timerTotal = new System.Diagnostics.Stopwatch(); timerTotal.Start(); do { //如果 (字节数-已经完成数) 如果小于 写入缓冲区 (1) 则等于 (字节数-已经完成数) (2) 否则,则等于缓冲区数 int writeCountBytes = (bufferLength - totalBytesCompleted < writeBufferSize ? bufferLength - totalBytesCompleted : writeBufferSize); //(1) 要写入的数据 (2)totalBytesCompleted 从此位置开始写入 (3) writeCountBytes 写入的数量 destinationStream.BeginWrite(sendBuffer, totalBytesCompleted, writeCountBytes, new AsyncCallback((state)=> { try { //(4)写入完成后 destinationStream.EndWrite(state); } catch (Exception ex) { innerException = ex; } //(5):写入完成后,发信号 writeCompletedEvent.Set(); }), null); //有交警 必须有信号才能通行 交警等待 writeWaitTimeMS时间 if (!writeCompletedEvent.WaitOne(writeWaitTimeMS)) { //#if !WINDOWS_PHONE // using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess()) // AppendStringToLogFile("WriteWithTimeLog_" + process.Id, "Write timed out after " + writeWaitTimeMS.ToString() + "ms, while writing " + writeCountBytes + " bytes."); //#endif throw new TimeoutException("Write timed out after " + writeWaitTimeMS.ToString() + "ms"); } if (innerException != null) throw innerException; //完成的写入数 +=此次的写入数 totalBytesCompleted += writeCountBytes; } while (totalBytesCompleted < bufferLength); //如果已经写入的数据< 数据数 则继续循环 写入数据 否则跳出循环 timerTotal.Stop(); double writeTimePerKBms = 0; if (bufferLength > 0) //计算出每KB数据的写入时间 writeTimePerKBms = (double)timerTotal.ElapsedMilliseconds * 1024.0 / bufferLength; //#if !WINDOWS_PHONE // using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess()) // AppendStringToLogFile("WriteWithTimeLog_" + process.Id, "Write succeded using " + writeWaitTimeMS.ToString() + "ms, using buffer of " + sendBuffer.Length.ToString() + " bytes, average write time was " + writeTimePerKBms.ToString("0.00") + " ms/KB. timeoutMSPerKBWrite was " + timeoutMSPerKBWrite); //#endif //返回每KB数据的写入时间 return writeTimePerKBms; } /// 此方法与上面的方法的区别是,每次写入一个缓冲区的数据后,都要从输入流中读取指定缓冲区大小的数据 public static double Write(Stream inputStream, long inputStart, long inputLength, Stream destinationStream, int writeBufferSize, double timeoutMSPerKBWrite, int minTimeoutMS) { if (inputStream == null) throw new ArgumentException("inputStream"); if (destinationStream == null) throw new ArgumentException("destinationStream"); //定位好输入流的指定位置 inputStream.Seek(inputStart, SeekOrigin.Begin); long totalBytesCompleted = 0; Exception innerException = null; AutoResetEvent writeCompletedEvent = new AutoResetEvent(false); //数据的缓冲区 如果数据的长度小于要写入的缓冲区的大小 则(1): 数据缓冲区等于 数据的长度 否则(2)数据缓冲区等于 写入缓冲区的大小 byte[] sendBuffer = new byte[Math.Min(inputLength, writeBufferSize)]; //计算超时时间 int writeWaitTimeMS = Math.Max(minTimeoutMS, (int)((sendBuffer.Length / 1024.0) * timeoutMSPerKBWrite)); System.Diagnostics.Stopwatch timerTotal = new System.Diagnostics.Stopwatch(); timerTotal.Start(); do { //剩余数据数 ==总数据库 -已经完成数 long bytesRemaining = inputLength - totalBytesCompleted; //要读取的数据长度: 如果数据的缓冲区 大于 剩余的数据数 则等于 (1)剩余的数据数 (2)否则为缓冲区的大小 //writeCountBytes 已读取,要写入的数据长度 int writeCountBytes = inputStream.Read(sendBuffer, 0, (sendBuffer.Length > bytesRemaining ? (int)bytesRemaining : sendBuffer.Length)); if (writeCountBytes <= 0) break; if (!destinationStream.CanWrite) throw new Exception("Unable to write to provided destinationStream."); //写入到目标数据流中 destinationStream.BeginWrite(sendBuffer, 0, writeCountBytes, new AsyncCallback((state) => { try { //完成写入数据 完成一次写入 destinationStream.EndWrite(state); } catch (Exception ex) { innerException = ex; } //给信号 writeCompletedEvent.Set(); }), null); if (!writeCompletedEvent.WaitOne(writeWaitTimeMS)) { //#if !WINDOWS_PHONE // using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess()) // AppendStringToLogFile("WriteWithTimeLog_" + process.Id, "Write timed out after " + writeWaitTimeMS.ToString() + "ms, while writing " + writeCountBytes + " bytes."); //#endif throw new TimeoutException("Write timed out after " + writeWaitTimeMS.ToString() + "ms"); } if (innerException != null) throw innerException; //已经写入的总数 totalBytesCompleted += writeCountBytes; } while (totalBytesCompleted < inputLength); //如果已经写入的总数<数据库 继续执行循环 timerTotal.Stop(); double writeTimePerKBms = 0; if (inputLength > 0) writeTimePerKBms = (double)timerTotal.ElapsedMilliseconds * 1024.0 / inputLength; //#if !WINDOWS_PHONE // using (System.Diagnostics.Process process = System.Diagnostics.Process.GetCurrentProcess()) // AppendStringToLogFile("WriteWithTimeLog_" + process.Id, "Write succeded using " + writeWaitTimeMS.ToString() + "ms, using buffer of " + sendBuffer.Length.ToString() + " bytes, average write time was " + writeTimePerKBms.ToString("0.00") + " ms/KB. timeoutMSPerKBWrite was " + timeoutMSPerKBWrite); //#endif return writeTimePerKBms; }
//在英文网站上购买 九折折扣代码: NCDN_PRCLW
//淘宝正版销售 http://shop115882994.taobao.com/ 推广期间 八折优惠
/// <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) { 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); } } catch (Exception) { //If an error happens here, such as if the file is locked then we lucked out. } } } } http://www.cnblogs.com/networkcomms http://www.networkcoms.cn 编辑
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。