ReadableByteChannel.read (ByteBuffer dest) считывает с ограничением в 8 КБ.Почему?
-
02-10-2019 - |
Вопрос
У меня есть кое-какой код, который:
- считывает из
ReadableByteChannel
вByteBuffer
, - принимает к сведению переданные байты,
- делает паузу от нескольких десятков до сотен миллисекунд,
- передает
ByteBuffer
наWritableByteChannel
.
Некоторые детали:
- Оба канала являются сокетами TCP / IP.
- Общий объем считываемых данных по соединению исчисляется десятками мегабайт.
- Исходный сокет (который
ReadableByteChannel
получает байты от) находится на том же компьютере. - 64-разрядный Debian Lenny на HP DL380s
- Sun Java 1.6.0 обновление 20
Проблема в том, что независимо от того, насколько велик байтебуфер, либо с .allocate()
или .allocateDirect()
, количество байт, считываемых в байт-буфер, достигает максимума в 8 КБ.Мой целевой размер ByteBuffer составляет 256 КБ, что составляет лишь крошечную долю (1/32-ю).Примерно в 10% случаев считывается только 2896 байт.
Я проверил настройки TCP-буфера операционной системы, и они выглядят нормально.Это подтверждается просмотром отчета netstat о том, сколько байт находится в буфере - у обоих есть данные в буферах сокетов, превышающие 8 КБ.
tcp 0 192384 1.2.3.4:8088 1.2.3.4:53404 ESTABLISHED
tcp6 110144 0 1.2.3.4:53404 1.2.3.4:8088 ESTABLISHED
Одна вещь, которая выделяется здесь, - это сочетание TCP и TCP6, но, я думаю, это не должно быть проблемой.Мой Java-клиент находится на порту 53404 в приведенном выше выводе.
Я попытался настроить свойства сокета в пользу пропускной способности, а не задержки, но без изменений.
Socket socket = new Socket(host.getHostName(), host.getPort());
socket.setPerformancePreferences(1, 0, 2); //bw > connection time > latency
Когда я регистрирую значение socket.getReceiveBufferSize()
, он последовательно сообщает всего лишь 43856 байт.Хотя он меньше, чем мне бы хотелось, он все равно больше 8 КБ.(Это также не очень круглое число, которого я бы ожидал.)
Я действительно в тупике относительно того, в чем здесь проблема.Теоретически, AFAIK, этого не должно было происходить.Было бы нежелательно "переходить" к решению, основанному на потоке, хотя именно к этому мы перейдем дальше, если решение не может быть найдено.
Что я упускаю из виду?Что я могу сделать, чтобы это исправить?
Решение
Хорошо, я нашел проблему!(И я отвечаю на свой собственный вопрос на случай, если у кого-то возникнет такая же проблема.)
Я приводил в пример ReadableByteChannel
не непосредственно из Socket
экземпляр, но из HttpEntity.getContent()
(Клиент Apache HTTP Commons для Общего доступа) возвращенный метод InputStream
.Клиенту HTTP Commons был передан сокет на ранней стадии вместе с DefaultHttpClientConnection.bind()
способ.Чего я не понял, так это того, что, по-моему, канал имеет BufferedInputStream
экземпляр, скрытый внутри клиентской реализации HTTP Commons.(8 КБ просто является значением по умолчанию для Java 6.)
Таким образом, мое решение состояло в том, чтобы захватить ReadableByteChannel
с самого начала Socket
пример.