2014-11-19 4 views
1

Я пытался реализовать простой клиент http с помощью Java Socket. В моей программе я запрашиваю изображение с сервера и пытаюсь скопировать требуемый образ JPEG на локальный компьютер. Мне удалось создать запрос и получить желаемый контент. Я также разделил заголовок ответа и содержимое. Но проблема в том, что я пишу байты с использованием FileOutputStream в файл .jpeg, и после записи, когда вы открываете файл в средстве просмотра изображений (например, picasa), изображение кажется недействительным. Вот мой весь код. Может ли кто-нибудь рассказать мне, что не так с кодом? Почему изображение недействительно?Как загрузить изображение с помощью Java Socket с удаленного сервера Http?

import java.io.BufferedInputStream; 
import java.io.BufferedReader; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.Socket; 

import sun.misc.IOUtils; 


public class ImageCopy { 
    public static void main(String args[]) throws IOException{ 
       String host = "www.uni-koblenz-landau.de"; //declare the host name 
       String resourceLoc = "/images/starts-c-ko.jpg"; //declare the specific pagename of get 
       HttpRequester req = new HttpRequester(); 
       req.request(host, resourceLoc); //send the request mentiong the host and pagename 


    } 
    } 

class HttpRequester{ 
    public void request(String host, String resourceLoc) throws IOException{ 
     Socket httpSocket = new Socket(host, 80); //create the request for port 80 
     PrintWriter writer = new PrintWriter(httpSocket.getOutputStream()); 
     FileOutputStream foutStream = new FileOutputStream("E:\\quora.jpeg"); //creating file to hold the output stream 

     // building the header fields 
     String protocol = "GET /" +resourceLoc+" HTTP/1.1"; 
     String connection ="Connection: close"; 
     String acceptedLanguage ="Accept-Language: de,en;q=0.7,en-us;q=0.3"; 
     String headerEnd = ""; 
     String HostHeader = "Host: www.uni-koblenz-landau.de"; 

     // writing the headers to the outputstream 

     writer.println(protocol); 
     writer.println(HostHeader); 
     writer.println(connection); 
     writer.println(acceptedLanguage); 
     writer.println(headerEnd); 

     writer.flush(); 

     // request sent 

     BufferedInputStream reader = new BufferedInputStream(httpSocket.getInputStream()); 

     InputStream is; 

     int byteCode =0; 
     char ch ; 
      StringBuilder builder = new StringBuilder(); 

     while((byteCode=reader.read())!=-1) 
     { 
      builder.append((char)byteCode); 
      // System.out.print((char)byteCode); 

     } 

     String text = builder.toString(); 
     // sub[0] is supposed to contain the header and sub[1] should contain the bytes of the   image 

     String[] sub = text.split("\r\n\r\n"); 
     System.out.println(sub[0]); 

     byte[] byts = sub[1].getBytes(); 

     for(int i=0;i<byts.length;i++){ 
      foutStream.write(byteCode); 
     } 
     System.out.println(byts.length); 
    } 

} 
+0

, вероятно, не ошибка, но вы не закрывающие foutStream. – SteveL

+0

Зачем использовать гнездо? Почему бы не HttpURLConnection? – EJP

ответ

1

Пожалуйста, попробуйте этот рабочий код первым:

import java.io.FileOutputStream; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.HttpURLConnection; 
import java.net.URL; 

public class URLTest { 

    private static void sendGet() throws Exception { 

    String url = "http://www.uni-koblenz-landau.de/images/starts-c-ko.jpg"; 

    URL obj = new URL(url); 
    HttpURLConnection con = (HttpURLConnection) obj.openConnection(); 

    // optional default is GET 
    con.setRequestMethod("GET"); 

    //add request header 
    con.setRequestProperty("User-Agent", "Mozilla/5.0"); 

    int responseCode = con.getResponseCode(); 
    System.out.println("\nSending 'GET' request to URL : " + url); 
    System.out.println("Response Code : " + responseCode); 

    InputStream in = con.getInputStream(); 
    OutputStream out = new FileOutputStream("/Users/ravikiran/Desktop/abc.jpg"); 
    try { 
     byte[] bytes = new byte[2048]; 
     int length; 

     while ((length = in.read(bytes)) != -1) { 
     out.write(bytes, 0, length); 
     } 
    } finally { 
     in.close(); 
     out.close(); 
    } 
    } 

