/// <summary> /// 标记一个任务项目状态,并检查任务是否完成 /// </summary> /// <param name="item">任务条目</param> /// <param name="state">状态</param> internal void MarkSendTaskItemState(FileTaskItem item, FileTaskItemState state) { if (item.State == state) { return; } if (state == FileTaskItemState.Finished || state == FileTaskItemState.Failure) { //退出传输状态 _activeSendItems.Remove(item); //强制更新状态 OnTaskItemProgressChanged(new FileTaskEventArgs(item.TaskInfo, item)); EnsureSendStateUpdateTimerState(); } item.State = state; OnTaskItemStateChanged(new FileTaskEventArgs(item.TaskInfo, item)); //是否需要更新状态 if (state == FileTaskItemState.Processing) { _activeSendItems.Add(item); EnsureSendStateUpdateTimerState(); } //如果是完成了,那就查找下这个任务是不是全部完成了,如果是的话,那就删掉任务 if (state == FileTaskItemState.Finished && item.TaskInfo.TaskList.Count(s => s.State != FileTaskItemState.Finished) == 0) { OnSendTaskFinished(new FileTaskEventArgs(item.TaskInfo)); //SendTask.Remove(item.TaskInfo.PackageID); } }
/// <summary> /// 开始接收文件任务 /// </summary> /// <param name="task">任务信息</param> /// <param name="item">任务项目</param> internal void PerformFileReceive(FileTaskInfo task, FileTaskItem item) { #if DEBUG System.Console.WriteLine("开始接受文件,尝试连接到 " + task.RemoteHost.HostSub.Ipv4Address.ToString()); #endif using (TcpClient client = new TcpClient()) { client.ReceiveTimeout = this.Config.ConnectionTimeout; client.SendTimeout = this.Config.ConnectionTimeout; try { client.Connect(task.RemoteHost.HostSub.Ipv4Address); } catch (Exception) { this.TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); if (client.Connected) { client.Close(); } return; } //检测是文件夹还是单个文件 if (item.IsFolder) { PerformFileReceive_Folder(client, task, item); } else { PerformFileReceive_File(client, task, item); } client.Close(); } }
//建立文件夹 bool ProcessDirCmd(FileTaskItem taskitem, ref string currentDirectory, Stack <string> pathStack, string folderName, bool updateTotal) { string newPath = Path.Combine(currentDirectory, folderName); try { Directory.CreateDirectory(newPath); } catch (Exception) { OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.CreateDirectory, newPath, taskitem.TaskInfo.RemoteHost)); TaskManager.MarkReceiveTaskItemState(taskitem, FileTaskItemState.Failure); return(false); } pathStack.Push(currentDirectory); currentDirectory = newPath; //更新进度 taskitem.FinishedFolderCount++; taskitem.FolderCount++; return(true); }
/// <summary> /// 将初始化的任务项目信息转换为JSON格式 /// </summary> /// <param name="item"></param> /// <returns></returns> public static string ToJsonInfo(this FileTaskItem item) { System.Text.StringBuilder sb = new StringBuilder(); sb.Append("{"); sb.AppendFormat("pkgid:\"{10}\",index:{0},curname:\"{11}\",filename:\"{1}\",filecount:{2},sended:{3},filesize:\"{4}\",sizesended:\"{5}\",percentage:{6},timeused:\"{7}\",timerest:\"{8}\",state:{9},speed:'',path:\"{12}\",isfolder:{13}", item.Index, Helper.ConvertJsString(item.Name), item.FileCount + item.FolderCount, item.FinishedFileCount + item.FinishedFolderCount, item.TotalSize.ToSizeDescription(), item.FinishedSize.ToSizeDescription(), 0, "--:--:--", "--:--:--", (int)item.State, item.TaskInfo.PackageID, Helper.ConvertJsString(item.CurrentName), Helper.ConvertJsString(item.FullPath), item.IsFolder ? 1 : 0 ); sb.Append("}"); return(sb.ToString()); }
/// <summary> /// 将初始化的任务项目信息转换为JSON格式 /// </summary> /// <param name="item"></param> /// <returns></returns> public static string ToJsonInfoWithProgress(this FileTaskItem item) { TimeSpan usedTime, restTime; double speed; int percentage; item.GetStateInfo(out usedTime, out restTime, out speed, out percentage); System.Text.StringBuilder sb = new StringBuilder(); sb.Append("{"); sb.AppendFormat("pkgid:\"{10}\",index:{0},curname:\"{12}\",filename:\"{1}\",filecount:{2},sended:{3},filesize:\"{4}\",sizesended:\"{5}\",percentage:{6},timeused:\"{7}\",timerest:\"{8}\",state:{9},speed:'{11}/S'", item.Index, Helper.ConvertJsString(item.Name), item.FileCount, item.FinishedFileCount, item.TotalSize.ToSizeDescription(), item.FinishedSize.ToSizeDescription(), percentage, string.Format("{0:00}:{1:00}:{2:00}", usedTime.Hours, usedTime.Minutes, usedTime.Seconds), string.Format("{0:00}:{1:00}:{2:00}", restTime.Hours, restTime.Minutes, restTime.Seconds), (int)item.State, item.TaskInfo.PackageID, ((ulong)speed).ToSizeDescription(), Helper.ConvertJsString(item.CurrentName) ); sb.Append("}"); return(sb.ToString()); }
/// <summary> /// 检测任务是否可以启动 /// </summary> void StartReceive() { if ((Config.TasksMultiReceiveCount > 0 && activeReceiveItems.Count >= Config.TasksMultiReceiveCount) || ReceiveTask.Count == 0) { return; } //RunCount-Fix thread limit issue int runCount = 0; foreach (FileTaskInfo t in ReceiveTask) { for (int j = 0; j < t.TaskList.Count; j++) { if (t.TaskList[j].State == FileTaskItemState.Scheduled) { FileTaskInfo task = t; FileTaskItem item = task.TaskList[j]; //开始传输 FileReceiveRequiredEventArgs e = new FileReceiveRequiredEventArgs(task, item); OnFileReceiveRequiring(e); if (!e.IsHandled) { OnFileReceiveRequired(e); } runCount++; //标记状态 MarkReceiveTaskItemState(item, FileTaskItemState.Initializing); if (activeReceiveItems.Count + runCount >= Config.TasksMultiReceiveCount && Config.TasksMultiReceiveCount > 0) { return; //超过数目则退出 } } } } }
/// <summary> /// 查询任务信息 /// </summary> /// <param name="packageId"></param> /// <param name="taskIndex"></param> /// <returns></returns> public FileTaskItem QuerySendTask(ulong packageId, int taskIndex, IPAddress addr) { if (!SendTask.ContainsKey(packageId) || taskIndex < 0) { return(null); } lock (SendTask) { FileTaskInfo fti = SendTask[packageId]; if (taskIndex >= fti.TaskList.Count || addr.ToString() != fti.RemoteHost.HostSub.Ipv4Address.Address.ToString()) { return(null); } else { FileTaskItem fi = fti.TaskList[taskIndex]; OnSendItemStart(new FileTaskEventArgs(fti, fi)); return(fi); } } }
/// <summary> /// 发送单个文件 /// </summary> /// <param name="client"></param> /// <param name="task"></param> /// <param name="item"></param> void PerformSendFile(TcpClient client, FileTaskInfo task, FileTaskItem item) { System.IO.FileStream fs = null; System.Net.Sockets.NetworkStream writer = null; try { writer = client.GetStream(); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return; } try { fs = new System.IO.FileStream(item.FullPath, System.IO.FileMode.Open, System.IO.FileAccess.Read); } catch (Exception) { if (writer != null) { writer.Close(); } TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.OpenFileToSend, item.FullPath, task.RemoteHost)); return; } using (fs) { //检测断点数据是否正确 if (item.CurrentFileTransfered < 0 || item.CurrentFileTransfered > (ulong)fs.Length) { item.CurrentFileTransfered = 0; } fs.Seek((long)item.CurrentFileTransfered, System.IO.SeekOrigin.Begin); //设置当前任务信息 item.CurrentFileSize = (ulong)fs.Length; TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Processing); item.StartTime = DateTime.Now; using (writer) { byte[] buffer = new byte[SendBuffer]; //缓冲区 while (item.CurrentFileTransfered < item.CurrentFileSize) { int bytesRead = fs.Read(buffer, 0, buffer.Length); try { writer.Write(buffer, 0, bytesRead); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); break; } //更新进度 item.CurrentFileTransfered += (ulong)bytesRead; item.FinishedSize += (ulong)bytesRead; } item.FinishedFileCount++; writer.Close(); } fs.Close(); //标记任务完成 if (item.State != FileTaskItemState.Failure) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Finished); } } }
//发送要求创建文件命令 bool PerformSendDirectory_SendCreateDirCommand(string path, NetworkStream stream, FileTaskInfo task, FileTaskItem item) { string strCMD = string.Format(":{0}:{1}:{2:x}:", string.IsNullOrEmpty(path) ? "." : System.IO.Path.GetFileName(path), 0, (int)(string.IsNullOrEmpty(path) ? Consts.Cmd_FileType_Option.RetParent : Consts.Cmd_FileType_Option.Dir)); byte[] bytes = null; if (task.RemoteHost.IsEnhancedContractEnabled) { bytes = System.Text.Encoding.Unicode.GetBytes(strCMD); } else { bytes = System.Text.Encoding.Default.GetBytes(strCMD); } if (!string.IsNullOrEmpty(path)) { item.FinishedFolderCount++; } try { stream.Write(System.Text.Encoding.Default.GetBytes((bytes.Length + 4).ToString("x4")), 0, 4); stream.Write(bytes, 0, bytes.Length); return(true); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } }
//发送文件夹中的文件 bool PerformSendDirectory_SendFilesInDirectory(string path, NetworkStream stream, FileTaskInfo task, FileTaskItem item, bool updateTotal) { System.IO.FileInfo fileinfo = new System.IO.FileInfo(path); if (!fileinfo.Exists) { OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.OpenFileToSend, path, task.RemoteHost)); } if (updateTotal) { item.TotalSize += (ulong)fileinfo.Length; } item.CurrentName = fileinfo.Name; item.CurrentFileTransfered = 0; item.CurrentFileSize = (ulong)fileinfo.Length; string strCMD = string.Format(":{0}:{1:x}:{2:x}:", fileinfo.Name, fileinfo.Length, (int)Consts.Cmd_FileType_Option.Regular); byte[] bytes = null; if (task.RemoteHost.IsEnhancedContractEnabled) { bytes = System.Text.Encoding.Unicode.GetBytes(strCMD); } else { bytes = System.Text.Encoding.Default.GetBytes(strCMD); } try { stream.Write(System.Text.Encoding.Default.GetBytes((bytes.Length + 4).ToString("x4")), 0, 4); stream.Write(bytes, 0, bytes.Length); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } //写入文件数据 FileStream reader = null; try { reader = fileinfo.OpenRead(); } catch (Exception) { OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.OpenFileToSend, path, task.RemoteHost)); TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } using (reader) { byte[] buffer = new byte[SendBuffer]; while (item.CurrentFileTransfered < (ulong)reader.Length) { int bytesRead = reader.Read(buffer, 0, buffer.Length); item.CurrentFileTransfered += (ulong)bytesRead; item.FinishedSize += (ulong)bytesRead; try { stream.Write(buffer, 0, bytesRead); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } } reader.Close(); } item.FinishedFileCount++; return(true); }
//发送文件夹 void PerformSendDirectory(TcpClient client, FileTaskInfo task, FileTaskItem item) { NetworkStream stream = null; try { stream = client.GetStream(); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return; } string currentDirectory = item.FullPath; //当前处理路径 Stack <string> directoryStack = new Stack <string>(); //文件夹栈 directoryStack.Push(""); bool needUpdateTotal = item.TotalSize == 0; //是否需要在发送的时候更新统计 TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Processing); item.StartTime = DateTime.Now; using (stream) { while (!string.IsNullOrEmpty(currentDirectory) || directoryStack.Count > 0) { if (!PerformSendDirectory_SendCreateDirCommand(currentDirectory, stream, task, item)) { return; } if (string.IsNullOrEmpty(currentDirectory)) { if (directoryStack.Count > 0) { currentDirectory = directoryStack.Pop(); //当前是空目录,则向上递归 } continue; } //扫描目录和文件 string[] files = null, directories = null; try { files = System.IO.Directory.GetFiles(currentDirectory); directories = System.IO.Directory.GetDirectories(currentDirectory); item.FolderCount += directories.Length; item.FileCount += files.Length; } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.QueryDirectory, item.FullPath, task.RemoteHost)); return; } //优先发送文件 foreach (var f in files) { if (!PerformSendDirectory_SendFilesInDirectory(f, stream, task, item, needUpdateTotal)) { return; } } //扫描子目录 if (directories.Length > 0) { directoryStack.Push(""); Array.ForEach(directories, s => { directoryStack.Push(s); }); currentDirectory = directoryStack.Pop(); //取出一个文件夹来发送 } else { //如果没有子目录,则置空当前目录,以命令流程向上返回 currentDirectory = null; } } if (item.State != FileTaskItemState.Failure) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Finished); } } }
protected virtual void OnFileSystemOperationError(FileSystemOperationErrorEventArgs e) { if (FileSystemOperationError == null) { return; } if (!IPMClient.NeedPostMessage) { FileSystemOperationError(this, e); } else { if (scpcFileSystemOperationError == null) { scpcFileSystemOperationError = (s) => { FileSystemOperationError(this, s as FileSystemOperationErrorEventArgs); } } ; IPMClient.SendASynchronizeMessage(scpcFileSystemOperationError, e); } } #region 发送文件事件 #endregion #endregion #region 发送文件-监听线程 /// <summary> /// 开始发送文件的监听线程 /// </summary> void StartListener() { System.Threading.ThreadStart ts = ListenForSendRequest; new System.Threading.Thread(ts) { IsBackground = true }.Start(); } /// <summary> /// 关闭监听线程 /// </summary> void CloseListener() { listener.Stop(); IsInitialized = false; } /// <summary> /// 监听函数 /// </summary> void ListenForSendRequest() { listener.Start(); while (IsInitialized) { try { TcpClient client = listener.AcceptTcpClient(); //开始发送线程 if (client != null) { System.Diagnostics.Debug.WriteLine("文件发送线程:已经接收到连接请求,远程IP:" + client.Client.RemoteEndPoint.ToString()); new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(PerformFileSend)) { IsBackground = true }.Start(client); } } catch (Exception) { if (!IsInitialized) { break; } } } } #endregion #region 发送文件-发送线程 /// <summary> /// 处理文件发送请求 /// </summary> /// <param name="client"></param> void PerformFileSend(object p) { System.Diagnostics.Debug.WriteLine("文件发送线程 [0x" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString("X4") + "] 已经启动"); using (TcpClient client = p as TcpClient) { byte[] buffer = new byte[400]; //接收或发送缓冲区 int bytesReceived = ReceiveByBuffer(client, buffer, buffer.Length); //第一步:接收文件传输命令 if (bytesReceived < 1) { return; //没收到数据 } Message request = ParseSendCommand(buffer, 0, bytesReceived); //试着解析命令 System.Diagnostics.Debug.WriteLineIf(request == null, "未能解析收到的请求,退出发送线程"); if (request == null) { return; } System.Diagnostics.Debug.WriteLine("已解析文件请求:" + request.NormalMsg.ToString()); //非法请求 //查找任务 string[] taskInfo = request.NormalMsg.Split(':'); ulong pid = 0ul; int tid = 0; FileTaskItem task = null; if (taskInfo.Length < 2 || !ulong.TryParse(taskInfo[0], System.Globalization.NumberStyles.AllowHexSpecifier, null, out pid) || !int.TryParse(taskInfo[1], System.Globalization.NumberStyles.AllowHexSpecifier, null, out tid) || (task = TaskManager.QuerySendTask(pid, tid, (client.Client.RemoteEndPoint as IPEndPoint).Address)) == null ) { return; } System.Diagnostics.Debug.WriteLine(string.Format("文件请求已经接纳,文件编号:0x{0:x8},文件索引:0x{1:x4}", pid, tid)); TaskManager.MarkSendTaskItemState(task, FileTaskItemState.Initializing); //准备发送 if (task.IsFolder) { PerformSendDirectory(client, task.TaskInfo, task); } else { //文件支持有限的断点续传 if (taskInfo.Length == 3) { ulong temp; if (ulong.TryParse(taskInfo[2], out temp)) { task.CurrentFileTransfered = temp; task.FileTransferedAtPast = temp; } System.Diagnostics.Debug.WriteLineIf(task.CurrentFileTransfered > 0, string.Format("断点模式,从 0x{0} 处开始续传", task.CurrentFileTransfered)); } PerformSendFile(client, task.TaskInfo, task); } client.Close(); } } //发送文件夹 void PerformSendDirectory(TcpClient client, FileTaskInfo task, FileTaskItem item) { NetworkStream stream = null; try { stream = client.GetStream(); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return; } string currentDirectory = item.FullPath; //当前处理路径 Stack <string> directoryStack = new Stack <string>(); //文件夹栈 directoryStack.Push(""); bool needUpdateTotal = item.TotalSize == 0; //是否需要在发送的时候更新统计 TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Processing); item.StartTime = DateTime.Now; using (stream) { while (!string.IsNullOrEmpty(currentDirectory) || directoryStack.Count > 0) { if (!PerformSendDirectory_SendCreateDirCommand(currentDirectory, stream, task, item)) { return; } if (string.IsNullOrEmpty(currentDirectory)) { if (directoryStack.Count > 0) { currentDirectory = directoryStack.Pop(); //当前是空目录,则向上递归 } continue; } //扫描目录和文件 string[] files = null, directories = null; try { files = System.IO.Directory.GetFiles(currentDirectory); directories = System.IO.Directory.GetDirectories(currentDirectory); item.FolderCount += directories.Length; item.FileCount += files.Length; } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.QueryDirectory, item.FullPath, task.RemoteHost)); return; } //优先发送文件 foreach (var f in files) { if (!PerformSendDirectory_SendFilesInDirectory(f, stream, task, item, needUpdateTotal)) { return; } } //扫描子目录 if (directories.Length > 0) { directoryStack.Push(""); Array.ForEach(directories, s => { directoryStack.Push(s); }); currentDirectory = directoryStack.Pop(); //取出一个文件夹来发送 } else { //如果没有子目录,则置空当前目录,以命令流程向上返回 currentDirectory = null; } } if (item.State != FileTaskItemState.Failure) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Finished); } } } //发送文件夹中的文件 bool PerformSendDirectory_SendFilesInDirectory(string path, NetworkStream stream, FileTaskInfo task, FileTaskItem item, bool updateTotal) { System.IO.FileInfo fileinfo = new System.IO.FileInfo(path); if (!fileinfo.Exists) { OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.OpenFileToSend, path, task.RemoteHost)); } if (updateTotal) { item.TotalSize += (ulong)fileinfo.Length; } item.CurrentName = fileinfo.Name; item.CurrentFileTransfered = 0; item.CurrentFileSize = (ulong)fileinfo.Length; string strCMD = string.Format(":{0}:{1:x}:{2:x}:", fileinfo.Name, fileinfo.Length, (int)Consts.Cmd_FileType_Option.Regular); byte[] bytes = null; if (task.RemoteHost.IsEnhancedContractEnabled) { bytes = System.Text.Encoding.Unicode.GetBytes(strCMD); } else { bytes = System.Text.Encoding.Default.GetBytes(strCMD); } try { stream.Write(System.Text.Encoding.Default.GetBytes((bytes.Length + 4).ToString("x4")), 0, 4); stream.Write(bytes, 0, bytes.Length); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } //写入文件数据 FileStream reader = null; try { reader = fileinfo.OpenRead(); } catch (Exception) { OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.OpenFileToSend, path, task.RemoteHost)); TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } using (reader) { byte[] buffer = new byte[SendBuffer]; while (item.CurrentFileTransfered < (ulong)reader.Length) { int bytesRead = reader.Read(buffer, 0, buffer.Length); item.CurrentFileTransfered += (ulong)bytesRead; item.FinishedSize += (ulong)bytesRead; try { stream.Write(buffer, 0, bytesRead); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } } reader.Close(); } item.FinishedFileCount++; return(true); } //发送要求创建文件命令 bool PerformSendDirectory_SendCreateDirCommand(string path, NetworkStream stream, FileTaskInfo task, FileTaskItem item) { string strCMD = string.Format(":{0}:{1}:{2:x}:", string.IsNullOrEmpty(path) ? "." : System.IO.Path.GetFileName(path), 0, (int)(string.IsNullOrEmpty(path) ? Consts.Cmd_FileType_Option.RetParent : Consts.Cmd_FileType_Option.Dir)); byte[] bytes = null; if (task.RemoteHost.IsEnhancedContractEnabled) { bytes = System.Text.Encoding.Unicode.GetBytes(strCMD); } else { bytes = System.Text.Encoding.Default.GetBytes(strCMD); } if (!string.IsNullOrEmpty(path)) { item.FinishedFolderCount++; } try { stream.Write(System.Text.Encoding.Default.GetBytes((bytes.Length + 4).ToString("x4")), 0, 4); stream.Write(bytes, 0, bytes.Length); return(true); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return(false); } } /// <summary> /// 发送单个文件 /// </summary> /// <param name="client"></param> /// <param name="task"></param> /// <param name="item"></param> void PerformSendFile(TcpClient client, FileTaskInfo task, FileTaskItem item) { System.IO.FileStream fs = null; System.Net.Sockets.NetworkStream writer = null; try { writer = client.GetStream(); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); return; } try { fs = new System.IO.FileStream(item.FullPath, System.IO.FileMode.Open, System.IO.FileAccess.Read); } catch (Exception) { if (writer != null) { writer.Close(); } TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.OpenFileToSend, item.FullPath, task.RemoteHost)); return; } using (fs) { //检测断点数据是否正确 if (item.CurrentFileTransfered < 0 || item.CurrentFileTransfered > (ulong)fs.Length) { item.CurrentFileTransfered = 0; } fs.Seek((long)item.CurrentFileTransfered, System.IO.SeekOrigin.Begin); //设置当前任务信息 item.CurrentFileSize = (ulong)fs.Length; TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Processing); item.StartTime = DateTime.Now; using (writer) { byte[] buffer = new byte[SendBuffer]; //缓冲区 while (item.CurrentFileTransfered < item.CurrentFileSize) { int bytesRead = fs.Read(buffer, 0, buffer.Length); try { writer.Write(buffer, 0, bytesRead); } catch (Exception) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Failure); break; } //更新进度 item.CurrentFileTransfered += (ulong)bytesRead; item.FinishedSize += (ulong)bytesRead; } item.FinishedFileCount++; writer.Close(); } fs.Close(); //标记任务完成 if (item.State != FileTaskItemState.Failure) { TaskManager.MarkSendTaskItemState(item, FileTaskItemState.Finished); } } } /// <summary> /// 解析请求的命令 /// </summary> /// <param name="buffer"></param> /// <param name="startIndex"></param> /// <param name="length"></param> /// <returns></returns> Message ParseSendCommand(byte[] buffer, int startIndex, int length) { byte[] cmdInfo = new byte[length]; Array.Copy(buffer, 0, cmdInfo, 0, length); if (!MessagePacker.Test(cmdInfo)) { return(null); } Message msg = MessagePacker.TryToTranslateMessage(cmdInfo, null); if (msg == null || (msg.Command != Consts.Commands.GetDirFiles && msg.Command != Consts.Commands.GetFileData)) { return(null); } return(msg); } /// <summary> /// 接收数据 /// </summary> /// <param name="buffer">缓冲区</param> /// <returns></returns> int ReceiveByBuffer(TcpClient client, byte[] buffer) { try { return(client.Client.Receive(buffer)); } catch (Exception) { //网络异常 return(-1); } } /// <summary> /// 接收数据 /// </summary> /// <param name="buffer">缓冲区</param> /// <returns></returns> int ReceiveByBuffer(TcpClient client, byte[] buffer, int length) { try { return(client.Client.Receive(buffer, length, SocketFlags.None)); } catch (Exception) { //网络异常 return(-1); } } /// <summary> /// 接收数据 /// </summary> /// <param name="buffer">缓冲区</param> /// <returns></returns> int ReceiveByBuffer(NetworkStream stream, byte[] buffer) { try { return(stream.Read(buffer, 0, buffer.Length)); } catch (Exception) { //网络异常 return(-1); } } /// <summary> /// 接收数据 /// </summary> /// <param name="buffer">缓冲区</param> /// <returns></returns> int ReceiveByBuffer(NetworkStream stream, byte[] buffer, int length) { try { return(stream.Read(buffer, 0, length)); } catch (Exception) { //网络异常 return(-1); } } #endregion #region 接收文件 /// <summary> /// 请求接收文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void _taskManager_FileReceiveRequired(object sender, FileReceiveRequiredEventArgs e) { if (!IsInitialized) { return; } new Thread(() => { PerformFileReceive(e.Task, e.Item); }) { IsBackground = true }.Start(); }
/// <summary> /// 标记一个任务项目状态,并检查任务是否完成 /// </summary> /// <param name="item">任务条目</param> /// <param name="state">状态</param> internal void MarkReceiveTaskItemState(FileTaskItem item, FileTaskItemState state) { if (item.State == state) { return; } if (state == FileTaskItemState.Finished || state == FileTaskItemState.Failure) { //退出传输状态 this.activeReceiveItems.Remove(item); OnTaskItemProgressChanged(new FileTaskEventArgs(item.TaskInfo, item)); this.EnsureReceiveStateUpdateTimerState(); } item.State = state; OnTaskItemStateChanged(new FileTaskEventArgs(item.TaskInfo, item)); //是否需要更新状态 if (state == FileTaskItemState.Processing) { this.activeReceiveItems.Add(item); this.EnsureReceiveStateUpdateTimerState(); } //如果是完成了,那就查找下这个任务是不是全部完成了,如果是的话,那就删掉任务 if ((state == FileTaskItemState.Finished || state == FileTaskItemState.Failure)) { //检测任务完成 if (item.TaskInfo.TaskList.Count(s => s.State != FileTaskItemState.Finished && s.State != FileTaskItemState.Failure) == 0) { FileTaskInfo task = item.TaskInfo; this.OnReceiveTaskFinished(new FileTaskEventArgs(task)); this.ReceiveTask.Remove(task); //检测是否有失败的,如果有就将请求重新发送以便重试 for (int i = task.TaskList.Count - 1; i >= 0; i--) { if (task.TaskList[i].State != FileTaskItemState.Failure) { task.TaskList.RemoveAt(i); //如果是成功的,则移除 } else { task.TaskList[i].State = FileTaskItemState.Scheduled; //重置任务的当前状态 if (!task.TaskList[i].IsFolder) { task.TaskList[i].FullPath = System.IO.Path.GetDirectoryName(task.TaskList[i].FullPath); } } } if (task.TaskList.Count > 0) { var e = new FileTaskEventArgs(task); OnFileReceiveTaskReDroped(e); if (!e.IsHandled) { OnFileReceiveTaskDiscarded(e); } } } StartReceive(); } }
/// <summary> /// 创建 FileTaskEventArgs class 的新实例 /// </summary> public FileTaskEventArgs(FileTaskInfo taskInfo, FileTaskItem taskItem) { TaskInfo = taskInfo; TaskItem = taskItem; IsHandled = false; }
/// <summary> /// 接收文件夹 /// </summary> /// <param name="client"></param> /// <param name="task"></param> /// <param name="item"></param> void PerformFileReceive_Folder(TcpClient client, FileTaskInfo task, FileTaskItem item) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Initializing); //创建网络流 NetworkStream netStream = null; try { netStream = client.GetStream(); } catch (Exception) { OnNetworkError(new EventArgs()); TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); return; } bool updateTotal = item.TotalSize == 0; //是否在更新进度的时候需要更新总数 using (netStream) { //发送文件请求 PackedNetworkMessage pnm = MessagePacker.BuildNetworkMessage(Message.Create(task.RemoteHost, task.RemoteHost.HostSub.Ipv4Address, Config.GetRandomTick(), Config.HostName, Config.HostUserName, Consts.Commands.GetDirFiles, 0ul, string.Format("{0:x}:{1:x}:0:", task.PackageID, item.Index), "")); if (!SendDataInBuffer(netStream, pnm.Data, pnm.Data.Length)) { return; //发送请求 } TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Processing); item.StartTime = DateTime.Now; string filename; ulong size; bool isFolder, isRet; Stack <string> pathStack = new Stack <string>(); string currentPath = item.FullPath; while (client.Connected && item.State != FileTaskItemState.Canceling && ReadCmdHeader(netStream, task.RemoteHost, out filename, out size, out isFolder, out isRet)) { if (isRet) { if (pathStack.Count > 0) { currentPath = pathStack.Pop(); if (pathStack.Count == 0) { break; //Fixed: 当当前队列不再有信息时,其实接收已经完成了。因为当前队列中最后一个肯定是文件夹自己。 } } else { break; } } else if (isFolder) { //建立文件夹 if (!ProcessDirCmd(item, ref currentPath, pathStack, filename, updateTotal)) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); return; } } else { //传文件 if (!ProcessFileTransfer(client, netStream, task, item, currentPath, filename, size, updateTotal)) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); return; } } } netStream.Close(); } if (item.State == FileTaskItemState.Canceling) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Canceled); } else if (item.State != FileTaskItemState.Failure) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Finished); } }
//传输文件 bool ProcessFileTransfer(TcpClient client, NetworkStream netStream, FileTaskInfo task, FileTaskItem item, string currentDirectory, string fileName, ulong fileSize, bool updateTotal) { FileStream writer = null; string path = Path.Combine(currentDirectory, fileName); try { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path)); writer = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write); } catch (Exception) { OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.CreateFile, path, task.RemoteHost)); TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); return(false); } //初始化传输参数 item.CurrentFileSize = fileSize; item.CurrentFileTransfered = 0ul; item.CurrentName = fileName; if (updateTotal) { item.TotalSize += fileSize; } item.FileCount++; using (writer) { byte[] buffer = new byte[SendBuffer]; int length = 0; int readlength = buffer.Length; if ((ulong)readlength > item.CurrentFileSize) { readlength = (int)item.CurrentFileSize; } while (item.State != FileTaskItemState.Canceling && client.Connected && item.CurrentFileTransfered < item.CurrentFileSize && (length = ReceiveByBuffer(netStream, buffer, readlength)) > 0) { if (!WriteBufferToFile(task.RemoteHost, writer, path, buffer, length)) { break; } item.CurrentFileTransfered += (ulong)length; item.FinishedSize += (ulong)length; readlength = buffer.Length; if ((ulong)readlength > item.CurrentFileSize - item.CurrentFileTransfered) { readlength = (int)(item.CurrentFileSize - item.CurrentFileTransfered); } } writer.Close(); System.Diagnostics.Debug.Assert(item.CurrentFileTransfered <= item.CurrentFileSize, string.Format("传输文件异常。{0} 预计长度:{1} ,实际写入 {2}", item.CurrentName, item.CurrentFileSize, item.CurrentFileTransfered)); if (item.CurrentFileTransfered < item.CurrentFileSize) { if (item.State != FileTaskItemState.Canceling) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); } return(false); } else { item.FinishedFileCount++; return(true); } } }
/// <summary> /// 接收文件 /// </summary> /// <param name="client"></param> /// <param name="task"></param> /// <param name="item"></param> void PerformFileReceive_File(TcpClient client, FileTaskInfo task, FileTaskItem item) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Initializing); //创建文件 System.IO.FileInfo fileinfo = new FileInfo(item.FullPath); if (fileinfo.Exists) { item.CurrentFileTransfered = (ulong)fileinfo.Length; } if (item.CurrentFileSize <= item.CurrentFileTransfered) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Finished); return; } //创建文件 System.IO.FileStream writer = null; try { System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(item.FullPath)); writer = fileinfo.OpenWrite(); } catch (Exception) { OnFileSystemOperationError(new FileSystemOperationErrorEventArgs(FileSystemOperationType.CreateFile, item.FullPath, task.RemoteHost)); TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); return; } //创建网络流 NetworkStream netStream = null; try { netStream = client.GetStream(); } catch (Exception) { OnNetworkError(new EventArgs()); TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); return; } using (writer) { using (netStream) { //发送文件请求 PackedNetworkMessage pnm = MessagePacker.BuildNetworkMessage(Message.Create(task.RemoteHost, task.RemoteHost.HostSub.Ipv4Address, Config.GetRandomTick(), Config.HostName, Config.HostUserName, Consts.Commands.GetFileData, 0ul, string.Format("{0:x}:{1:x}:{2}", task.PackageID, item.Index, item.CurrentFileTransfered), "")); if (!SendDataInBuffer(netStream, pnm.Data, pnm.Data.Length)) { return; //发送请求 } TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Processing); item.StartTime = DateTime.Now; byte[] buffer = new byte[SendBuffer]; int length = buffer.Length; while (item.State != FileTaskItemState.Canceling && client.Connected && (length = ReceiveByBuffer(netStream, buffer, length)) > 0) { if (!WriteBufferToFile(task.RemoteHost, writer, item.FullPath, buffer, length)) { return; } item.CurrentFileTransfered += (ulong)length; item.FinishedSize += (ulong)length; //判断还有多少 length = buffer.Length; ulong restLength = item.CurrentFileSize - item.CurrentFileTransfered; if (restLength < (ulong)length) { length = (int)restLength; } } } } //判断是否完成 if (item.State == FileTaskItemState.Canceling) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Canceled); } else if (item.CurrentFileTransfered == item.CurrentFileSize) { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Finished); } else { TaskManager.MarkReceiveTaskItemState(item, FileTaskItemState.Failure); } }
/// <summary> /// 创建一个新的 FileReceiveEventArgs 对象. /// </summary> public FileReceiveRequiredEventArgs(FileTaskInfo task, FileTaskItem item) { Task = task; Item = item; IsHandled = false; }
/// <summary> /// 处理文件发送请求 /// </summary> /// <param name="client"></param> void PerformFileSend(object p) { System.Diagnostics.Debug.WriteLine("文件发送线程 [0x" + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString("X4") + "] 已经启动"); using (TcpClient client = p as TcpClient) { byte[] buffer = new byte[400]; //接收或发送缓冲区 int bytesReceived = ReceiveByBuffer(client, buffer, buffer.Length); //第一步:接收文件传输命令 if (bytesReceived < 1) { return; //没收到数据 } Message request = ParseSendCommand(buffer, 0, bytesReceived); //试着解析命令 System.Diagnostics.Debug.WriteLineIf(request == null, "未能解析收到的请求,退出发送线程"); if (request == null) { return; } System.Diagnostics.Debug.WriteLine("已解析文件请求:" + request.NormalMsg.ToString()); //非法请求 //查找任务 string[] taskInfo = request.NormalMsg.Split(':'); ulong pid = 0ul; int tid = 0; FileTaskItem task = null; if (taskInfo.Length < 2 || !ulong.TryParse(taskInfo[0], System.Globalization.NumberStyles.AllowHexSpecifier, null, out pid) || !int.TryParse(taskInfo[1], System.Globalization.NumberStyles.AllowHexSpecifier, null, out tid) || (task = TaskManager.QuerySendTask(pid, tid, (client.Client.RemoteEndPoint as IPEndPoint).Address)) == null ) { return; } System.Diagnostics.Debug.WriteLine(string.Format("文件请求已经接纳,文件编号:0x{0:x8},文件索引:0x{1:x4}", pid, tid)); TaskManager.MarkSendTaskItemState(task, FileTaskItemState.Initializing); //准备发送 if (task.IsFolder) { PerformSendDirectory(client, task.TaskInfo, task); } else { //文件支持有限的断点续传 if (taskInfo.Length == 3) { ulong temp; if (ulong.TryParse(taskInfo[2], out temp)) { task.CurrentFileTransfered = temp; task.FileTransferedAtPast = temp; } System.Diagnostics.Debug.WriteLineIf(task.CurrentFileTransfered > 0, string.Format("断点模式,从 0x{0} 处开始续传", task.CurrentFileTransfered)); } PerformSendFile(client, task.TaskInfo, task); } client.Close(); } }