Как читать поток Java, пока не будет достигнут определенный байт - PullRequest
3 голосов
/ 17 августа 2010

Мой вопрос похож на этот пост.Но я не посылаю длину пакета, а 0 байт в конце. Самый эффективный способ чтения в потоке tcp в Java

Так что мне интересно, как бы я закодировал что-нибудь такое.

На данный момент я просто использую

this.socketIn = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
String line = this.socketIn.readLine();

Если пакет отправляется во время рассылки спама, он будет считать пакет, который еще не поступил, как полностью прочитанную строку, но он не завершен и испортил весь протокол.

В моем протоколе каждый пакет заканчивается 0 байтом (0x00), чтобы определить конец одного пакета, если в случае, когда пакеты в конечном итоге объединены / сложены вместе.

Итак, что я пытаюсь сделать на самом делепродолжать читать поток сокетов до тех пор, пока не будет достигнуто значение 0x00, чтобы указать, что пакет полностью обработан и готов к обработке ... и, конечно, некоторая защита (тайм-аут лучше, я считаю) для определения того, что пакет является нежелательным, поскольку он не завершен в0 байт за определенный промежуток времени, скажем, 5 секунд.

Как бы я поступил так?

PS> Я не использую инфраструктуру NIO, а просто обычный поток для каждого сокета подключения, и я не хочу переключаться на NIO, поскольку очень трудно внедрить данные в совершенно другой глобальный поток, который обрабатывает обновления иотправляет конкретные обновления случайным пользователям (не транслируется).

Вот что я пробовал до сих пор.

    String line = "";
    int read;
    long timeOut = System.currentTimeMillis();
    while(true) {
        read = this.socketIn.read();
        if (read == -1 || read == 0 || (System.currentTimeMillis()-timeOut) > 5000)
            break;
        line += read
    }

Ответы [ 3 ]

5 голосов
/ 17 августа 2010

Вот эскиз, использующий setSocketTimeout для решения сценария «медленный клиент / отказ в обслуживании».

this.socket.setSoTimeout(5000);
BufferedReader br = new BufferedReader(
    new InputStreamReader(this.socket.getInputStream()));
StringBuilder sb = new StringBuilder();
try {
    int ch ;
    while ((ch == br.read()) != -1) {
        if (ch == 0) {
            String message = sb.toString();
            // process message
            sb.setLength(0);
        } else {
            sb.append((char) ch);
        }
    }
} catch (InterruptedIOException ex) {
    System.err.println("timeout!"); 
    ...
} finally {
    br.close();
}

Я думаю, что также возможно реализовать (зверское) время ожидания сокета, создав второй поток, который вызывает socket.close() объекта сокета, если он обнаруживает, что поток чтения не получает никаких данных. Но это тяжелый подход, учитывая более простой подход setSoTimeout().

2 голосов
/ 17 августа 2012
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader in = new BufferedReader(isr);
String line = "";
String response = "";
while ((line = in.readLine()) != null) {
    System.out.println(line);
    response = response + line + "\n";
    if (in.ready() == false) {
        break;
    }
}

Хитрость - это функция готовности, которая принадлежит BufferedReader.Вам нужно проверить, готово ли оно, а не просто выйти из цикла.

0 голосов
/ 17 августа 2010

Должен ли я использовать StringBuilder? или построй свой, как писал EJP. что быстрее?

            String line = "";
            int read;
            //long timeOut = System.currentTimeMillis();
            this.socket.setSoTimeout(5000);
            while(this.socket.isConnected()) {
            read = this.socketIn.read();
            if (read == -1)
                throw new IOException("Insufficient data / timeout)");
            else if(read == 0)
                break;
            line += (char)(read & 0xFF);
            }
...