Java: правильная обработка сетевого ввода-вывода? - PullRequest
0 голосов
/ 01 марта 2010

У меня проблема в том, что когда я использую InputStream для чтения байтов, он блокируется, пока соединение не будет установлено. EG:

        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[20000];
        while (is.read(buffer) != -1) {
            System.out.println("reading");
        }
        System.out.println("socket read");

«чтение с сокета» не распечатывается до тех пор, пока пакет FYN фактически не будет получен, закрывая соединение. Как правильно получить все байты без блокировки и ожидания разрыва соединения?

Ответы [ 6 ]

2 голосов
/ 01 марта 2010

Чтение до получения -1 означает , который вы хотите прочитать до EOS. Если вы не хотите читать до EOS, не зацикливайтесь до -1: остановитесь раньше. Вопрос «когда?»

Если вы хотите прочитать полное «сообщение» и не более, вы должны отправить сообщение таким образом, чтобы читатель мог найти его конец: например, протокол типа длина-длина или, более просто, размер слово перед каждым сообщением или протокол с самоописанием, такой как XML.

2 голосов
/ 01 марта 2010

С традиционными сокетами дело в том, что обычно вы делаете хотите, чтобы они блокировались: то, что вы делаете, когда логически не хотите, чтобы ваша программа блокировала, - вы помещаете код чтения / записи в другой поток, так что отдельный поток чтения / записи блокирует, но не всю вашу программу.

В противном случае вы можете использовать метод available (), чтобы увидеть, есть ли какие-либо входные данные перед чтением. Но тогда вы должны быть осторожны, чтобы не сидеть в цикле с горящим процессором, постоянно вызывая available ().

Редактировать: если проблема в том, что вы счастливы блокировать до тех пор, пока не придут байты , но не до тех пор, пока не разорвется соединение (и это происходит), то вам нужно сделать клиент на другом конце вызывает flush () в своем выходном потоке после отправки байтов.

2 голосов
/ 01 марта 2010

Взгляните на java.nio , который имеет неблокирующую поддержку IO .

1 голос
/ 01 марта 2010

код, вероятно, не делает то, что вы думаете, что он делает. read (buffer) возвращает количество прочитанных байтов, другими словами: это не гарантирует заполнение вашего буфера в любом случае. См. DataInputStream.readFully () для кода, который заполняет весь массив:

или вы можете использовать следующие функции (основанные на DataInputStream.readFully ()):

public final void readFully(InputStream in, byte b[]) throws IOException
{
    readFully(in, b, 0, b.length);
}

public final void readFully(InputStream in, byte b[], int off, int len) throws IOException
{
    if (len < 0) throw new IndexOutOfBoundsException();
    int n = 0;
    while (n < len)
    {
        int count = in.read(b, off + n, len - n);
        if (count < 0) throw new EOFException();
        n += count;
    }
}

Ваш код будет выглядеть так:

InputStream is = socket.getInputStream();
byte[] buffer = new byte[20000];
readFully(is, buffer);
System.out.println("socket read");
1 голос
/ 01 марта 2010

Попробуйте это:

        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[20000];
        int bytesRead;
        do {
            System.out.println("reading");
            bytesRead = is.read(buffer);
        }
        while (is.available() > 0 && bytesRead != -1);
        System.out.println("socket read");

Подробнее: http://java.sun.com/j2se/1.4.2/docs/api/java/io/InputStream.html#available()

1 голос
/ 01 марта 2010

Пример взят из exampledepot на java.nio

// Create a direct buffer to get bytes from socket.
// Direct buffers should be long-lived and be reused as much as possible.
ByteBuffer buf = ByteBuffer.allocateDirect(1024);

try {
    // Clear the buffer and read bytes from socket
    buf.clear();
    int numBytesRead = socketChannel.read(buf);

    if (numBytesRead == -1) {
        // No more bytes can be read from the channel
        socketChannel.close();
    } else {
        // To read the bytes, flip the buffer
        buf.flip();

        // Read the bytes from the buffer ...;
        // see Getting Bytes from a ByteBuffer
    }
} catch (IOException e) {
    // Connection may have been closed
}

Убедитесь, что понимаете переворачивание буфера, потому что это вызывает много головной боли. По сути, вы должны обратить свой буфер, чтобы прочитать из него. Если вы хотите повторно использовать этот буфер, чтобы иметь сокет для записи в него, вы должны перевернуть его снова. Однако clear () сбрасывает направление буфера.

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