Java NIO: соединение принудительно закрыто - PullRequest
0 голосов
/ 08 июля 2011

Я пытался реализовать простой HTTP-клиент, используя Java NIO. Но я получаю ошибку, что соединение было принудительно закрыто удаленным хостом до того, как все данные были прочитаны. С обычными розетками все отлично работает.

Вот пример:

private static final String REQUEST = "GET / HTTP/1.1\r\nHost: stackoverflow.com\r\n\r\n";

void channel() {
    try {
        SocketChannel sc = SocketChannel.open(new InetSocketAddress("stackoverflow.com", 80));
        while (!sc.isConnected()) {
        }

        ByteBuffer buf = ByteBuffer.allocate(16*1024);
        buf.put(REQUEST.getBytes());
        buf.rewind();
        sc.write(buf);

        buf.rewind();
        while (sc.read(buf) > 0) {
            buf.rewind();
            System.out.println(new String(buf.array()));
            buf.clear();
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}

void socket() {
    try {
        Socket s = new Socket("stackoverflow.com", 80);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));

        out.write(REQUEST);
        out.flush();

        String l;
        while ((l = in.readLine()) != null) {
            System.out.println(l);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    // Works:
    new Test().socket();
    // Exception:
    new Test().channel();
}

Это исключение, которое я получаю:

java.io.IOException: An existing connection was forcibly closed by the remote host
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(Unknown Source)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
at sun.nio.ch.IOUtil.read(Unknown Source)
at sun.nio.ch.SocketChannelImpl.read(Unknown Source)
at at.maph.tlsproxy.client.Test.channel(Test.java:39)
at at.maph.tlsproxy.client.Test.main(Test.java:70)

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

1 Ответ

0 голосов
/ 13 сентября 2011

Хорошо, теперь я понял это после проверки возвращаемого значения write(), которое было 16,384, поэтому случайные данные были отправлены на сервер.Проблема была в вызове rewind в буфере, вместо этого необходимо использовать flip:

void channel() {
    try {
        SocketChannel sc = SocketChannel.open(new InetSocketAddress("stackoverflow.com", 80));

        ByteBuffer buf = ByteBuffer.allocate(16*1024);
        buf.put(REQUEST.getBytes());
        buf.flip();     // <--------- Here
        sc.write(buf);

        buf.rewind();
        while (sc.read(buf) > 0) {
            buf.flip();   // <------- And here
            System.out.println(new String(buf.array()));
            buf.clear();
        }

    } catch (IOException e) {
        e.printStackTrace();
    }
}
...