具体问题
bos.未flush() 会造成 Socket 的 阻塞
解决办法: 用 flush 或者 Socket.shutdownOutput()
BufferedOutputStream.close() flush() 和 Socket.shutdownOutput
BufferedOuputStream 成员变量 和 flush()
-
BufferedOutputStream 内层被包装类 FilterOutputStream
/** * BufferedOutputStream 继承至 FilterOutputStream * */ public class BufferedOutputStream extends FilterOutputStream {} public class FilterOutputStream extends OutputStream { // 最底层的被包装类 OutputStream protected OutputStream out; }
BufferedOutputStream
的out
成员变量指的就是被FilterOutputStream
包装的OutputStream
-
构造方法
public class BufferedOutputStream extends FilterOutputStream { // 接收一个 OutputStream 及其子类 传递给带双参的构造函数 public BufferedOutputStream(OutputStream out) { // 不指定 buffered 的大小则默认为8192字节 this(out, 8192); } // 带双参构造函数, 调用父类的 public BufferedOutputStream(OutputStream out, int size) { super(out); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; } }
-
BufferedOuputStream.flush()
@Override public synchronized void flush() throws IOException { flushBuffer(); out.flush(); }
-
flush() 调用本类的
flushBuffer()
+out.flush()
/** Flush the internal buffer */ private void flushBuffer() throws IOException { if (count > 0) { out.write(buf, 0, count); count = 0; } }
-
-
-
write(byte b[], int off, int len)) 方法
/** * 内置的 buffered 桶, 用于装数据 */ protected byte buf[]; /** * @param out 内部包装的 OutputStream */ public BufferedOutputStream(OutputStream out) { this(out, 8192); }
@Override public synchronized void write(byte b[], int off, int len) throws IOException { // 第一次装的数据已经满了, 清空buffer的数据再用out去写 if (len >= buf.length) { flushBuffer(); out.write(b, off, len); return; } // 只有 buffered 装满了,才清空 buffer 的数据 if (len > buf.length - count) { flushBuffer(); } // 否则先将数据写入buf内,等待下次写数据 System.arraycopy(b, off, buf, count, len); count += len; }
综上 : BufferedOutputStream 是 FilterOutputStream 的包装类,
FilterOutputStream 是 OutputStream 的包装类
BufferedOutputStream .close() 和 Socket.shutdownOutput()
-
BufferedOutputStream.close() 源码
@Override public void close() throws IOException { if (closed) { return; } closed = true; Throwable flushException = null; try { flush(); } catch (Throwable e) { flushException = e; throw e; } finally { if (flushException == null) { out.close(); } else { try { out.close(); ... } } } }
BufferedOutputStream 内部调用了底层包装类 OuptStream.close()
-
JDK8及之前释放资源使用 close() – 不安全
/** * 关闭流直接关闭socket */ public void close() throws IOException { // Prevent recursion. See BugId 4484411 if (closing) return; closing = true; if (socket != null) { if (!socket.isClosed()) socket.close(); } else impl.close(); closing = false; }
-
JDK9新特性:Socket.shutdownOutput()
public void shutdownOutput() throws IOException { if (isClosed()) throw new SocketException("Socket is closed"); if (!isConnected()) throw new SocketException("Socket is not connected"); if (isOutputShutdown()) throw new SocketException("Socket output is already shutdown"); getImpl().shutdownOutput(); shutOut = true; }
-
能够单方向得关闭流
-