private void TransferSingleTaskSmallFile(FileTask task, TransferType taskType) { try { SocketClient client = SocketFactory.GenerateConnectedSocketClient(task, 1); if (taskType == TransferType.Upload) { int pt = 0; byte[] headerBytes = BytesConverter.WriteString(new byte[4], task.RemotePath, ref pt); byte[] contentBytes = File.ReadAllBytes(task.LocalPath); byte[] bytes = new byte[headerBytes.Length + contentBytes.Length]; Array.Copy(headerBytes, 0, bytes, 0, headerBytes.Length); Array.Copy(contentBytes, 0, bytes, headerBytes.Length, contentBytes.Length); client.SendBytes(SocketPacketFlag.UploadRequest, bytes); client.ReceiveBytesWithHeaderFlag(SocketPacketFlag.UploadAllowed, out byte[] recvBytes); client.Close(); } else { client.SendBytes(SocketPacketFlag.DownloadRequest, task.RemotePath); client.ReceiveBytesWithHeaderFlag(SocketPacketFlag.DownloadAllowed, out byte[] bytes); client.Close(); File.WriteAllBytes(task.LocalPath, bytes); } this.Record.CurrentFinished = task.Length; task.Status = FileTaskStatus.Success; } catch (Exception ex) { task.Status = FileTaskStatus.Failed; System.Windows.Forms.MessageBox.Show(ex.Message); } }
/// <summary> /// 下载的主线程,循环下载列表中每一个任务直至所有任务完成 /// </summary> private void TransferMain() { IsTransfering = true; // 直到 currentTaskIndex 指向最后,代表所有任务完成 while (!Record.IsFinished()) { FileTask current_task = Record.CurrentTask; if (current_task.IsDirectory) { Record.StartNewTask(current_task); TransferDirectoryTask(current_task); } else { UpdateUI(this, EventArgs.Empty); Record.StartNewTask(current_task); TransferSingleTask(current_task); if (IsStopDownloading) { IsStopDownloading = false; IsTransfering = false; return; } Record.FinishCurrentTask(); Record.CurrentTaskIndex++; } } /// 界面更新 100% TicTokBytes = 0; this.Record.CurrentFinished = this.Record.CurrentLength; this.Record.Clear(); UpdateProgress(this, EventArgs.Empty); IsTransfering = false; }
private void UploadSingleTaskDirectory(FileTask task) { /// 请求 server 端创建目录 try { SocketClient client = SocketFactory.GenerateConnectedSocketClient(task, 1); int pt = 0; byte[] headerBytes = BytesConverter.WriteString(new byte[4], task.RemotePath, ref pt); client.SendBytes(SocketPacketFlag.CreateDirectoryRequest, headerBytes); client.ReceiveBytesWithHeaderFlag(SocketPacketFlag.CreateDirectoryAllowed, out byte[] recvBytes); client.Close(); } catch (Exception) { task.Status = FileTaskStatus.Denied; return; } /// 更新 TaskList, 重新定位当前任务 UpdateTasklist(this, new UpdateUIInvokeEventArgs(new Action(() => { lock (this.Record) { FileTask father_task = Record.CurrentTask; int bias = Record.CurrentTaskIndex; this.Record.RemoveTaskAt(Record.CurrentTaskIndex); List <FileTask> tasks_son = GetUploadTasksInDirectory(father_task); for (int i = 0; i < tasks_son.Count; ++i) { FileTask task_son = tasks_son[i]; UpdateTaskLength(task_son); this.Record.InsertTask(bias + i, task_son); } } }))); }
public void InsertTask(int index, FileTask task) { lock (this.FileTasks) { this.FileTasks.Insert(index, task); TotalLength += task.Length; Logger.Log("<FiletaskRecord> call InsertTask " + index.ToString() + " : " + task.ToString(), LogLevel.Debug); } }
/// <summary> /// 启动新任务时调用 /// </summary> public void StartNewTask(FileTask task) { lock (this.FileTasks) { CurrentLength = task.Length; // 更新 CurrentLength CurrentFinished = task.FinishedPacket * HB32Encoding.DataSize; } Logger.Log(string.Format("<FileTaskRecord> call StartNewTask, TotalLength={0}, TotalFinished={1}, CurrentLength={2}, CurrentFinished={3}, PrevBytesAddup={4}", TotalLength, TotalFinished, CurrentLength, CurrentFinished, PrevBytesAddup), LogLevel.Debug); }
public void RemoveTaskAt(int index) { lock (this.FileTasks) { FileTask task = this.FileTasks[index]; this.FileTasks.RemoveAt(index); TotalLength -= task.Length; Logger.Log(string.Format("<FiletaskRecord> call RemoveTaskAt : " + index.ToString()), LogLevel.Debug); } }
public static int Compare(FileTask t1, FileTask t2) { if (t1.IsDirectory == t2.IsDirectory) { return(t1.Name.CompareTo(t2.Name)); } else { return(t1.IsDirectory ? -1 : 1); } }
/// <summary> /// 启动 Directory 传输任务, 更新Task列表后按原 Record.CurrentIndex 返回 /// </summary> /// <param name="task"></param> private void TransferDirectoryTask(FileTask task) { if (task.Type == TransferType.Upload) { UploadSingleTaskDirectory(task); } else { DownloadSingleTaskDirectory(task); } }
/// <summary> /// /// </summary> /// <param name="task"></param> private void TransferSingleTaskBigFile(FileTask task) { /// 请求 server 端打开文件, 并获取 FileStreamId task.FileStreamId = GetFileStreamId(task); if (task.FileStreamId == -1) { task.Status = FileTaskStatus.Failed; Record.CurrentTaskIndex++; return; } /// 创建本地 FileStream localFileStream = new FileStream(task.LocalPath, FileMode.OpenOrCreate, task.Type == TransferType.Upload ? FileAccess.Read : FileAccess.Write); /// 运行下载子线程 FileTaskStatus result = RunTransferSubThreads(task); /// 结束 Transfer, 关闭 FileStream localFileStream.Close(); localFileStream = null; /// 请求server端关闭并释放文件 try { SocketClient sc = SocketFactory.GenerateConnectedSocketClient(task, 1); if (task.Type == TransferType.Upload) { sc.SendBytes(SocketPacketFlag.UploadPacketRequest, new byte[1], task.FileStreamId, -1); } else { sc.SendHeader(SocketPacketFlag.DownloadPacketRequest, task.FileStreamId, -1); } sc.Close(); } catch (Exception ex) { Logger.Log("Transfer finished. But server FileStream not correctly closed. " + ex.Message, LogLevel.Warn); } /// 判断从子线程退出返回原因是否是 Pause if (IsStopDownloading) { task.Status = FileTaskStatus.Pause; } else { task.Status = result; } }
/// <summary> /// 加载当前任务 /// </summary> public void LoadXml() { if (!File.Exists(RecordPath)) { System.Windows.Forms.MessageBox.Show(RecordPath + "do not exist"); return; } XDocument doc = XDocument.Load(RecordPath); XElement root = doc.Root; /// Index XElement idx = root.Element("index"); CurrentTaskIndex = int.Parse(idx.Element("current").Value); /// Tasks XElement tasks = root.Element("taskCollection"); foreach (XElement task in tasks.Elements("task")) { FileTask fileTask = new FileTask(); fileTask.Route = ConnectionRoute.FromBytes(Convert.FromBase64String(task.Element("Route").Value)); fileTask.IsDirectory = bool.Parse(task.Element("IsDirectory").Value); fileTask.Type = (TransferType)Enum.Parse(typeof(TransferType), task.Element("Type").Value); fileTask.RemotePath = task.Element("RemotePath").Value; fileTask.LocalPath = task.Element("LocalPath").Value; fileTask.Length = long.Parse(task.Element("Length").Value); fileTask.Status = (FileTaskStatus)Enum.Parse(typeof(FileTaskStatus), task.Element("Status").Value); fileTask.FinishedPacket = int.Parse(task.Element("FinishedPacket").Value); FileTasks.Add(fileTask); } /// Length /* * XElement len = root.Element("length"); * CurrentLength = long.Parse(len.Element("currentLength").Value); * CurrentFinished = long.Parse(len.Element("currentFinished").Value); * TotalLength = long.Parse(len.Element("totalLength").Value); * PrevBytesAddup = long.Parse(len.Element("taskAddup").Value); */ CurrentLength = FileTasks[CurrentTaskIndex].Length; CurrentFinished = FileTasks[CurrentTaskIndex].FinishedPacket * HB32Encoding.DataSize; TotalLength = 0; PrevBytesAddup = 0; for (int i = 0; i < FileTasks.Count; ++i) { TotalLength += FileTasks[i].Length; if (i < CurrentTaskIndex) { PrevBytesAddup += FileTasks[i].Length; } } Logger.Log("Loaded record.", LogLevel.Info); }
/// <summary> /// 下载FileTask加入队列前, 对文件夹任务获取总大小 /// </summary> /// <param name="task"></param> /// <returns></returns> public static long GetDownloadDirectoryTaskLength(FileTask task) { try { SocketClient client = SocketFactory.GenerateConnectedSocketClient(task.Route); client.SendBytes(SocketPacketFlag.DirectorySizeRequest, task.RemotePath); client.ReceiveBytesWithHeaderFlag(SocketPacketFlag.DirectorySizeResponse, out byte[] bytes); return(long.Parse(Encoding.UTF8.GetString(bytes))); } catch (Exception) { return(-1); } }
/// <summary> /// packet 完成写入后清除记录并修正完成package数目 /// </summary> /// <param name="task"></param> /// <param name="packet">完成写入的packet index</param> private void FinishPacket(FileTask task, int packet) { lock (this.PacketLock) { if (TransferingPackets.Contains(packet)) { TransferingPackets.Remove(packet); FinishedPackets.Add(packet); } while (FinishedPackets.Contains(task.FinishedPacket)) { FinishedPackets.Remove(task.FinishedPacket); task.FinishedPacket++; } } }
private void DownloadSingleTaskDirectory(FileTask task) { /// 创建本地 directory if (!Directory.Exists(task.LocalPath)) { DirectoryInfo dirInfo = new DirectoryInfo(task.LocalPath); dirInfo.Create(); } /// 获取 server 端文件列表 List <SocketFileInfo> files; try { SocketClient client = SocketFactory.GenerateConnectedSocketClient(task, 1); client.SendBytes(SocketPacketFlag.DirectoryRequest, task.RemotePath); client.ReceiveBytesWithHeaderFlag(SocketPacketFlag.DirectoryResponse, out byte[] recv_bytes); files = SocketFileInfo.BytesToList(recv_bytes); client.Close(); } catch (Exception) { task.Status = FileTaskStatus.Denied; return; } /// 更新 TaskList, 重新定位当前任务 UpdateTasklist(this, new UpdateUIInvokeEventArgs(new Action(() => { this.Record.RemoveTaskAt(Record.CurrentTaskIndex); int bias = Record.CurrentTaskIndex; for (int i = 0; i < files.Count; ++i) { SocketFileInfo f = files[i]; FileTask task_add = new FileTask { Route = task.Route.Copy(), IsDirectory = f.IsDirectory, Type = TransferType.Download, RemotePath = Path.Combine(task.RemotePath, f.Name), LocalPath = task.LocalPath + "\\" + f.Name, Length = f.Length, }; UpdateTaskLength(task_add); this.Record.InsertTask(bias + i, task_add); } }))); }
/// <summary> /// 对于即将添加到 FileTasks 列表中的 directory 任务, 应获取其总大小 /// </summary> /// <param name="task"></param> private void UpdateTaskLength(FileTask task) { if (task.Type == TransferType.Download) { if (task.IsDirectory && task.Length == 0) { task.Length = GetDownloadDirectoryTaskLength(task); } } else { if (task.IsDirectory && task.Length == 0) { task.Length = GetLocalDirectoryLength(task.LocalPath); } } }
private FileTaskStatus RunTransferSubThreads(FileTask task) { IsCurrentTaskFailed = false; /// 清空 packets 缓存记录 lock (this.PacketLock) { TransferingPackets.Clear(); FinishedPackets.Clear(); } TransferSubThreads = new Thread[Config.ThreadLimit]; for (int i = 0; i < Config.ThreadLimit; ++i) { if (task.Type == TransferType.Upload) { TransferSubThreads[i] = new Thread(new ParameterizedThreadStart(UploadThreadUnit)) { IsBackground = true }; } else { TransferSubThreads[i] = new Thread(new ParameterizedThreadStart(DownloadThreadUnit)) { IsBackground = true }; } TransferSubThreads[i].Start(task); Thread.Sleep(50); } //Config.ThreadLimit = 1; /// 阻塞至子线程工作完毕 for (int i = 0; i < Config.ThreadLimit; ++i) { TransferSubThreads[i].Join(); } /// 确定 task 状态 if (IsCurrentTaskFailed) { IsCurrentTaskFailed = false; return(FileTaskStatus.Failed); } else { return(FileTaskStatus.Success); } }
public void AddTask(FileTask task) { lock (this.FileTasks) { if (_need_clear) { FileTasks.Clear(); CurrentTaskIndex = 0; PrevBytesAddup = 0; TotalLength = 0; CurrentLength = 0; CurrentFinished = 0; _need_clear = false; } FileTasks.Add(task); TotalLength += task.Length; Logger.Log("<FiletaskRecord> call AddTask : " + task.ToString(), LogLevel.Debug); } }
/// <summary> /// 启动 File 传输任务,根据当前 FileTask 任务区分传输模式,并阻塞直到所有子线程完成后, /// 将 currentTaskIndex 指向下个 task,返回 /// 当前任务为 小文件 则启用单线程传输 /// 当前任务为 大文件 则启用多线程传输 /// </summary> private void TransferSingleTask(FileTask task) { Logger.Log(string.Format("<FileTaskManager> call TransferSingleTask, {0, 20}{1}", "", task.ToString()), LogLevel.Debug); if (task.Type == TransferType.Download) { task.Status = FileTaskStatus.Downloading; } else if (task.Type == TransferType.Upload) { task.Status = FileTaskStatus.Uploading; } if (task.Length <= Config.SmallFileThreshold) { TransferSingleTaskSmallFile(task, task.Type); } else { TransferSingleTaskBigFile(task); } }
/// <summary> /// 根据 FileTask 向 Server 端请求 FileStreamId (16bit - 0~65535), 如有异常返回-1 /// </summary> /// <param name="task"></param> /// <returns></returns> private int GetFileStreamId(FileTask task) { SocketPacketFlag mask = (SocketPacketFlag)((task.Type == TransferType.Upload ? 1 : 0) << 8); try { SocketClient client = SocketFactory.GenerateConnectedSocketClient(task, 1); client.SendBytes(SocketPacketFlag.DownloadFileStreamIdRequest | mask, task.RemotePath); client.ReceiveBytesWithHeaderFlag(SocketPacketFlag.DownloadAllowed ^ mask, out byte[] bytes); client.Close(); string response = Encoding.UTF8.GetString(bytes); return(int.Parse(response)); } catch (Exception ex) { Logger.Log("Cannot get FileStreamID, Exception : " + ex.Message); System.Windows.Forms.MessageBox.Show(ex.Message); return(-1); } }
/// <summary> /// 申请获取任务packet index, 任务完成则返回 -1 /// 根据 packet 数目更新 UI /// </summary> /// <param name="task"></param> /// <returns> packet index </returns> private int GeneratePacketIndex(FileTask task) { lock (this.PacketLock) { int packet = task.FinishedPacket; while (packet < task.TotalPacket) { if (TransferingPackets.Contains(packet) || FinishedPackets.Contains(packet)) { packet++; continue; } else { TransferingPackets.Add(packet); return(packet); } } return(-1); } }
/// <summary> /// 在 Uplaod Directory时, 获取 local_path 下所有子 FileTask 列表 /// </summary> /// <param name="local_path"></param> /// <param name="remote_path"></param> /// <returns></returns> private List <FileTask> GetUploadTasksInDirectory(FileTask father_task) { string local_path = father_task.LocalPath; string remote_path = father_task.RemotePath; DirectoryInfo directory = new DirectoryInfo(local_path); DirectoryInfo[] directoryInfos = directory.GetDirectories(); List <FileTask> tasks = new List <FileTask>(); foreach (DirectoryInfo dir_info in directoryInfos) { tasks.Add(new FileTask { Route = father_task.Route.Copy(), IsDirectory = true, Type = TransferType.Upload, RemotePath = remote_path + "\\" + dir_info.Name, LocalPath = local_path + "\\" + dir_info.Name, Length = 0, }); } FileInfo[] fileInfos = directory.GetFiles(); foreach (FileInfo file_info in fileInfos) { tasks.Add(new FileTask { Route = father_task.Route.Copy(), IsDirectory = false, Type = TransferType.Upload, RemotePath = remote_path + "\\" + file_info.Name, LocalPath = local_path + "\\" + file_info.Name, Length = file_info.Length, }); } tasks.Sort(FileTask.Compare); return(tasks); }
/// <summary> /// 响应 Pages 中的添加任务调用 /// 对于Directory 任务会获取任务文件夹大小 /// </summary> /// <param name="task"></param> public void AddTask(FileTask task) { UpdateTaskLength(task); Record.AddTask(task); }
private void DownloadThreadUnit(object o) { FileTask task = (FileTask)o; SocketClient client = SocketFactory.GenerateConnectedSocketClient(task, -1); int packet = GeneratePacketIndex(task); while (packet != -1) { if (IsStopDownloading || IsCurrentTaskFailed) { break; } try { #region 通过 fsid 向 server 请求 bytes /// ↑ 包含在 server 重启后重新获取 fsid 的异常处理 if (IsRequestingFsid) { /// 此时其它线程正在获取fsid并已获得 obj_lock_request_fsid 锁 /// 等待其它线程释放 obj_lock_request_fsid 后, 可通过 fsid 请求packet lock (obj_lock_request_fsid) { client.SendHeader(SocketPacketFlag.DownloadPacketRequest, task.FileStreamId, packet); } } else { /// 正常请求packet client.SendHeader(SocketPacketFlag.DownloadPacketRequest, task.FileStreamId, packet); } client.ReceiveBytes(out HB32Header header, out byte[] bytes); /// 异常处理 if (header.Flag == SocketPacketFlag.DownloadDenied) { if (header.I1 > 0) { /// ↓对应情况: Server 重启后没有对应 fsid, client端原有 fsid 不可用 if (IsRequestingFsid) { /// 此时其它子线程正在获取 fsid /// 执行 continue 后进入 lock(obj_lock_request_fsid) 等待获取fsid的线程释放锁 continue; } else { /// 加锁获取 fsid, 此时其它子线程等待当前线程获取 fsid 后再发包 IsRequestingFsid = true; lock (obj_lock_request_fsid) { task.FileStreamId = GetFileStreamId(task); IsRequestingFsid = false; } } } else { /// task failed, 置 flag 后退出子线程 IsCurrentTaskFailed = true; break; } } #endregion lock (this.localFileStream) { localFileStream.Seek((long)packet * HB32Encoding.DataSize, SeekOrigin.Begin); localFileStream.Write(bytes, 0, header.ValidByteLength); } FinishPacket(task, packet); lock (this.Record) { TicTokBytes += header.ValidByteLength; Record.CurrentFinished += header.ValidByteLength; if (this.AllowUpdateUI()) { UpdateUI(this, EventArgs.Empty); if (Record.NeedSaveRecord()) { Record.SaveXml(); } } } packet = GeneratePacketIndex(task); } catch (Exception) { /// 生成已连接 SocketClient while (!IsStopDownloading) { try { client = SocketFactory.GenerateConnectedSocketClient(task, 1); break; } catch { continue; } } } } client.Close(); }
/// <summary> /// /// </summary> /// <param name="o"></param> private void UploadThreadUnit(object o) { FileTask task = (FileTask)o; SocketClient client = SocketFactory.GenerateConnectedSocketClient(task); int packet = GeneratePacketIndex(task); while (packet != -1) { if (IsStopDownloading || IsCurrentTaskFailed) { break; } try { /// 根据 packet 读取 FileStream 中 bytes long begin = (long)packet * HB32Encoding.DataSize; int length = HB32Encoding.DataSize; if (begin + HB32Encoding.DataSize > task.Length) { length = (int)(task.Length - begin); } byte[] contentBytes = new byte[length]; lock (this.localFileStream) { localFileStream.Seek((long)packet * HB32Encoding.DataSize, SeekOrigin.Begin); localFileStream.Read(contentBytes, 0, length); } /// 上传 packet 对应 bytes if (IsRequestingFsid) { lock (obj_lock_request_fsid) { client.SendBytes(SocketPacketFlag.UploadPacketRequest, contentBytes, task.FileStreamId, packet); } } else { client.SendBytes(SocketPacketFlag.UploadPacketRequest, contentBytes, task.FileStreamId, packet); } client.ReceiveBytes(out HB32Header header, out byte[] bytes); /// 异常处理 if (header.Flag == SocketPacketFlag.UploadDenied) { if (header.I1 > 0) { if (IsRequestingFsid) { continue; } else { IsRequestingFsid = true; lock (obj_lock_request_fsid) { task.FileStreamId = GetFileStreamId(task); IsRequestingFsid = false; } } } else { IsCurrentTaskFailed = true; break; } } /// 完成当前 packet FinishPacket(task, packet); lock (this.Record) { TicTokBytes += length; Record.CurrentFinished += length; if (this.AllowUpdateUI()) { UpdateUI(this, EventArgs.Empty); // Save record xml Record.SaveXml(); } } packet = GeneratePacketIndex(task); } catch (Exception) { while (!IsStopDownloading) { try { client = SocketFactory.GenerateConnectedSocketClient(task, 1); break; } catch { continue; } } } } client.Close(); }