public async void SendFileAsync(string addr, string filepath) { Message meta = Message.CreateMeta(filepath, PackSize); string status = ""; long continueId = 0; try { status = "Wait Confirmation"; IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(addr), ReceiverPort); UdpSend(remoteEP, meta); await WaitMessage( msg => msg.Type == MsgType.Continue, (remoteEP, msg) => continueId = msg.PackID); if (continueId == -1) { OnTransferError?.Invoke(new State(ActionCode.FileSend, StateCode.Error, "Request rejected")); return; } remoteEP.Port = TransferPort; status = "Transferring"; TcpSetupStream(remoteEP, ns => { using FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read); byte[] bs = null; Message dataMsg = new Message { PackID = continueId, Data = new byte[PackSize] }; fs.Seek((continueId - 1) * PackSize, SeekOrigin.Begin); while (fs.Length - fs.Position > PackSize) { fs.Read(dataMsg.Data, 0, PackSize); bs = dataMsg.ToBytes(); ns.Write(bs, 0, bs.Length); ns.Flush(); dataMsg.PackID++; OnPackTransfered?.Invoke((fs.Position / fs.Length)); } fs.Read(dataMsg.Data, 0, (int)(fs.Length - fs.Position)); bs = dataMsg.ToBytes(); ns.Write(bs, 0, bs.Length); ns.Flush(); }); OnTransferDone?.Invoke(new State(ActionCode.FileSend, StateCode.Success, "")); } catch (OperationCanceledException) { OnTransferError?.Invoke(new State(ActionCode.FileSend, StateCode.Error, status + " Timeout")); } catch (SocketException e) { OnTransferError?.Invoke(new State(ActionCode.FileSend, StateCode.Error, e.Message)); } }
private void ReceiveFile(IPEndPoint remoteEP, Message meta) { int continueId = LoadMetaFile(meta); UdpSend(remoteEP, new Message { PackID = continueId }); TcpAcceptStream(ns => { using (FileStream metafs = new FileStream(meta.Filename + ".meta", FileMode.Open)) using (FileStream fs = new FileStream(meta.Filename, FileMode.OpenOrCreate)) using (SHA256 sha = SHA256.Create()) { Message data; byte[] bs = new byte[meta.PackSize + 9]; for (int i = continueId - 1; i < meta.PackCount - 1; i++) { ns.Read(bs, 0, meta.PackSize + 9); data = Message.Parse(bs); fs.Seek(0, SeekOrigin.End); fs.Write(data.Data, 0, meta.PackSize); metafs.Seek(-8, SeekOrigin.End); metafs.Write(Utils.GetBytes(data.PackID + 1), 0, 8); fs.Flush(); metafs.Flush(); OnPackTransfered?.Invoke((i / meta.PackCount)); } ns.Read(bs, 0, meta.PackSize + 9); data = Message.Parse(bs); fs.Write(data.Data, 0, (int)(meta.Size - meta.PackSize * (meta.PackCount - 1))); fs.Flush(); fs.Seek(0, SeekOrigin.Begin); metafs.Seek(0, SeekOrigin.Begin); byte[] metahs = new byte[256]; metafs.Read(metahs, 0, 256); byte[] hash = new byte[256]; byte[] t = sha.ComputeHash(fs); Array.Copy(t, 0, hash, 0, t.Length); if (!hash.SequenceEqual(metahs)) { throw new ChecksumMismatchException("Checksum not match, file may be collapsed."); } } File.Delete(meta.Filename + ".meta"); }); }