OutputStreamWriter不参与SSL加密,仅负责字符编码转换;真正加密由SSLSocket输出流完成,必须显式指定UTF-8编码并搭配BufferedWriter使用,且需握手完成后才可写入并正确关闭。

OutputStreamWriter 本身不参与 SSL 加密,它只负责字符到字节的编码转换;真正做加密的是底层的 SSLSocket 输出流。所以“在写入 SSLSocket 加密流时做编码缓冲”,实际是把 OutputStreamWriter 包装在 SSLSocket.getOutputStream() 之上,并合理配置其缓冲和编码行为。
编码必须显式指定,不能依赖平台默认
SSL 流本身传输的是字节,不关心字符集。如果你不指定编码,OutputStreamWriter 会用系统默认 Charset(如 Windows 上可能是 GBK),导致服务端解码失败。务必显式传入 UTF-8 等标准编码:
- ✅ 正确:
new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8) - ❌ 危险:
new OutputStreamWriter(socket.getOutputStream())(隐式使用 platform default)
缓冲靠 BufferedWriter,不是 OutputStreamWriter 自身
OutputStreamWriter 有小量内部缓冲(一般 8192 字节),但不可控、不保证刷新时机。真实场景中应套一层 BufferedWriter 来控制行缓冲或批量写入:
- 推荐组合:
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), UTF_8)) - 写完后必须调用
flush()—— SSL 流不会自动刷出,未 flush 的数据可能卡在缓冲区,对方收不到 - 避免频繁
write() + flush(),批量写入再 flush 更高效
注意 SSL 握手完成后再写入
SSLSocket 必须完成握手(handshake)才能安全写入。直接对未完成 handshake 的输出流写数据,可能被静默丢弃或抛异常:
立即学习“Java免费学习笔记(深入)”;
- 创建 socket 后,先调用
socket.startHandshake()(显式触发)或等待首次 I/O 自动触发 - 确认握手完成后再构建
OutputStreamWriter和BufferedWriter - 可检查
socket.getSession().getCipherSuite()是否非空,作为握手完成的间接依据
关闭顺序要正确:先关 writer,再关 socket
关闭 BufferedWriter 会自动 flush 并关闭底层 OutputStreamWriter 和 SSLSocket 输出流。但要注意:
- 不要单独 close
OutputStreamWriter或底层OutputStream,否则后续 writer 操作会报错 - 整个连接关闭前,确保 writer 已 flush 并 close;否则 SSL 关闭警报(close_notify)可能不完整,影响对方 clean shutdown
- 典型做法:
try-with-resources包裹BufferedWriter,让 JVM 自动管理释放


















