Java InputStream ожидает данных. - PullRequest
9 голосов
/ 12 марта 2012

Я разрабатываю приложение Сервер-Клиент, и у меня проблема с ожиданием ввода данных в потоке ввода.

У меня есть тема, предназначенная для чтения входных данных. В настоящее время используется цикл while для удержания до тех пор, пока данные не станут доступны. (Протокол N.B. следующий: отправьте размер пакета, скажем N, как int, затем отправьте N байтов).

public void run(){
    //some initialization
    InputStream inStream = sock.getInputStream();
    byte[] packetData;
    //some more stuff
    while(!interrupted){
        while(inStream.available()==0);
        packetData = new byte[inStream.read()];
        while(inStream.available()<packetData.length);
        inStream.read(packetData,0,packetData.length);
        //send packet for procession in other thread
    }
}

Это работает, но блокировка потока с помощью цикла while - это плохая идея. Я мог бы использовать Thread.sleep (X) для предотвращения непрерывного потребления ресурсов циклом, но, безусловно, должен быть лучший способ.

Также я не могу полагаться на InputStream.read, чтобы блокировать поток, поскольку часть данных может быть отправлена ​​сервером с задержками. Я пытался, но это всегда приводило к неожиданному поведению.

Буду признателен за любые идеи:)

Ответы [ 2 ]

12 голосов
/ 12 марта 2012

Вы можете использовать DataInputStream.readFully ()

DataInputStream in = new DataInputStream(sock.getInputStream());
//some more stuff
while(!interrupted) {
    // readInt allows lengths of up to 2 GB instead of limited to 127 bytes.
    byte[] packetData = new byte[in.readInt()];
    in.readFully(packetData);
    //send packet for procession in other thread
}

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

SocketChannel sc = 
ByteBuffer bb = ByteBuffer.allocateDirect(1024 *1024); // off heap memory.

while(!Thread.currentThread.isInterrupted()) {
     readLength(bb, 4);
     int length = bb.getInt(0);
     if (length > bb.capacity()) 
         bb = ByteBuffer.allocateDirect(length);
     readLength(bb, length);
     bb.flip();
     // process buffer.
}



static void readLength(ByteBuffer bb, int length) throws EOFException {
     bb.clear();
     bb.limit(length);
     while(bb.remaining() > 0 && sc.read(bb) > 0);
     if (bb.remaining() > 0) throw new EOFException();
}
4 голосов
/ 12 марта 2012

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

Просто используйте обычный read для чтения всего, что доступно, но только отправьте пакет для обработки в другом потоке , как только в вашем буфере будет packetData.length байт ...

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