2015-03-06 2 views
0

Я новичок в Java, и я пишу HTTP-клиент, который извлекает содержимое HTML из URL-адреса и записывает этот ответ в файл. После этого все изображения запрошенной веб-страницы также должны храниться локально.Java-сокет HTTPClient: с использованием двух входных потоков

Я написал функцию, которая создает новый запрос, функцию для извлечения HTML-файла и функции для извлечения изображений. К сожалению, я не могу получить изображения; они не записываются и не хранятся в местоположении.

Я думаю, проблема в том, что я использую два разных входных потока. Как мне переписать мой код, чтобы решить эту проблему? Мне не разрешено использовать функцию OpenStream() у моего инструктора: это должно произойти с помощью ручного запроса GET.

Заранее спасибо.

private static String createRequest(URL url, String httpCmd, 
     boolean version1_1) { 
    StringBuilder sb = new StringBuilder(); 
    sb.append(httpCmd.toUpperCase()); 
    sb.append(' '); 
    String path = url.getPath(); 
    if (!path.startsWith("/")) { 
     path = "/" + path; 
    } 
    sb.append(path); 
    if (version1_1) { 
     sb.append(" HTTP/1.1\r\n"); 
     sb.append("Host: "); 
     sb.append(url.getHost()); 
     sb.append("\r\n"); 
    } else { 
     sb.append(" HTTP/1.0\r\n"); 
    } 
    sb.append("\r\n"); 
    return sb.toString(); 
} 





public void retrieveFile(String htppCommand, String url, int port, 
     String htppversion) throws IOException { 

    Socket s = new Socket(); 

    URL u; 
    if (url.startsWith("http://")) { 
     u = new URL(url); 
    } else { 
     u = new URL("http://" + url); 
    } 

    try { 
     s.connect(new InetSocketAddress(u.getHost(), port)); 
     PrintWriter pw = new PrintWriter(s.getOutputStream(), true); 

     DataInputStream in = new DataInputStream(s.getInputStream()); 
     FileOutputStream out = new FileOutputStream("../output.html"); 

     byte[] data = new byte[4096]; 

     pw.print(createRequest(u, htppCommand, true)); 
     pw.flush(); 


     int length; 
     int imagenumber = 0; 

     while ((length = in.read(data)) != -1) { 

      System.out.println(new String(data)); 
      out.write(data, 0, length); 

      Document doc = Jsoup.parse(new String(data)); 
      Elements images = doc 
        .select("img[src~=(?i)\\.(png|jpe?g|gif)]"); 

      for (Element image : images) { 

       imagenumber++; 
       retrieveImage(image.attr("src"), s, imagenumber); 

      } 

     } 

     pw.close(); 
     in.close(); 
     out.close(); 

    } 
    // Host not found 
    catch (UnknownHostException e) { 
     if (s != null) 
      s.close(); 
     System.err.println("Host not found: " + url); 
     System.exit(1); 
     return; 
    } 

    // ------------------------------------------------------------------------------ 

    // close the socket 
    s.close(); 

} 



public void retrieveImage(String imageurl, Socket s, int imagenumber) 
     throws IOException { 

    String extension = ""; 

    // System.out.println(image); 
    if (imageurl.contains(".jpg")) { 
     extension = ".jpg"; 

    } else { 

     if (imageurl.contains(".png")) { 

      extension = ".png"; 

     } 

     else { 
      extension = ".gif"; 

     } 
    } 

    String path = "../image" + imagenumber + extension; 

    URL myurl = new URL(imageurl); 

    DataInputStream is = new DataInputStream(s.getInputStream()); 

    PrintWriter printer = new PrintWriter(s.getOutputStream(), true); 
    OutputStream os = new FileOutputStream(path); 
    printer.print(createRequest(myurl, "GET", true)); 
    printer.flush(); 

    int length = 0; 

    byte[] b = new byte[4096]; 

    while ((length = is.read(b)) != -1) { 

     os.write(b, 0, length); 

    } 

    is.close(); 
    os.close(); 

} 

ответ

0

Скорее всего, проблема в том, что вы пытаетесь повторно использовать сокет из первого запроса. В классическом запросе-ответе вы должны закрыть сокет после получения ответа и создать новый сокет для другого запроса. Вы, вероятно, не хотите связываться с соединениями Keep-Alive только для домашней работы. Для простоты каждый ваш HTTP-запрос должен открыть новый сокет и, следовательно, иметь собственный InputStream. Кроме того, не должно быть разницы между тем, как делается запрос между самой страницей html и изображениями.

Таким образом, для каждого запроса:

  • Открыть новый сокет с хост/порт
  • Открыть входной поток и написать запрос в это
  • получить ответ через выходной поток сокета
  • Закрыть ввода и выходные потоки
  • Замкнутое гнездовое соединение

Надеюсь, что это поможет.

+0

Почему так сложно? Используйте Apache HttpClient. –

+0

@ Michael-O это его назначение для реализации http-клиента. – dimoniy

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