0

I am writting a simple HTTP server using Java NIO but got stuck quiet early. I have the following code:

Selector accept = Selector.open();
            ServerSocketChannel ssc = ServerSocketChannel.open();
            ssc.configureBlocking(false);

            InetAddress lh = InetAddress.getByName("127.0.0.1");
            InetSocketAddress isa = new InetSocketAddress(lh, port);
            ssc.socket().bind(isa);
            SelectionKey acceptKey = ssc.register(accept,
                    SelectionKey.OP_ACCEPT);

            while (accept.select() > 0) {
                Set<SelectionKey> readyKeys = accept.selectedKeys();
                Iterator<SelectionKey> i = readyKeys.iterator();

                while (i.hasNext()) {
                    SelectionKey sk = i.next();
                    if (sk.isAcceptable()) {
                        System.out.println("Is acceptable");
                        ssc = (ServerSocketChannel) sk.channel();
                        SocketChannel sc = ssc.accept();
                        sc.configureBlocking(false);
                        sc.register(accept, SelectionKey.OP_READ);
                        System.out.println("Registered new SocketChannel");
                    }
                    if (sk.isReadable()) {
                        SocketChannel sc = (SocketChannel) sk.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(20000);
                        buffer.clear();
                        int bytesRead = sc.read(buffer);
                        buffer.flip();

                        while (buffer.hasRemaining()) {
                            System.out.print((char) buffer.get());
                        }

                        buffer.clear();
                    }
                    i.remove();
                }
            }

Now if I open two tabs in a browser and navigate to localhost:8080 this will be the output of the application:

Is acceptable
Registered new SocketChannel
Is acceptable
Registered new SocketChannel
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8

Is acceptable
Registered new SocketChannel

Now I have two questions: 1) Why do I get an extra accept event at the beginning? 2) Why the second http request is not received? The connection is accepted, its SocketChannel is being registered within the selector. But the request body is not received. I know that there are many "empty" read events generated but none of them brings the request body.

Janek
  • 1,441
  • 2
  • 19
  • 28

2 Answers2

1
  1. You have three accept events.
  2. Possibly because you haven't responded to the first one.
  3. The 'empty' read events are probably closes, which you are ignoring.

Try fixing all this and retesting. You can't expect the peer to behave itself when you're not.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Thanks. 1. Where does the 3rd accept event come from? I did 2 http requests and I would expect that each triggers exactly one accept event. 2. Why? I thought that these two requests are independent from each other and responding or ignoring does not affect the second one. – Janek Jun 10 '13 at 05:40
  • 1. The browser. You could always print the channel's remote socket address and see for yourself. 2. I don't know why but my final sentence still applies. – user207421 Jun 10 '13 at 05:43
1
  1. Why do I get an extra accept event at the beginning?

    • This will occur only if you initiate the request from browser.
    • If you create connection using simple socket/http client you will receive only one accept request. (Though you need to modify your read code to close socket when read returns -1).
  2. Why the second http request is not received?

  3. Check this behaviour in IE

    • Modify your code to handle exception while performing read when connection is closed (in catch block sc.close() and sk.cancel())
    • Initiate the request from IE
    • Two accept + one read received
    • In IE cancel the request
    • Wait some time and initiate the request again in same tab
    • Only one read is received, no accept request
    • Now again go to same tab and cancel the request
    • Now again initiate request from same tab
    • Same two accept + one read
    • Above leads me to believe #2 point that second connection might be created for backup purpose
Community
  • 1
  • 1
Snehal Patel
  • 819
  • 6
  • 9
  • There is no 'exception when the socket is closed' in the OP's code. `read()` returns -1. Closing a channel cancels all its keys: you don't need to do both. – user207421 Jun 10 '13 at 10:00
  • When socket is properly closed then there won't be any exception but if you cancel the request then read method will throw exception. – Snehal Patel Jun 10 '13 at 12:06
  • Thanks. So the question 1 is closed. The second is still puzzling me. I got a new observation. If I open the localhost:8080 from two different browsers then I do receive two http get requests. – Janek Jun 10 '13 at 18:18
  • Did a bit more experiments. I created a different http "server" using standard Java sockets and the behaviour is exactly the same. Only one request is being received from a browser. Requests from two different browsers will be received as expected. – Janek Jun 10 '13 at 21:11