Как изменить размер внутреннего буфера DataInputStream - PullRequest
0 голосов
/ 01 апреля 2010

Я использую этот тип кода для моего соединения TCP / IP:

sock = new Socket(host, port);
sock.setKeepAlive(true);
din = new DataInputStream(sock.getInputStream());
dout = new DataOutputStream(sock.getOutputStream());

Затем в отдельном потоке я проверяю din.available() байтов, чтобы увидеть, есть ли какие-нибудь входящие пакеты для чтения.

Проблема в том, что если приходит пакет размером более 2048 байт, din.available() возвращает 2048 в любом случае. Так же, как был внутренний буфер 2048. Я не могу прочитать эти 2048 байтов, когда знаю, что это не полный пакет, который ожидает мое приложение. Однако, если я не прочитаю это - все застрянет на 2048 байтах и ​​никогда не получит больше.

Можно ли как-нибудь увеличить размер буфера DataInputStream? Буфер приема сокета равен 16384, возвращаемому sock.getReceiveBufferSize(), поэтому это не сокет, ограничивающий меня 2048 байтами.

Если нет способа увеличить размер буфера DataInputStream - думаю, единственный способ - объявить свой собственный буфер и прочитать все из DataInputStream в этот буфер?

Привет

Ответы [ 5 ]

2 голосов
/ 02 апреля 2010

Я собираюсь сделать предположение о том, что вы называете «пакетом». Я собираюсь предположить, что ваш «пакет» - это некоторая единица работы, передаваемая на ваш сервер. TCP-пакеты Ethernet ограничены 1536 байтами. Неважно, какого размера пишет пиринг.

Таким образом, вы не можете ожидать, что каждый раз будете атомарно читать полную единицу работы. Это просто не произойдет. То, что вы пишете, нужно будет определить, насколько оно велико. Это можно сделать, передав значение заранее, которое сообщает серверу, сколько данных ему следует ожидать.

Учитывая это, подход будет заключаться в том, чтобы поток выполнял блокирующее чтение на din. Просто обработайте данные, когда они станут доступны, пока у вас не будет готового пакета. Затем передайте пакет другому потоку, чтобы обработать сам пакет. (См. ArrayBlockingQueue .)

Ваш поток чтения сокетов будет обрабатывать данные с любой скоростью и степенью детализации. Поток процессора пакетов всегда работает с точки зрения завершенных пакетов.

1 голос
/ 01 апреля 2010

Оберните ваш поток ввода данных вокруг большего буферизованного потока ввода:

DataInputStream din =
  new DataInputStream(
    new BufferedInputStream( sock.getInputStream( ), 4096 )
  );

Но я не думаю, что это поможет вам. Вы должны использовать ввод из сокета, иначе отправитель застрянет.

Возможно, вам стоит потратить больше времени на разработку лучшего протокола связи.

0 голосов
/ 01 июля 2018

Вы не можете. DataInputStream не имеет внутреннего буфера. Вам просто нужно заблокировать в цикле чтения.

0 голосов
/ 01 апреля 2010

Это не то, как вы используете InputStreams. Вы никогда не хотите использовать доступный метод, он практически бесполезен. Если вам нужно прочитать «пакеты» данных, то вам нужно включить их в свой протокол. Один из простых способов сделать это - сначала отправить длину пакета, а затем отправить пакет. получатель считывает длину пакета, а затем читает столько же байтов из потока.

0 голосов
/ 01 апреля 2010

Если вы копаете в источник DataInputStream, getAvailable () фактически делегируется потоку, из которого его считывают, поэтому 2048 приходит из входного потока сокета, а не из DataInputStream (который реализован по умолчанию в собственном коде).

Также имейте в виду, что API-интерфейс для InputStream

Обратите внимание, что в то время как некоторые реализации InputStream вернет сумму количество байтов в потоке, много не буду. Никогда не правильно использовать возвращаемое значение этого метода выделить буфер, предназначенный для хранения всех данные в этом потоке.

То есть, если вы получаете значение 2048, это не означает, что больше нет доступных данных, это просто сумма, которая гарантированно будет прочитана без блокировки. Также обратите внимание, что хотя BufferedInputStream, как предложено Александром, является опцией, это не гарантирует, что буфер будет всегда заполнен (фактически, если вы посмотрите на источник, он только попытается заполнить буфер, когда сделан один из вызовов чтения).

Так что, если вы хотите убедиться, что вы всегда получаете «полные пакеты», вам, вероятно, лучше создать собственную оболочку входного потока, в которую вы можете добавить специальный метод «byte [] readPacket ()», который будет блокировать до тех пор, пока он не сможет заполнить собственный буфер при чтении данных из основного потока сокета.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...