我有最简单的客户端 - 服务器通信。
客户端:
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
}
但是如果我们刷新流,则会抛出异常。
服务器:
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.
}
这种差异的原因是什么?
答案 0 :(得分:2)
这是因为BufferedWriter
在它独立包装的流的顶部添加了一层自己的缓冲。
当您刷新基础流时,您正在做的就是这些。 BufferedWriter
仍有缓冲区。你绕过了那些。
但是,当您刷新BufferedWriter
时,您需要处理其额外的缓冲层,然后将其发送到基础流。 BufferedWriter
的{{1}}实现之后也会在基础流上调用flush()
,因此您可以获得[将更高级别缓冲区刷新到基础流]的完整链[= 1]。 [刷新基础流]。
您可以在source for BufferedWriter#flush()
(评论我的)中看到该行为:
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()
来电。
答案 1 :(得分:0)
OutputStream API可能有帮助。
刷新此输出流并强制写出任何缓冲的输出字节。 flush的一般契约是调用它表示,如果先前写入的任何字节已被输出流的实现缓冲,则应立即将这些字节写入其预期目的地。 如果该流的预期目的地是由底层操作系统提供的抽象,例如文件,则刷新流仅保证先前写入流的字节被传递到操作系统以进行写入;它不能保证它们实际上写入物理设备,如磁盘驱动器。
OutputStream的flush方法不执行任何操作。
和client.getOutputStream()获取扩展FileOutputStream的SocketOutputStream,而不是覆盖flush mothod。