2011-04-19 4 views
1

Я пишу прокси и есть следующий код:Как читать ответ сервера без его блокировки?

Socket conUser; 
Socket conDest; 
try{ 
    ServerSocket ss = new ServerSocket(Integer.parseInt(p.getProperty("proxy.port"))); 
    while(true){ 
     //Connect to user 
     conUser = ss.accept(); 
     BufferedReader inputFromUser = new BufferedReader(new InputStreamReader(conUser.getInputStream())); 
     BufferedWriter outputToUser = new BufferedWriter(new OutputStreamWriter(conUser.getOutputStream(), "UTF8")); 

     //Get user request 
     StringBuffer req = new StringBuffer(); 
     getUserRequest(inputFromUser, req); 
     System.out.println("User requested the following:"); 
     System.out.println(req); 

     //Connect to server 
     InetAddress a = InetAddress.getByName(determineHost(req)); 
     conDest = new Socket(a,80); 

     //Send request to server 
     BufferedWriter outputToServer = new BufferedWriter(new OutputStreamWriter(conDest.getOutputStream(), "UTF8")); 
     InputStreamReader inputFromServer = new InputStreamReader(conDest.getInputStream(), "UTF8"); 
     outputToServer.write(req.toString()); 
     outputToServer.flush(); 

     System.out.println("=============================="); 
     System.out.println("Server replied with the following:"); 
     //Read reply from the server 
     //========================================= 
     int chars; 
       while ((chars = inputFromServer.read()) != -1) { 
        System.out.print((char)chars); 
        outputToUser.write(chars); 
        outputToUser.flush(); 
        //serverReply.append(chars); 
       } 
       //Relay reply to user 
      //outputToUser.write(serverReply.toString()); 
      //System.out.println(serverReply); 
      //outputToUser.flush(); 
     conUser.close(); 
     conDest.close(); 
    } 
} 
catch (Exception e) { 
     System.err.println(e); 
} 

Что происходит: Я установить соединение и успешно. Я также отправляю запрос, и это тоже удается. Я также получаю ответ и могу загрузить HTML всей страницы, за исключением того, что чтение, похоже, не заканчивается, когда оно достигает конца содержимого.

В частности, я пытался загрузить домашнюю страницу Google, и передача с номером, достигнутая 0 (это конец передачи передачи), и, следовательно, не должно было быть больше ввода для чтения, но это не приводило к тому, что цикл прекратить чтение. Для меня также странно, что почти все примеры кода прокси используют этот цикл, и, полагая, что они работают, я не вижу больших различий между своим кодом и моим.

Как сделать петлю закончен правильно?

EDIT: для записи да, я знаю, что TCP-соединение должно оставаться открытым для обработки дальнейших соединений. Это не относится к проблеме, которую я испытываю. Мне нужно, чтобы этот цикл завершился за каждый ответ.

+0

Я полагаю, сервер полагает, что вы захотите сделать другой запрос в том же сокете. Вам либо нужно сказать, что вы не хотите этого делать, либо отключить, когда у вас достаточно данных (он скажет вам, сколько можно ожидать) –

+0

Что произойдет, если вы используете> 0 вместо! = -1? Я не уверен, что это будет работать с read(), но оно должно работать с read (char [], int, int), потому что в последнем случае вы запрашиваете определенное количество символов или все остальное, если доступно меньше. Zero подразумевает, что больше нет - это не совсем то же самое, что «конец потока», но, похоже, работает лучше для меня. – richj

ответ

1

В общем случае соединение не закрыто в конце каждого отклика. Создание TCP-соединений занимает относительно много времени, поэтому соединение остается открытым, готовым для отправки следующего запроса.

Вот несколько пояснительных ссылок:

+0

Да, я знаю о постоянных связях и конвейерной обработке, но это не отвечает на мой вопрос. Я хочу, чтобы соединение было завершено за ответ. – EpsilonVector

+0

Если вы хотите, чтобы соединение прекратилось, ситуация осложнилась, так как вашей программе нужно будет понять больше протокола HTTP. Я вижу два варианта. ** 1) ** Добавьте заголовок «Соединение: закрыть» в запрос, который вы передаете серверу. ** 2) ** Прервать цикл обработки ответа, когда вы прочитали полный ответ (либо прочитать байты длины содержимого, либо больше нет кусков). Тем не менее, вы действительно записываете полный HTTP-прокси, что намного сложнее, чем «эхо-сигнал» сокета. Совет axtavt считает существующие библиотеки хорошими. –

1

Если вы хотите, чтобы правильно завершить соединение после получения ответа HTTP, ваш простой цикл не достаточно. Вы должны определить конец сообщения, как описано в разделе 4.4 «Длина сообщения» RFC 2616, а затем закрыть соединение.

Однако было бы лучше использовать существующие библиотеки, такие как встроенный URLConnection.

Смежные вопросы