java socket 发送 xml 报文需统一编码(如utf-8)、明确消息边界(如长度头)、过滤非法字符、及时 flush;xml 声明不改变实际字节,特殊字符易致传输失败,base64 编码可提升鲁棒性。

Java Socket 发送 XML 报文前,必须确保字节流编码一致
XML 是文本,但 Socket 传输的是字节。如果服务端用 UTF-8 解析,而你用 new OutputStreamWriter(out, "GBK") 写入,对方收到的就是乱码或解析失败——这不是 XML 格式问题,是编码错位。
- 发送前显式指定编码:用
String.getBytes("UTF-8")转字节数组,再写入OutputStream;避免依赖平台默认编码 - 若用
BufferedWriter或OutputStreamWriter,务必传入"UTF-8"构造参数,且确认服务端也按此解码 - XML 声明里的
encoding属性(如<?xml version="1.0" encoding="UTF-8"?>)只是提示,不改变实际字节内容,别指望它“自动修正”编码
别直接 write(xmlString),要处理换行与结束标识
TCP 是流式协议,没有消息边界。发一段 XML 过去,对方 InputStream.read() 可能只读到一半,或者一次读到两段拼在一起——除非你定义分隔规则。
- 常见做法:在 XML 字符串末尾加换行符(
" "),服务端按行读取(BufferedReader.readLine());但注意 XML 本身可能含,需确保报文内不出现裸换行作为分隔 - 更稳妥:在 XML 前写 4 字节长度头(
DataOutputStream.writeInt(len)),服务端先读 int 再读对应字节数——这要求双方严格约定协议格式 - 千万别用
PrintWriter.println(xmlString)后直接 close(),Socket 未 flush 就断开,数据大概率发不出去
XML 中的特殊字符会让 Socket 传输变脆弱
XML 本身允许 、<code>& 等字符,但如果传输层(比如中间有代理、日志系统、或服务端用非 XML 解析器预处理)对这些字符做转义或截断,整条报文就废了。
- 发送前检查是否含非法控制字符:
xmlString.replaceAll("[\x00-\x08\x0B\x0C\x0E-\x1F]", ""),尤其注意u0000(空字符)会截断字符串 - 如果服务端接受 Base64,建议将 XML 字符串 encode 后发送,降低传输层误伤风险:
Base64.getEncoder().encodeToString(xmlString.getBytes("UTF-8")) - 不要依赖 XML 库自动转义——
Document.appendChild()生成的节点已转义,但手拼字符串时容易漏掉& → &
Socket 写入后必须 flush,且关注 IOException 的真实含义
OutputStream.write() 成功只代表数据进了 OS 缓冲区,不代表对方收到了。真正出问题往往在 flush() 或后续 close() 时才抛异常。
- 每次写完 XML 必须调
out.flush(),否则在 Nagle 算法或缓冲区未满时,数据卡在本地出不去 - 捕获
IOException后,检查e.getMessage()是否含"Broken pipe"(对方已断连)或"Connection reset"(强制中断),这类错误无法重试,得重建连接 - 别在 finally 块里无条件
socket.close()——如果 write + flush 已失败,close 可能掩盖原始错误,先处理写异常再关连接
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










