//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... }
//called if there are new data private void OnClientDataReceived(object sender, DataReceivedEventArgs e) { //neplatne zpravy zahazujeme if (!MessageConstructor.ValidateMessage(e.Data)) { return; } if (MessageConstructor.IsHandshake(e.Data)) { handshake_response = e.Data; return; } if (MessageConstructor.IsDataReceived(e.Data)) { uint rc_packet_num = BitConverter.ToUInt32(e.Data, 1); uint aw_packet_num = BitConverter.ToUInt32(e.Data, 1 + sizeof(uint)); if (StopAndWait && rc_packet_num == UInt32.MinValue && aw_packet_num == UInt32.MaxValue) { // rezim stop and go => pouze jeden packet na ceste a prijemce prijal chybnou zpravu // posli znova packet Client.SendPacket(Packets[0], Target); return; } PacketsMutex.WaitOne(); for (int i = 0; i < MaxPackets; ++i) { if (Packets[i].AckCount == -1) { continue; } //if (Packets[i].Number == packet_num) //{ // is_pending = true; // Packets[i].OnReceive(); // packet_num--; // AckPackets.Add(i); //} if (Packets[i].Number == rc_packet_num) { Packets[i].OnReceive(); //rc_packet_num--; AckPackets.Add(i); DeliveredPacketCount++; } if (Packets[i].Number == aw_packet_num) { Packets[i].AckCount++; if (Packets[i].AckCount >= 3) { Client.SendPacket(Packets[i], Target); } } } PacketsMutex.ReleaseMutex(); //Console.WriteLine($"Received ACK of {packet_num}"); return; } if (MessageConstructor.IsFileMeta(e.Data)) { meta_response = e.Data; return; } }