Обнаружение разрыва EOF / TCP с использованием сокетов Java из Javascript

Я создаю сокет Java в Javascript, отправляю HTTP-запрос и получаю правильный ответ, но, похоже, я не могу обнаружить EOF или сервер, закрывающий сокет в конце. Что я делаю не так? Проблема в том, что мы никогда не выходим из самого внешнего цикла while - сервер прекращает передачу и (предположительно) закрывает свой конец соединения, но Receiver.read() никогда не возвращает -1, и все методы сокета возвращают состояние, соответствующее тому, что сокет все еще подключен. .

    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 );

person moonshadow    schedule 03.04.2009    source источник


Ответы (4)


Не будет ли это:

      while( receiver.available() && !eof)

быть лучше? вместо первого while(приемник.доступный())?

person Nicolas C    schedule 03.04.2009
comment
Кажется немного избыточным - available() определяется как возвращающее количество байтов данных, доступных для чтения без блокировки, поэтому вернет 0 после EOF. На всякий случай попробовал; не устраняет проблему. - person moonshadow; 03.04.2009
comment
Или вы имеете в виду вместо самого внешнего while? Доступность данных для чтения без блокировки не зависит от того, закрыл ли сервер сокет — могли быть паузы в передаче, а ОС могла буферизовать входные данные. Поэтому мы должны проверить оба по отдельности. - person moonshadow; 03.04.2009
comment
Нет, я имел в виду внутреннее время, но ваш первый комментарий правильный: я не прав. - person Nicolas C; 03.04.2009

В порядке. Каково значение eof, когда код достигает этого комментария?
// в этот момент ответ действительно содержит ожидаемый ответ HTTP

Какой симптом? Я предполагаю, что это бесконечный цикл?

person Nicolas C    schedule 03.04.2009
comment
eof в этот момент по-прежнему равен 0 (иначе мы бы правильно вышли из самого внешнего while(), и я бы не публиковал это). Вопрос отредактирован - надеюсь, теперь проблема яснее? - person moonshadow; 03.04.2009

Хорошо, дальнейшие исследования показывают, что не существует неблокирующего способа узнать, закрыла ли удаленная сторона сокет. Однако добиться этого можно с помощью каналов NIO:

    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 );
person moonshadow    schedule 03.04.2009

Когда достигнут конец потока, available() возвращает 0, поэтому в вашем коде вы никогда не читаете -1

person Maurice Perry    schedule 03.04.2009
comment
Верно. Но read() будет блокироваться до тех пор, пока не будет достигнут EOF или не будет больше данных, а Javascript является однопоточным, поэтому мы не хотим выполнять чтение, не зная наверняка, что у нас есть данные для чтения. Доступный() может возвращать 0 во время передачи, поэтому мы не можем использовать его для проверки EOF. - person moonshadow; 03.04.2009