/// <summary> /// 以指定的发送规则发送数据到指定的网络流,数据来自输入流“inputStream”。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="inputStream">数据输入流。</param> /// <param name="sleep">发送数据间隔时间。</param> /// <param name="dataSize">每次发送数据包大小。</param> /// <param name="firstDataSize">首次发送数据包大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>实际发送的数据大小。</returns> public static long WriteDataToNetwork(System.Net.Sockets.NetworkStream networkStream, System.IO.Stream inputStream, System.TimeSpan sleep, int dataSize, int firstDataSize, TransferPositionChangedHandler transferSizeChanged) { //if (!NetworkStream.CanWrite) //{ // throw new System.Exception("网络文件流不支持写入操作。"); //} //this.OutputLog("[IP=" + RemoteClient.RemoteIP.ToString() + ":" + RemoteClient.RemotePort.ToString() + "] 开始传送文件:" + FileName); //if (!networkStream.CanWrite) //{ // return; //} if (inputStream.Length < firstDataSize) { firstDataSize = System.Convert.ToInt32(inputStream.Length); } if (inputStream.Length < dataSize) { dataSize = System.Convert.ToInt32(inputStream.Length); } int bufferLength = dataSize > firstDataSize ? dataSize : firstDataSize; byte[] buffer = new byte[bufferLength]; //if (!networkStream.CanWrite) //{ // return; //} //try //{ #region 开始写入数据。 long tLen = 0; //long currentSize = inputStream.Position; int len = inputStream.Read(buffer, 0, firstDataSize); while (len != 0) { //if (!networkStream.CanWrite) //{ // break; //} networkStream.Write(buffer, 0, len); tLen += len; //currentSize += len; if (transferSizeChanged != null) { TransferPositionChangedEventArgs e = new TransferPositionChangedEventArgs(inputStream.Position); transferSizeChanged(e); if (e.AbortTransfer) { break; } } if (sleep > System.TimeSpan.Zero) { //if (!networkStream.CanWrite) //{ // break; //} System.Threading.Thread.Sleep(sleep);//控制每隔多长时间发送一次数据。 } //if (!networkStream.CanWrite) //{ // break; //} len = inputStream.Read(buffer, 0, bufferLength); } #endregion //} //catch (System.Threading.ThreadAbortException taex) //{ // //this.OutputLog(taex.ToString()); //} //catch (System.IO.IOException ioex) //{ // /*此处 catch 用于截获下面的因属于正常的下载文件完成 IE 客户端先断开连接引发的异常: // System.IO.IOException: 无法将数据写入传输连接: 远程主机强迫关闭了一个现有的连接。。 ---> System.Net.Sockets.SocketException: 远程主机强迫关闭了一个现有的连接。 // 在 System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) // 在 System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size) // --- 内部异常堆栈跟踪的结尾 --- // 在 System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size) // 在 IEFileServer.Form1.SendFileToNetwork(String FileName, NetworkStream NetworkStream) 位置 D:\Documents and Settings\桌面\IEFileServer\IEFileServer\Form1.cs:行号 157 // */ // //this.OutputLog(ioex.ToString()); //} //catch (System.ObjectDisposedException odex) //{ // //this.OutputLog(odex.ToString()); //} return(tLen); }
/// <summary> /// 从指定的网络流中获取数据并写入到输出流中。支持断点续传。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="outputStream">数据输出流。</param> /// <param name="bufferSize">设置允许使用的缓冲区最大大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>指示数据传输是否成功。</returns> /// <remarks> /// 断点续传的前提条件为数据输出流参数 <paramref name="outputStream"/> 提供读写支持。 /// </remarks> public static bool ReadDataFromNetworkBreakPoint(System.Net.Sockets.NetworkStream networkStream, System.IO.Stream outputStream, int bufferSize, TransferPositionChangedHandler transferSizeChanged) { if (outputStream.CanRead == false || outputStream.CanWrite == false || outputStream.CanSeek == false) { throw new System.IO.IOException("无效的数据输出流参数“outputStream”,必须允许读取数据,写入数据和支持查找功能。"); } //System.Int32 EnableBreakLength = 1024 * 500; //指示断点上传启用条件。当待上传的数据总大小大于或等于此值时启用断点上传功能。断点检测是需要耗费时间的,所以此值不应该设置过小。 //System.Int32 BreakCheckLength = 1024 * 32; //指示断点识别数据块大小,为 0 时表示忽略断点检测。默认设置为32Kbyte。如果设置的值太小将造成识别错误,太大又将影响效率首次传输效率。 System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(networkStream, System.Text.Encoding.UTF8); System.IO.BinaryWriter binaryWriter = new System.IO.BinaryWriter(networkStream, System.Text.Encoding.UTF8); System.Int64 dataLength = binaryReader.ReadInt64(); //读取待上传数据总长度。 System.Int32 sha1Length = binaryReader.ReadInt32(); //读取SHA1码的长度。 byte[] clientSha1Datas = binaryReader.ReadBytes(sha1Length); //读取SHA1码。 #region 加载断点数据或生成新的断点数据。 if (dataLength == outputStream.Length) //如果存盘数据大小与待上传数据大小相同,则先确认文件上传是否已经完成。 { byte[] sha1 = Thinksea.General.GetSHA1(outputStream, 0); //获取SHA1码。 if (Thinksea.General.CompareArray(sha1, clientSha1Datas)) //如果 SHA1 码相同,则认为文件已经传输完成。 { binaryWriter.Write(dataLength); //写入发送数据的起始位置。 binaryWriter.Write(true); //告诉客户端文件传输已经完成。 return(true); } } BreakPoint breakPoint = LoadBreakPoint(outputStream); if (!(breakPoint != null && dataLength == breakPoint.TotalSize && Thinksea.General.CompareArray(breakPoint.SHA1, clientSha1Datas))) //只有文件大小相同,并且校验码相同,才启用断点续传。 { breakPoint = new BreakPoint(); breakPoint.TotalSize = dataLength; breakPoint.SHA1 = clientSha1Datas; breakPoint.LastTransferPosition = 0; SaveBreakPoint(outputStream, breakPoint); } #endregion //System.Int64 BreakCheckPosition = 0; //断点识别数据块起始位置。 //if (dataLength >= outputStream.Length && dataLength > EnableBreakLength && outputStream.Length > 0) //如果需要断点续传。 //{ // if (outputStream.Length < BreakCheckLength) BreakCheckLength = System.Convert.ToInt32(outputStream.Length); //根据已经传送的数据的长度调整校验数据块的大小。 // BreakCheckPosition = outputStream.Seek(0 - BreakCheckLength, System.IO.SeekOrigin.End); //定位断点检测起始位置。 // byte[] BreakCheckDatas = new byte[BreakCheckLength]; //断点识别数据块。 // outputStream.Read(BreakCheckDatas, 0, BreakCheckDatas.Length); //读取待校验的断点数据。 // binaryWriter.Write(BreakCheckPosition); //写入断点识别数据块起始位置。 // binaryWriter.Write(BreakCheckLength); //写入断点识别数据块大小。 // System.Int32 clientBreakDatasLength = binaryReader.ReadInt32(); //获取客户端将上传的断点识别数据块大小。 // byte[] clientBreakDatas = binaryReader.ReadBytes(clientBreakDatasLength); //获取客户端上传的断点识别数据块。 // if (Thinksea.General.CompareArray(BreakCheckDatas, clientBreakDatas)) //如果校验码相同,则启用断点续传。 // { // outputStream.Seek(0, System.IO.SeekOrigin.End); // } // else //如果校验码不同,则重新传送数据。 // { // outputStream.SetLength(0); //截断文件长度。 // outputStream.Seek(0, System.IO.SeekOrigin.Begin); // } //} //else //{ // BreakCheckPosition = 0; // BreakCheckLength = 0; // binaryWriter.Write(BreakCheckPosition); //写入断点识别数据块起始位置。 // binaryWriter.Write(BreakCheckLength); //写入断点识别数据块大小。 // outputStream.SetLength(0); //截断文件长度。 // outputStream.Seek(0, System.IO.SeekOrigin.Begin); //} binaryWriter.Write(breakPoint.LastTransferPosition); //通知客户端上传数据的起始位置。 if (breakPoint.LastTransferPosition < breakPoint.TotalSize) { outputStream.Seek(breakPoint.LastTransferPosition, System.IO.SeekOrigin.Begin); //设置写入数据起始位置。 int saveBreakPointSize = 1024 * 500; //保存断点信息的条件。 //Thinksea.FileTransfer.Lib.FileSystem.ReadDataFromNetwork(networkStream, (dataLength - outputStream.Position), outputStream, bufferSize, transferSizeChanged); //读取数据。 Thinksea.Net.DataTransfer.ReadDataFromNetwork(networkStream, (dataLength - outputStream.Position), outputStream, bufferSize, delegate(TransferPositionChangedEventArgs e) { if ((e.TransferPosition - breakPoint.LastTransferPosition) > saveBreakPointSize) //记录断点传输信息。 { breakPoint.LastTransferPosition = e.TransferPosition; SaveBreakPoint(outputStream, breakPoint); } if (transferSizeChanged != null) { transferSizeChanged(e); } }); //读取数据。 } bool success = false; if (outputStream.Position == breakPoint.TotalSize) { outputStream.SetLength(breakPoint.TotalSize); //清除断点数据。 #region 校验文件SHA1码是否相同。 byte[] serverSha1Datas = Thinksea.General.GetSHA1(outputStream, 0); //获取SHA1码。 if (Thinksea.General.CompareArray(clientSha1Datas, serverSha1Datas)) { success = true; } else { success = false; } #endregion } binaryWriter.Write(success); return(success); }
/// <summary> /// 以指定的文件名保存文件。支持断点续传。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="fileName">存盘文件名。</param> /// <param name="bufferSize">设置允许使用的缓冲区最大大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>指示数据传输是否成功。</returns> public static bool ReadFileFromNetworkBreakPoint(System.Net.Sockets.NetworkStream networkStream, string fileName, int bufferSize, TransferPositionChangedHandler transferSizeChanged) { System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None); try { return(ReadDataFromNetworkBreakPoint(networkStream, fs, bufferSize, transferSizeChanged)); } finally { fs.Close(); } }
/// <summary> /// 发送文件到指定的网络流。支持断点续传。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="fileName">文件名。</param> /// <param name="bufferSize">设置允许使用的缓冲区最大大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>指示数据传输是否成功。</returns> public static bool WriteFileToNetworkBreakPoint(System.Net.Sockets.NetworkStream networkStream, string fileName, int bufferSize, TransferPositionChangedHandler transferSizeChanged) { System.IO.FileStream fileStream = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read); try { return(WriteDataToNetworkBreakPoint(networkStream, fileStream, bufferSize, transferSizeChanged)); } //catch (System.Exception ioex) //{ // //this.OutputLog("[IP=" + RemoteClient.RemoteIP.ToString() + ":" + RemoteClient.RemotePort.ToString() + "] " + ioex.ToString()); //} finally { fileStream.Close(); } //this.OutputLog("[IP=" + RemoteClient.RemoteIP.ToString() + ":" + RemoteClient.RemotePort.ToString() + "] 传送文件完成:" + FileName); }
/// <summary> /// 发送数据到指定的网络流,数据来自输入流“inputStream”。支持断点续传。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="inputStream">数据输入流。</param> /// <param name="bufferSize">设置允许使用的缓冲区最大大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>指示数据传输是否成功。</returns> public static bool WriteDataToNetworkBreakPoint(System.Net.Sockets.NetworkStream networkStream, System.IO.Stream inputStream, int bufferSize, TransferPositionChangedHandler transferSizeChanged) { if (inputStream.CanRead == false || inputStream.CanSeek == false) // || inputStream.CanWrite == false { throw new System.IO.IOException("无效的数据输入流参数“inputStream”,必须允许读取数据和支持查找功能。"); //,写入数据 } System.IO.BinaryReader binaryReader = new System.IO.BinaryReader(networkStream, System.Text.Encoding.UTF8); System.IO.BinaryWriter binaryWriter = new System.IO.BinaryWriter(networkStream, System.Text.Encoding.UTF8); byte[] sha1Datas = Thinksea.General.GetSHA1(inputStream, 0); //获取SHA1码。 binaryWriter.Write(inputStream.Length); //写入待上传数据总长度。 binaryWriter.Write(sha1Datas.Length); //写入SHA1码的长度。 binaryWriter.Write(sha1Datas); //写入SHA1码。 //System.Int64 BreakCheckPosition = binaryReader.ReadInt64(); //读取客户端请求的断点识别数据块起始位置。 //System.Int32 BreakCheckLength = binaryReader.ReadInt32(); //读取客户端请求的断点识别数据块大小。 //if (BreakCheckLength > 0) //服务端请求上传断点识别数据块。 //{ // inputStream.Seek(BreakCheckPosition, System.IO.SeekOrigin.Begin); // byte[] BreakCheckDatas = new byte[BreakCheckLength]; //断点识别数据块。 // inputStream.Read(BreakCheckDatas, 0, BreakCheckDatas.Length); //读取待校验的断点数据。 // binaryWriter.Write(BreakCheckDatas.Length); //写入断点识别数据块大小。 // binaryWriter.Write(BreakCheckDatas); //写入断点识别数据块。 //} System.Int64 firstPosition = binaryReader.ReadInt64(); //获取开始上传的数据区起始位置。 if (firstPosition != inputStream.Length) { inputStream.Seek(firstPosition, System.IO.SeekOrigin.Begin); //设置读取数据位置。 Thinksea.Net.DataTransfer.WriteDataToNetwork(networkStream, inputStream, System.TimeSpan.Zero, bufferSize, bufferSize, transferSizeChanged); //发送数据。 } bool success = binaryReader.ReadBoolean(); //获取一个标识,指示文件上传是否成功。 return(success); }
/// <summary> /// 以指定的文件名保存文件。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="dataSize">指定要读取的数据大小。</param> /// <param name="fileName">存盘文件名。</param> /// <param name="bufferSize">设置允许使用的缓冲区最大大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>实际接收到的数据大小。</returns> public static long ReadFileFromNetwork(System.Net.Sockets.NetworkStream networkStream, long dataSize, string fileName, int bufferSize, TransferPositionChangedHandler transferSizeChanged) { System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None); try { return(ReadDataFromNetwork(networkStream, dataSize, fs, bufferSize, transferSizeChanged)); } finally { fs.Close(); } }
/// <summary> /// 从指定的网络流中获取数据并写入到输出流中。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="dataSize">指定要读取的数据最大大小。</param> /// <param name="outputStream">数据输出流。</param> /// <param name="bufferSize">设置允许使用的缓冲区最大大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>实际接收到的数据大小。</returns> public static long ReadDataFromNetwork(System.Net.Sockets.NetworkStream networkStream, long dataSize, System.IO.Stream outputStream, int bufferSize, TransferPositionChangedHandler transferSizeChanged) { long tLen = 0; byte[] buff = new byte[dataSize < bufferSize ? dataSize : bufferSize]; int len; int tRead; long rightSize; //剩余待传输的数据大小。 while (tLen < dataSize) // && networkStream.CanRead { rightSize = dataSize - tLen; tRead = System.Convert.ToInt32(rightSize > buff.Length ? buff.Length : rightSize); len = networkStream.Read(buff, 0, tRead); if (len == 0) { break; } outputStream.Write(buff, 0, len); tLen += len; if (transferSizeChanged != null) { TransferPositionChangedEventArgs e = new TransferPositionChangedEventArgs(outputStream.Position); transferSizeChanged(e); if (e.AbortTransfer) { break; } } } return(tLen); }
/// <summary> /// 发送数据到指定的网络流,数据来自输入流“inputStream”。 /// </summary> /// <param name="networkStream">与客户端连接的网络流。</param> /// <param name="inputStream">数据输入流。</param> /// <param name="bufferSize">设置允许使用的缓冲区最大大小。</param> /// <param name="transferSizeChanged">已经传输的数据大小更改时引发此事件。设置为 null 则忽略此参数。</param> /// <returns>实际发送的数据大小。</returns> public static long WriteDataToNetwork(System.Net.Sockets.NetworkStream networkStream, System.IO.Stream inputStream, int bufferSize, TransferPositionChangedHandler transferSizeChanged) { return(WriteDataToNetwork(networkStream, inputStream, System.TimeSpan.Zero, bufferSize, bufferSize, transferSizeChanged)); }