여기서 한 발짝 나가서 클라이언트가 파일을 받으면 잘 받았다는 메시지를 서버로 출력하고자 한다. 위 코드들의 주석 처리된 부분이다. 희안하게도 주석을 풀고 서버와 클라이언트를 실행시키면 클라이언트의 코드는 블럭되어버린다. 정확히는 while 문장을 빠져나오지 못한다.
이유에 대해 한참을 고민했는데 원인은 단순했다. BufferedInputStream의 read를 중지 시키기 위해 -1이 리턴되는 상황을 기준으로 작성했는데 -1은 더이상 스트림으로 부터 읽을 데이터가 없을 때를 의미한다. 하지만 일반 파일에서 데이터를 읽으면 언제 끝이라는 것을 알 수 있지만 네트워크 너머의 소켓에서는 -1값이 넘어오지 않는다. 따라서 코드는 while에서 계속 데이터를 읽기 위해 대기중이다.
주석했을 때 코드가 동작했던 이유는 클라이언트가 종료하면서 소켓이 닫히면서 얻어진 부수적인 효과였다.
새로운 시도로 먼저 서버가 클라이언트에게 전달할 총 데이터가 얼마나 큰지 정보를 전달하고 클라이언트에서는
그만큼만 정보를 읽도록 처리한다. 전송할 데이터 크기(long), 전송할 데이터(byte [])를 모두 처리하기 위해서 DataInput/OutputStream을 사용한다.
publicclassServerFile{
publicstaticvoidmain(String[] args){
try (ServerSocketss=newServerSocket(6547)) {
Filefile=newFile("c:/windows/explorer.exe");
while (true) {
try (Socketsocket= ss.accept();
DataOutputStreamdout=newDataOutputStream( newBufferedOutputStream(socket.getOutputStream()));
BufferedReaderbr=newBufferedReader(newInputStreamReader(socket.getInputStream()));
BufferedInputStreambin=newBufferedInputStream(newFileInputStream(file));)
{
System.out.printf("client connected: %s%n", socket.getInetAddress());
longfileSize= file.length();
dout.writeLong(fileSize); // 전송할 데이터 크기를 미리 전달한다.byte[] b = newbyte[10000];
intreaded= -1;
while ((readed = bin.read(b)) > 0) {
dout.write(b, 0, readed);
}
dout.flush();
System.out.println("response message: "+br.readLine()); // 클라이언트 메시지 출력
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}