views:

1252

answers:

4

I'm creating a Java socket in Javascript, sending an HTTP request and receiving a response correctly but I seem to be unable to detect an EOF or the server closing the socket at the end. What am I doing wrong? The problem is we never exit the outermost while loop - the server stops transmitting and (presumably) closes its end of the connection, yet receiver.read() never returns -1 and all the socket methods return state consistent with the socket still being connected.

    var s = new java.net.Socket("www.google.com",80);
    var sender = new java.io.PrintStream(s.getOutputStream());
    var receiver = s.getInputStream();
    sender.print("GET / HTTP/1.0\r\n\r\n");
    sender.flush();
    s.shutdownOutput();
    var response = '';
    var eof = 0;
    while( !eof && s.isConnected() && s.isBound() && !s.isClosed() && !s.isInputShutdown() )
    {  
       if( receiver.available() )
       {
        while( receiver.available() )
        {
         var i = receiver.read();
         if( i == -1 ) { eof = 1; }
         else { response += String.fromCharCode(i); }
        }
        // at this point response does contain the expected HTTP response
       }
    }

    // in case remote end closed the socket before we got a chance to read all the bytes from it        
    // ...but this is never reached!
    while( receiver.available() )
    { 
      response += String.fromCharCode(receiver.read());
    }

    alert( response );
A: 
Nicolas
Seems a bit redundant - available() is defined as returning the number of bytes of data available to read without blocking, so would return 0 after EOF. Tried it anyway just in case; doesn't fix the problem.
moonshadow
Or do you mean in place of the outermost while? Data being available to read without blocking is independent of whether the server has closed the socket - there could be pauses in transmission, and the OS could have buffered input data. So we must test both separately.
moonshadow
No, I meant the inner while, but your first comment is right: I'm wrong.
Nicolas
A: 

Ok. What's the value of eof when the code reaches this comment?
// at this point response does contain the expected HTTP response

What's the symptom? I assume it's an infinite loop?

Nicolas
eof is still 0 at that point (otherwise we'd exit the outermost while() correctly and I'd not be posting this). Question edited - hopefully the problem is clearer now?
moonshadow
A: 

OK, further research suggests there is no non-blocking way to discover whether the remote side has closed a socket. However, it is possible to achieve this using NIO channels:

    var s = new java.nio.channels.SocketChannel.open(new java.net.InetSocketAddress( "www.google.com",80) );
    //ew, but while we're prototyping...
    s.configureBlocking(true); 
    var sender = new java.io.PrintStream(s.socket().getOutputStream());
    sender.print("GET / HTTP/1.0\r\n\r\n");
    sender.flush();

    s.configureBlocking(false); // yayy!

    var response = '';
    var len = 0;
    var dbuf = java.nio.ByteBuffer.allocate( 1024 );
    while( len >= 0 )
    {    
         len = s.read( dbuf );
         dbuf.flip();
         while( dbuf.hasRemaining() )
         { 
           response += String.fromCharCode( dbuf.get() );
         }
         dbuf.clear();
    }

    alert( response );
moonshadow
A: 

When the end of the stream is reached, available() returns 0, so in your code, you never read the -1

Maurice Perry
Right. But read() will block until either EOF is reached or there is more data, and Javascript is single-threaded so we don't want to issue a read without knowing for certain we have data to read. And available() can return 0 during transmission, so we can't use that to test for EOF.
moonshadow