Я тестировал реализацию сервлета HTTP (любезно предоставленный BalusC), который поддерживает HTTP-байтовые запросы.
Я обнаружил некоторые особые отличия между разными HTTP-клиентами и задавался вопросом, не пропал ли я что-нибудь. Я использовал видеофайл > 2G mp4 для своих тестов и собирал пакеты с Wireshark. Это примерно то, что происходит:
-
Samsung Galaxy SII:
- Запрос HTTP GET для файла поступает с запросом диапазона байтов
[0; <almost the end of the file>]
- сервер отвечает, начинает поток файла
-
каждый последующий фрагмент обслуживается в пределах того же HTTP-ответа. Новый HTTP-запрос не отправляется (если видео не переадресовано в определенную позицию). Для этого поток потокового кода довольно прост, он читает
RandomAccessFile input
и записывается вOutputStream output
черезbyte[] buffer
:while ((read = input.read(buffer)) > 0) { output.write(buffer, 0, read); }
- Запрос HTTP GET для файла поступает с запросом диапазона байтов
- iPad 1
- Запрос HTTP GET для файла поступает с запросом диапазона байтов
[0; <almost the end of the file>]
- сервер отвечает, начинает поток файла
- iPad получает кусок или два, а затем в одностороннем порядке решает прекратить прием байтов с сервера и выдает отдельный
GET
запрос для следующего фрагмента файла. Новые границы диапазона являются, например,[100, almost the end of the file]
. Видео отображается ОК. - цикл повторяется снова с шага 2. Левая граница всегда перемещается к концу файла.
- Запрос HTTP GET для файла поступает с запросом диапазона байтов
Я не исследовал, как именно соединение прекращается. Возможно, iPad перестает отправлять пакеты TCP ACK, я полагаю, это не имеет большого значения.
Моя проблема в том, что для каждого завершенного соединения я получаю исключение java.net.SocketException: Broken pipe
. Это не только загрязняет журналы (что является незначительной/разрешимой проблемой), но я считаю, что это может повредить производительность, поскольку увеличение исключений довольно дорого. При просмотре простого видео частота исключения составляла около 1 исключение/сек, но если у сервера было 100 одновременных пользователей, то JVM, вероятно, потратила бы массу времени, просто вычисляя трассировки стека вместо реальной работы.
Я также тестировал это на iPhone с помощью iOS 6 и смог наблюдать за тем же поведением, что и iPad 1. Чтобы повторить, этот не происходит на Samsung Android, ни на любых браузерах для настольных компьютеров, которые я пробовал, включая Safari на рабочем столе Mac.
Вопросы:
- является ли это ошибкой/особенностью iPad/iPhone?
- Есть ли способ для этого?