ReadableByteChannel.read (ByteBuffer dest) читает с ограничением 8 КБ. Зачем? - PullRequest
1 голос
/ 15 сентября 2010

У меня есть код, который:

  1. читает из ReadableByteChannel в ByteBuffer,
  2. принимает к сведению переданные байты,
  3. делает паузу от нескольких десятков до сотен миллисекунд,
  4. передает ByteBuffer на WritableByteChannel.

Некоторые детали:

  • Оба канала являются сокетами TCP / IP.
  • Общий размер чтения подключения составляет десятки мегабайт.
  • Исходный сокет (из которого ReadableByteChannel получает байты) находится на том же компьютере.
  • 64-разрядная версия Debian Lenny для HP DL380s
  • обновление Sun Java 1.6.0 20

Проблема заключается в том, какой бы ни был большой размер байт-буфера: .allocate() или .allocateDirect(), число байтов, считываемых в ByteBuffer, достигает 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 такого не должно быть.Было бы нежелательно «переходить на более ранние версии» решения, основанного на потоке, хотя именно в этом случае мы пойдем дальше, если решение не может быть найдено.

Чего мне не хватает?Что я могу сделать, чтобы исправить это?

1 Ответ

0 голосов
/ 16 сентября 2010

ОК, я нашел проблему! (И я отвечу на свой вопрос на случай, если у кого-то возникнет такая же проблема.)

Я копировал ReadableByteChannel не непосредственно из экземпляра Socket, а из HttpEntity.getContent() ( Apache HTTP Commons Client ), возвращенного InputStream. Клиенту HTTP Commons был передан сокет с самого начала методом DefaultHttpClientConnection.bind(). То, что я не понял, я думаю, что Канал имеет экземпляр BufferedInputStream, скрытый внутри реализации клиента HTTP Commons. (8 КБ просто является значением по умолчанию для Java 6.)

Поэтому мое решение заключалось в том, чтобы извлечь ReadableByteChannel из необработанного Socket экземпляра.

...