Java SE/End of Stream

Java End of Stream

Soul-Learner 2014. 12. 10. 10:40

서버측에서 전달되는 데이터의 끝을 탐지하기 위한 방법


자바에서 파일을 스트림으로 읽을 때 파일의 끝을 탐지하는 일반적인 방법

FileInputStream fin = new FileInputStream("sample.jpg");

byte[] buf = new byte[2048];

int read = 0;

while((read=fin.read(buf))!=-1) {

// buf 에 저장된 파일 데이터 사용

}


파일에 연결된 FileInputStream의 경우에는 위처럼 파일을 반복적으로 읽어 오다가 파일의 끝을 만나면 read() 메소드가 -1을 리턴하므로 이 때 파일 읽기를 종료하면 된다.


그러나 서버측에서 전달되는 파일 데이터를 클라이언트 측 프로그램에서 InputStream 으로 수신하는 경우에는 read() 메소드가 -1을 리턴하는 상황이 다르게 된다. 서버측에서 전송 스트림을 닫는 경우에 클라이언트 측 수신 스트림에서 read() 메소드가 -1을 리턴하게 된다.


그러므로 서버에서 바이너리 파일 데이터를 전송하는 경우에는 파일 데이터의 끝을 클라이언트 측에게 알리기 위해서는 전송 스트림을 닫거나 다른 방법을 사용해야 한다.


전송 스트림의 데이터 끝을 알리는 주요한 방법은 다음과 같이 3가지를 들 수 있다.

1. 서버측에서 스트림을 닫는다 ( OutputStream.close() )

2. 서버측에서 파일 데이터를 전송하기 전에 파일의 크기를 미리 클라이언트 측에게 알린 후에 파일 데이터를 전송한다

    - 클라이언트 측에서는 수신해야 할 파일 크기를 알게 되므로 데이터를 수신할 때마다 카운트를 올리다가 해당 파일 사이즈에 도달하면 수신을 종료하면 된다

3. 서버측에서는 파일의 끝을 알 수 있으므로 파일 데이터의 끝에 미리 약속된 부가적인 신호를 추가한다



클라이언트에서 파일 데이터를 수신할 때 수신 데이터의 총량을 계산하여 수신 완료를 결정하는 예

byte[] buf = new byte[1024];

int fileSize = [서버에서 알려준 파일의 사이즈];

int read = 0;

int cnt = 0;

while((read=bin.read(buf))!=-1){                       // 서버로부터 수신

    outFile.write(buf, 0, read);                           // 로컬 파일에 저장

    cnt += read;                                             // 수신한 데이터의 양을 누적하여 총수신량을 계산한다

    System.out.printf("%d/%d\n", cnt, fileSize);

    if(cnt == fileSize) break;                             // 총 수신한 데이터 량이 파일 사이즈와 동일한면 수신을 완료한다

}

outFile.close();                                               // 파일출력 스트림을 닫는다



클라이언트 측에서 수신 데이터의 끝을 탐지하기 위해 마지막 바이트 뒤에 부가적으로 특정 신호를 추가하는 예

서버측

byte[] buf = new byte[1024];

int read = 0;

while((read=bin.read(buf))!=-1){  // 파일로부터 읽어서 buf 배열에 저장한다

bout.write(buf, 0, read);     // 클라이언트에게 데이터를 전송한다

bout.flush();

} // 파일 데이터 전송 완료


// 전송 데이터의 끝에 지정된 신호를 추가하여 클라이언트에게 데이터의 종료 지점을 알린다

for(int i=0,num=-1;i<10;i++,num-=1) {   // 10개 바이트에 -1 ~ -10까지 저장하여 전송한다

buf[i] = (byte) num;

}


bout.write ( buf,0,10 );             // 부가적으로 데이터의 끝을 알리는 10개의 바이트 전송

bout.flush();

bin.close();                           // 파일 입력스트림 닫기


클라이언트 측

byte[] buf = new byte[1024];

int read = 0;

boolean isEnd = false;

while((read=bin.read(buf))!=-1){  // 서버로부터 읽어온다

   if(buf[read-1]==-10) {            // 마지막 10개 바이트를 검사하여 데이터의 끝으로 지정한 신호와 일치하는지 비교

      for(int i=2, num=-9;i<=10;i++, num+=1) {  // 데이터의 끝까지 읽어 왔는지 검사한다

if(buf[read-i]!=num) break;

if(i==10){

isEnd = true;               // 데이터의 끝 신호와 일치한 경우 수신을 종료한다

break;

}

      }

   }

   if(isEnd) read -= 10;             // 데이터 종료신호를 제외한 데이터를 파일에 저장한다

   outFile.write(buf, 0, read);

   outFile.flush();

   if(isEnd) break;

}

outFile.close();

System.out.println("파일 수신 완료");         // 파일출력 스트림 종료