Я начал работать над собственным проектом, который я делаю для развлечения.
Я создал приложение, которое использует дырокол UDP и затем передает данные с одного устройства A на второе устройство B, и я пытаюсь найти способ оптимизации скорости передачи.
Изначально у меня были некоторые проблемы с инициализацией передачи данных и получением данных на стороне получателя при выполнении тестов через Интернет и различные сети. После исследования я в конечном итоге уменьшил данные каждого пакета до 504 байтов, чтобы полезная нагрузка пакетов была ниже 508 байтов, что является максимальной безопасной полезной нагрузкой UDP . Это решило множество проблем, которые, по моему мнению, были вызваны потерей пакетов, и почти все время, когда я тестировал его с этой конфигурацией, работало идеально (при повторной передаче потерянных пакетов).
Передаваемые данные могут различаться по размеру (от нескольких КБ до 100 МБ), и когда передача инициируется, я беру исходные данные, обрабатываю их и делю их на пронумерованные куски по 504 байта и запускаю их через DatagramSocket
отправителя.
У меня есть цикл, который циклически перебирает пакеты, которые не были получены получателем, и отправитель поддерживает этот цикл в течение приличного количества попыток или времени, пока передача не будет успешно завершена или с ошибкой. В то же время отправитель прослушивает те же DatagramSocket
для пакетов подтверждения, которые приходят от получателя.
Получатель на другом конце (после какого-то рукопожатия, который получает информацию о том, сколько пакетов будет следовать) постоянно прослушивает входящие пакеты, и всякий раз, когда он получает один, он немедленно запускает пакет подтверждения.
Это прекрасно работает, но может быть очень медленным в зависимости от потери пакетов при каждой передаче (например, 20 минут для файла 5 МБ было одним из худших времен или 30-40 секунд для файла 5 МБ).
Ниже вы можете увидеть некоторый псевдокод, но с важными частями реализации:
//Sender side:
packetsToSend = ArrayList<ByteArray>()
keepTransfering = true
while(packetsToSend.isNotEmpty() && keepTransfering) {
packetsToSend.forEach { packet ->
datagramSocket.send( DatagramPacketCreation(packet) )
ackPacket = datagramSocket.receive(TIMEOUT=1) //1 millisecond timeout
processAckPacket(ackPacket)
}
}
С вышеописанным циклом и существующими потерями пакетов мне удалось получить скорость, равную 30-40 секундам, что составляет около 128 КБ / с.
Несколько недель назад я думал перенести часть получения подтверждения в другую ветку, чтобы это ускорило процесс. Протестировал его локально, работал нормально. Затем попытался проверить его через Интернет, и , по-видимому, маршрутизатор не может справиться с этим из-за перегрузки таблицы маршрутизатора .
Что я могу улучшить в логике, чтобы увеличить скорость без перегрузки маршрутизатора? Если у меня 1 миллисекундное ожидание (даже без получения пакета - давайте предположим, что я делаю это в другом потоке), скорость все равно будет ограничена до 488 КБ / с (5000 байт / с). Как бы я достиг более высоких скоростей, таких как 2-3 МБ / с?