Ваш опубликованный код, похоже, предполагает, что никакие пакеты не будут отброшены в пути от отправителя к получателю - это предположение не выполняется в реальной жизни (даже когда отправитель и получатель обарасположен на той же машине!), что является наиболее вероятной причиной того, что ваши передачи не работают, за исключением очень маленьких файлов (где вы можете положиться на удачу, чтобы убедиться, что все пакеты пройдут с первой попытки).
Чтобы реализовать более надежный механизм, вашей программе-получателю потребуется какой-то способ (а) определить, когда пакет был отброшен, и (б) отреагировать на это знание, отправив сообщение обратно отправителю, запрашивающемуотправитель повторно передает данные из «потерянного» пакета.(И, конечно, пакет запроса на ретрансляцию также может быть отброшен, поэтому вам также понадобится способ справиться с этим!)
Тем временем вашей программе-отправителю потребуется не только отправлять данные (как это происходит в настоящее время), но также принимает любые входящие пакеты запроса на повторную передачу от получателя и реагирует на них путем повторной передачи запрошенных данных.
В зависимости от точной схемы вашего протокола, отправитель и получатель могут такженеобходимо предпринять действия после того, как прошло определенное количество времени, когда данные не были отправлены или получены, чтобы избежать остановки процесса передачи файла, если все пакеты, чей прием был бы продвинут, будут отброшены.
Поэтому ваштекущего подхода к простому вызову блокировки sendto()
или recvfrom()
в цикле будет недостаточно;вместо этого и отправителю, и получателю потребуется реализовать некий конечный автомат, который позволит им одновременно отправлять соответствующий пакет (ы) в соответствующее время и быстро принимать и обрабатывать любые входящие пакеты. Обычно это делается с помощью отдельныхпотоки отправителя и получателя, или, альтернативно, установив сокет в неблокирующий режим и записав цикл обработки событий вокруг блокирующего вызова на select()
или poll()
.(Я предпочитаю последнее, потому что IMO, в то время как конечные автоматы сложно найти правильное решение, многопоточность еще сложнее)
Хорошее начало - поместить порядковый номер в каждый пакет;это позволяет получателю знать, как упорядочить данные, и позволяет ему обнаруживать «дыру» в данных, которые он получил.Как только он обнаружил дыру (то есть один или несколько пропущенных порядковых номеров), он может отправить пакет обратно отправителю с просьбой повторно отправить эти пакеты, и отправителю придется отреагировать путем повторной отправки этих пакетов.,Повторяйте по мере необходимости до тех пор, пока получатель не получит пакет с каждым возможным порядковым номером (вам также необходимо каким-то образом сообщить получателю, сколько ожидаемых порядковых номеров).