    public static void main(String[] args) throws Exception { 
    sendGet(); 
    } 
} 
+0

Вы должны напечатать 'отправка ...' * до * получения кода ответа. В тот момент, когда вы печатаете его здесь, он уже отправлен. – EJP

0

Есть по крайней мере, 2 проблемы в показанном коде. Во-первых тривиальна, ближе к концу программы у вас есть:

byte[] byts = sub[1].getBytes(); 

    for(int i=0;i<byts.length;i++){ 
     foutStream.write(byteCode); 
    } 

Я думаю foutStream.write(byts[i]); должно быть лучше.

Второй более тонкий. Вы получаете байты, конвертируете их как char в построитель строк, а затем возвращаете их в виде байтов. Это не работает, как ожидалось для байтовых значений> = 128.

Я только что сделал этот маленький тест:

public class ByteCharTest { 
    @Test 
    public void test1() { 
     byte[] bytes = new byte[]{ 'x', (byte) 0xc3, (byte) 0xa9, 
      (byte) 0xc3, (byte) 0xa8, 'y', (byte) 0xe9, (byte) 0xe8, 'z'}; 
     StringBuilder sb = new StringBuilder(); 
     for(byte b: bytes) { 
      sb.append((char) b); 
     } 
     String s = sb.toString(); 
     byte[] byte2 = s.getBytes(); 
     assertEquals(bytes.length, byte2.length); 
     for(int i=0; i<bytes.length; i++) { 
      assertEquals(bytes[i], byte2[i]); 
     } 
    } 
} 

И это ломает. Под отладчиком, строка s является «х \ uffce \ uffa9 \ uffc3 \ uffa9y \ uffe9 \ uffe8z», так как преобразование байта на символ распространяется знаковый бит и byte2 является x????y??z

Тест работает, если StringBuilder подается:

  sb.append((char) (((int) b) && 0xff)); 

Так что в вашем коде, вы должны иметь:

while((byteCode=reader.read())!=-1) 
    { 
     builder.append((char) (((int) byteCode) && 0xff)); 
     // System.out.print((char)byteCode); 
    } 

Просто объяснить исследуемые байт, 0xc3 0xa9 и 0xc3 0xa8 являются UTF-8 кодов для éè и 0xe8 0xe9 являются Latin 1 коды éè ...

+1

Он не должен использовать строковый или строковый построитель вообще. Они не являются контейнерами для двоичных данных. Не гарантируется обратный путь между байтом, символом и байтом. – EJP

-1

решение, которое на самом деле подходит ваш вопрос:

// Initialize the stream. 
final InputStream inputStream = socket.getInputStream(); 

// Header end flag. 
boolean headerEnded = false; 

byte[] bytes = new byte[2048]; 
int length; 
while ((length = inputStream.read(bytes)) != -1) { 
    // If the end of the header had already been reached, write the bytes to the file as normal. 
    if (headerEnded) 
     foutStream.write(bytes, 0, length); 

    // This locates the end of the header by comparing the current byte as well as the next 3 bytes 
    // with the HTTP header end "\r\n\r\n" (which in integer representation would be 13 10 13 10). 
    // If the end of the header is reached, the flag is set to true and the remaining data in the 
    // currently buffered byte array is written into the file. 
    else { 
     for (int i = 0; i < 2045; i++) { 
      if (bytes[i] == 13 && bytes[i + 1] == 10 && bytes[i + 2] == 13 && bytes[i + 3] == 10) { 
       headerEnded = true; 
       foutputStream.write(bytes, i+4, 2048-i-4); 
       break; 
      } 
     } 
    } 
} 
inputStream.close(); 
foutStream.close(); 
+0

Хотя это может быть способ пойти, эта реализация должна привести к незаконному исключению в некоторых случаях. байт [] bytes = новый байт [2048]; ... для (INT I = 0; я <2048; я ++) { ... вы получите доступ к байт [я + 3] –

+0

Это плохая реализация качества предполагает, что 'чтения()' заполняет буфер, и что оба терминатора линии принимаются в одном вызове чтения. – EJP

+0

@ EJP HTTP-заголовок имеет ограниченный размер. Отрегулируйте буфер до любого размера, наиболее подходящего вашему случаю.«Плохое качество реализации» означает, что есть более качественные. Я не видел других реализаций, когда я сам столкнулся с этой проблемой. – Alexay

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

  • Нет связанных вопросов^_^