private void OnClientDataReceived(object sender, DataReceivedEventArgs e) { if (!MessageConstructor.ValidateMessage(e.Data)) { if (StopAndWait) { byte[] msg = MessageConstructor.GetDataReceived(uint.MinValue, uint.MaxValue); Client.Send(msg, msg.Length); } return; } if (MessageConstructor.IsHandshake(e.Data)) { Connect(BitConverter.ToUInt32(e.Data, 1), BitConverter.ToUInt32(e.Data, 1 + sizeof(int)), e.EndPoint); return; } if (IsTransfering && MessageConstructor.IsFileData(e.Data)) { ReceivePacket(MessageConstructor.GetPacket(e.Data)); return; } if (MessageConstructor.IsFileMeta(e.Data)) { TotalPacketCount = BitConverter.ToUInt32(e.Data, 1 + sizeof(long)); string fn = Encoding.ASCII.GetString(e.Data, 1 + sizeof(long) + sizeof(uint), e.Data.Length - 1 - sizeof(long) - sizeof(uint) - sizeof(uint)); PrepareFile(fn); ReceivedPackets = new DataPacket[TotalPacketCount]; Console.WriteLine($"Receiving file '{fn}', total of {TotalPacketCount} packets."); WriteStatus(0, TotalPacketCount, false); Client.Send(e.Data, e.Data.Length); //Client.ErrorRate = 0.001; //Client.DropRate = 0.01; } if (IsTransfering && MessageConstructor.IsFileEnd(e.Data)) { WriteFile(); uint hash = BitConverter.ToUInt32(e.Data, 1); uint computed = MessageConstructor.GetFileHash(FileName); if (hash == computed) { FileReceived?.Invoke(this, new FileReceivedEventArgs() { FileName = FileName }); _is_transfering = false; } else { Console.WriteLine("Something is wrong, received different hash."); _is_transfering = false; } } }
//uint last_ack = 0; public void SendFile(string path) { DeliveredPacketCount = 0; _is_transfering = true; string file_name = Path.GetFileName(path); int buffer_size = (int)MaxPacketLength - DataPacket.MiscLength; // poslu FileMeta msg a pockam na odpoved - Handshake se stejnymi hodnotami FileInfo finfo = new FileInfo(path); uint pack_cnt = (uint)(finfo.Length / buffer_size + (finfo.Length % buffer_size > 0 ? 1 : 0)); //zkratit file_name, aby se veslo do maximalni delky packetu if (file_name.Length > (MaxPacketLength - sizeof(byte) - sizeof(long) - sizeof(int) - sizeof(uint))) { file_name = file_name.Substring((int)(MaxPacketLength - sizeof(byte) - sizeof(long) - sizeof(int) - sizeof(uint))); } byte[] msg = MessageConstructor.GetFileMeta(finfo.Length, pack_cnt, file_name); Client.Send(msg, msg.Length, Target); while (meta_response == null) { } if (!Extensions.AreSameArrays(msg, meta_response)) { meta_response = null; throw new Exception("Invalid FileMeta response"); } meta_response = null; // kdykoliv to bude mozne, tak budu posilat packety... // array - vsechny aktualni nepotvrzene packety uint packet_num = 0; // v tomto HashSetu jsou indexy packetu, ktere jsou potvrzene, tudiz je mozne je pouzit AckPackets = new HashSet <int>(); for (int i = 0; i < MaxPackets; ++i) { AckPackets.Add(i); } //int buffer_size = (int)MaxPacketLength - //packet length // 1 - //packet type // sizeof(uint) - //number of packet // sizeof(uint) - //data length // sizeof(uint); //CRC //indkuje, ze je potreba zrusit nejaky cyclus, pouziti ruzne bool break_cycle; WriteStatus(DeliveredPacketCount, pack_cnt, false); Client.ErrorRate = 0.1; Client.DropRate = 0.1; using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read))) { byte[] read_buffer = new byte[buffer_size]; while (reader.BaseStream.Position != reader.BaseStream.Length) { int act_count = reader.Read(read_buffer, 0, buffer_size); if (act_count < 0) { } // cekam na volny packet int idx; while (true) { PacketsMutex.WaitOne(); break_cycle = AckPackets.Count > 0; PacketsMutex.ReleaseMutex(); if (break_cycle) { break; } Thread.Sleep(20); } PacketsMutex.WaitOne(); idx = AckPackets.Pop(); PacketsMutex.ReleaseMutex(); //Nastvaim hodnoty volneho packetu // nemelo by byt potreba nastavovat PacketMutext, protoze jina vlakna by v tento moment nemela pristupovat k datum ktera chci upravovat //PacketsMutex.WaitOne(); Packets[idx].Data = MessageConstructor.GetFileData(packet_num, read_buffer, (uint)act_count); Packets[idx].Number = packet_num; Packets[idx].AckCount = 0; //PacketsMutex.ReleaseMutex(); Client.SendPacket(Packets[idx], Target); //zvysuji cislo packetu packet_num++; WriteStatus(DeliveredPacketCount, pack_cnt); } } //v tento moment jsou vsechnz packety dorucene ci na ceste, cekam na ack vsech prave posilanych while (true) { PacketsMutex.WaitOne(); // tedy vsechny packety jsou volne break_cycle = AckPackets.Count >= MaxPackets; PacketsMutex.ReleaseMutex(); WriteStatus(DeliveredPacketCount, pack_cnt); if (break_cycle) { break; } Thread.Sleep(20); } // poslu FileEnd msg //TODO: vypocet File hash byte[] file_end = MessageConstructor.GetFileEnd(MessageConstructor.GetFileHash(file_name)); Client.Send(file_end, file_end.Length, Target); // jine vlakno prijme reakci na file_end message a pokud to nebude uspokojiva odpoved, zopakuje zaslani... }