2014-11-14 1 views
0

가장 간단한 클라이언트 - 서버 통신이 있습니다.스트림을 플러시해도 효과가 없지만 작성자가 플러시됩니다.

클라이언트 :

public static void main(String args[]) throws Exception{ 
    Socket s = new Socket("localhost", 12345); 
    BufferedReader r = new BufferedReader(new InputStreamReader(s.getInputStream())); 
    System.out.println(r.readLine()); 
    s.close(); 
} 

서버 :

public static void main(String args[]) throws Exception{ 
    @SuppressWarnings("resource") 
    ServerSocket server = new ServerSocket(12345); 
    Socket client = server.accept(); 
    OutputStream out = client.getOutputStream(); 
    BufferedWriter w = new BufferedWriter(new PrintWriter(out)); 
    w.write("Hello client\n"); 
    w.flush(); //Works fine, client printed Hello client 
} 

그러나 우리는 exception'll가 발생 할 스트림을 플러시합니다.

서버 :

그 차이의 이유는 무엇
public static void main(String args[]) throws Exception{ 
    @SuppressWarnings("resource") 
    ServerSocket server = new ServerSocket(12345); 
    Socket client = server.accept(); 
    OutputStream out = client.getOutputStream(); 
    BufferedWriter w = new BufferedWriter(new PrintWriter(out)); 
    w.write("Hello client\n"); 
    out.flush(); //Has no effect, doesn't deliver the line to the client. 
} 

?

+2

질문의 한 부분은 플러시가 예외를 발생 시키지만 질문의 다른 부분은 효과가 없다고 말합니다. 무엇 이니? – user2357112

답변

2

이것은 BufferedWriter이 자체적으로 버퍼링하는 계층을 자체적으로 래핑하는 스트림의 맨 위에 추가하기 때문입니다.

기본 스트림을 플러시 할 때 그게 전부입니다. BufferedWriter에는 아직 버퍼가 있습니다. 너는 그걸 무시한다.

그러나 BufferedWriter을 플러시 할 때는 추가 버퍼링 레이어를 처리하여 기본 스트림으로 전송합니다. flush()의 구현은 이후에 기본 스트림에 flush()을 호출하므로 [상위 스트림 버퍼를 플러시] => [기본 스트림 플러시]의 전체 체인을 얻을 수 있습니다.

당신은 source for BufferedWriter#flush() (주석 광산)에서 해당 동작을 볼 수 있습니다

public void flush() throws IOException { 
    synchronized (lock) { 
     flushBuffer(); // Flushes this BufferedWriters buffers to 'out'. 
     out.flush();  // Now flushes 'out' (the stream it wraps). 
    } 
} 

당신은 기본이되는 스트림의 flush() 직접, 본질적으로 건너 뛰는 호출하면 그 위의 코드에서 BufferedWriter#flushBuffer() 전화.

+0

흥미 롭습니다. 최상위 수준 버퍼를 플러시하면 하위 수준이 자동으로 플러시됩니다. 맞습니까? –

+0

@ St.Antario 예; 죄송합니다. 내가 그 세부 사항을 잊어 버렸고 당신이 그것을 올렸을 때 그것을 실제로 추가했다고 깨달았습니다. –

+0

고마워. –

0

OutputStream API가 도움이 될 수 있습니다.

출력 스트림을 플러시하고 버퍼 된 출력 바이트를 강제로 기록합니다. flush의 범용 규약에서는, 출력 스트림의 구현에 의해 이전에 기입해진 바이트가 버퍼링되고있는 경우, 그러한 바이트를 즉시 의도 된 목적지에 기입해야한다는 것을 나타내는 것입니다. 이 스트림의 대상이 기본 운영 체제에서 제공하는 추상화 (예 : 파일) 인 경우 스트림을 플러시하면 이전에 스트림에 기록 된 바이트 만 쓰기 위해 운영 체제로 전달됩니다. 실제로 디스크 드라이브와 같은 물리적 장치에 기록된다는 것을 보증하지는 않습니다.

OutputStream의 flush 메소드는 아무 작업도 수행하지 않습니다.

및 client.getOutputStream()은 FileOutputStream을 확장하고 플러시 mothod를 재정의하지 않는 SocketOutputStream을 가져옵니다.

+0

1.'OutputStream # flush()'는 확실히 뭔가를합니다 : 호출 후 내부적으로 버퍼링 된 데이터가 2.'SocketOutputStream'은'flush()'를 오버라이드 (override)합니다.'write()'가 모든 필요한 작업을 수행하기 때문에 필요하지 않기 때문에 아무것도하지 않습니다. ('SocketOutputStream'은 여분의 버퍼링을하지 않습니다.) 그러므로 그것은 여전히 ​​그 문서에 기술 된'OutputStream' 불변 값을 고수하고 있습니다. 어떤 경우 이건'SocketOutputStream'이 무엇을하는지는 중요하지 않습니다, 그것은 관찰 된 이슈가 아닙니다. –

+0

1. 나는 1 점에 동의합니다 .2 SocketOutputStream은 확장 할 때 flush()를 재정의하지 않습니다. OutputStream에서 확장 한 FileOutputStream도 플러시 mothod를 재정의하지 않습니다. 그리고 OutputStream에서 플러시 mothod를 다음과 같이 재정의하십시오. public void fl ush() throws IOException { } –

+0

예; 미안, 그렇지 않아. 나머지 # 2가 유지됩니다. 'SocketOutputStream # flush()'는 아무것도하지 않아도됩니다. (여전히 명시된 규칙을 위반하지 않습니다) OP가 설명하는 문제의 일부는 아닙니다. OP의 관측치는'BufferedWriter'와 결합 된 * 모든 기본 스트림 유형에 대해 동일합니다. 그것은 'SocketOutputStream'이라는 것이 중요하지 않습니다. –