2013-07-15 4 views
1

상당히 복잡한 Java 서버의 업로드 시스템을 작성하려고합니다. 아래에 나열된 두 개의 작은 프로그램에서 오류를 재현했습니다. 기본적으로 ObjectOutputStream/ObjectInputStream을 사용하여 클라이언트/서버를 통해 통신합니다. 이것은 필수 사항입니다. 이 ObjectOutputStream/ObjectInputStream 설정에 대해 수천 줄의 코드가 완벽하게 작동하므로 업로드가 완료된 후에도이 스트림을 계속 사용할 수 있어야합니다.Java에서 objectoutputstream에 바이트 배열을 전송하는 데 문제가 발생했습니다.

파일 (클라이언트에서 읽는 파일과 서버에서 쓰는 파일)에 액세스하려면 FileInputStream 및 FileOutputStream이 사용됩니다. 내 클라이언트 은 완벽하게 작동하려면으로 나타납니다. 파일을 읽고 각 반복마다 다른 바이트 배열을 보냅니다 (한번에 1MB를 읽으므로 큰 파일은 힙을 오버플로하지 않고 처리 할 수 ​​있습니다). 그러나 서버에서 바이트 배열은 항상 첫 번째 배열 (파일의 첫 번째 1MB) 만있는 것처럼 보입니다. 이것은 ObjectInputStream/ObjectOutputStream에 대한 나의 이해와 일치하지 않습니다. 나는이 문제에 대한 해결책을 찾거나 내 자신의 해결책을 형성하기에 충분한 교육을 찾고있다.

다음은 클라이언트 코드 :

import java.net.*; 
import java.io.*; 

public class stupidClient 
{ 
    public static void main(String[] args) 
    { 
    new stupidClient(); 
    } 

    public stupidClient() 
    { 
    try 
    { 
     Socket s = new Socket("127.0.0.1",2013);//connect 
     ObjectOutputStream output = new ObjectOutputStream(s.getOutputStream());//init stream 

     //file to be uploaded 
     File file = new File("C:\\Work\\radio\\upload\\(Op. 9) Nocturne No. 1 in Bb Minor.mp3"); 
     long fileSize = file.length(); 
     output.writeObject(file.getName() + "|" + fileSize);//send name and size to server 

     FileInputStream fis = new FileInputStream(file);//open file 
     byte[] buffer = new byte[1024*1024];//prepare 1MB buffer 
     int retVal = fis.read(buffer);//grab first MB of file 
     int counter = 0;//used to track progress through upload 

     while (retVal!=-1)//until EOF is reached 
     { 
     System.out.println(Math.round(100*counter/fileSize)+"%");//show current progress to system.out 
     counter += retVal;//track progress 

     output.writeObject("UPACK "+retVal);//alert server upload packet is incoming, with size of packet read 

     System.out.println(""+buffer[0]+" "+buffer[1]+" "+buffer[2]);//preview first 3 bytes being sent 
     output.writeObject(buffer);//send bytes 
     output.flush();//make sure all bytes read are gone 

     retVal = fis.read(buffer);//get next MB of file 
     } 
     System.out.println(Math.round(100*counter/fileSize)+"%");//show progress at end of file 
     output.writeObject("UPLOAD_COMPLETE");//let server know protocol is finished 
     output.close(); 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
    } 
} 

는 IS 다음 내 서버 코드 :

언제나
import java.net.*; 
import java.io.*; 

public class stupidServer 
{ 
    Socket s; 
    ServerSocket server; 

    public static void main(String[] args) 
    { 
    new stupidServer(); 
    } 

    public stupidServer() 
    { 
    try 
    { 
     //establish connection and stream 
     server = new ServerSocket(2013); 
     s = server.accept(); 
     ObjectInputStream input = new ObjectInputStream(s.getInputStream()); 
     String[] args = ((String)input.readObject()).split("\\|");//args[0] will be file name, args[1] will be file size 
     String fileName = args[0]; 
     long filesize = Long.parseLong(args[1]); 

     String upack = (String)input.readObject();//get upload packet(string reading UPACK [bytes read]) 
     FileOutputStream outStream = new FileOutputStream("C:\\"+fileName.trim()); 

     while (!upack.equalsIgnoreCase("UPLOAD_COMPLETE"))//until protocol is complete 
     { 
     int bytes = Integer.parseInt(upack.split(" ")[1]);//get number of bytes being written 
     byte[] buffer = new byte[bytes]; 
     buffer = (byte[])input.readObject();//get bytes sent from client 

     outStream.write(buffer,0,bytes);//go ahead and write them bad boys to file 
     System.out.println(buffer[0]+" "+buffer[1]+" "+buffer[2]);//peek at first 3 bytes received 
     upack = (String)input.readObject();//get next 'packet' - either another UPACK or a UPLOAD_COMPLETE 
     } 
     outStream.flush(); 
     outStream.close();//make sure all bytes are in file 
     input.close();//sign off 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
    } 
} 

, 시간에 대한 많은 감사합니다!

답변

3

즉각적인 문제는 ObjectOutputStream이 스트림을 통해 동일한 개체를 여러 번 보내는 것을 피하기 위해 ID 메커니즘을 사용한다는 것입니다. 클라이언트는 buffer의 두 번째 이후 쓰기에 대해이 ID를 보내고 서버는 캐시 된 값을 사용합니다.

이 바로 문제의 해결책은 reset()에 전화를 추가하는 것입니다 제쳐두고, 당신이 그들 위에 자신의 프로토콜을 적층하여 객체 스트림을 오용하고

output.writeObject(buffer);//send bytes 
output.reset(); // force buffer to be fully written on next pass through loop 

. 예를 들어 파일 이름과 파일 크기를 "|"로 구분 된 단일 문자열로 쓰십시오; 그들을 두 개의 분리 된 값으로 씁니다. 각 쓰기의 바이트 수는 동감입니다.

+0

정확하게 해결되었습니다. 나는 전송 된 객체가 캐시되었다는 사실을 모르고 있었고, 더 많은 독서를해야한다 .... 많은 도움을 주셔서 감사합니다! – bowens