使用Smack发送自定义格式消息触发‘not-well-formed’异常求助
解决Smack发送含控制字符消息触发的not-well-formed流错误
你的问题根源很明确:XMPP是基于XML的协议,而XML 1.0规范严格禁止在内容中使用ASCII控制字符(除了制表符\t、换行\n、回车\r),你用到的STX(0x2)、ETX(0x3)、US(0x1F)都属于被禁止的字符,当Smack尝试把包含这些字符的消息封装进XML流时,服务器会判定XML格式无效,直接触发not-well-formed错误并断开连接。
下面给你两种可行的解决方案,按需选择:
方案1:替换控制字符为XML友好的标记
把那些控制字符换成自定义的字符串标记,发送后在接收端再替换回原字符,完全避开XML的字符限制。
发送端修改代码
// 用XML允许的字符串替换控制字符 String STX = "<STX_MARKER>"; String ETX = "<ETX_MARKER>"; String US = "<US_MARKER>"; // 生成其他参数(保持你的原有逻辑) String stringEncodedByteArray = Base64.getEncoder().encodeToString(bytes); String fileID = java.util.UUID.randomUUID().toString(); String fileName = "file1"; String fileSize = "1000"; String senderID = "user1"; // 构建消息内容 String messageContent = STX + "1" + US + fileID + US + fileName + US + fileSize + US + senderID + US + stringEncodedByteArray + ETX; // 发送消息(和你原来的发送逻辑一致) Message message = new Message("recipient@yourdomain.com", Message.Type.chat); message.setBody(messageContent); connection.sendStanza(message);
接收端处理逻辑
// 收到消息后,把标记替换回原控制字符 String receivedBody = message.getBody(); String STX = Character.toString((char) 2); String ETX = Character.toString((char) 3); String US = Character.toString((char) 31); String processedContent = receivedBody.replace("<STX_MARKER>", STX) .replace("<US_MARKER>", US) .replace("<ETX_MARKER>", ETX); // 接下来按你的原有逻辑解析processedContent即可
方案2:使用XMPP标准扩展传输结构化数据
如果是传输文件相关数据,更推荐使用XMPP官方定义的扩展协议(比如XEP-0047 带内字节流、XEP-0234 Jingle文件传输),或者自定义消息扩展元素,这样完全符合XMPP规范,也更易维护。
比如自定义扩展元素的示例:
// 创建聊天消息 Message message = new Message("recipient@yourdomain.com", Message.Type.chat); // 自定义文件信息扩展(指定一个唯一的命名空间) DefaultElement fileInfoExt = new DefaultElement("file-info", "com.yourcompany.xmpp.filetransfer"); fileInfoExt.addAttribute("id", fileID); fileInfoExt.addAttribute("name", fileName); fileInfoExt.addAttribute("size", fileSize); fileInfoExt.addAttribute("sender", senderID); // 添加Base64编码的文件数据扩展 DefaultElement fileDataExt = new DefaultElement("file-data", "com.yourcompany.xmpp.filetransfer"); fileDataExt.setText(stringEncodedByteArray); // 把扩展元素添加到消息中 message.addExtension(fileInfoExt); message.addExtension(fileDataExt); // 发送消息 connection.sendStanza(message);
接收端解析扩展
// 从收到的消息中获取扩展元素 Message receivedMsg = ...; DefaultElement fileInfo = (DefaultElement) receivedMsg.getExtension("file-info", "com.yourcompany.xmpp.filetransfer"); DefaultElement fileData = (DefaultElement) receivedMsg.getExtension("file-data", "com.yourcompany.xmpp.filetransfer"); // 获取参数 String fileID = fileInfo.getAttributeValue("id"); String fileName = fileInfo.getAttributeValue("name"); // ... 其他参数 byte[] fileBytes = Base64.getDecoder().decode(fileData.getText());
这种方式不仅避免了控制字符的问题,还让数据结构更清晰,也符合XMPP的设计理念。
内容的提问来源于stack exchange,提问作者H3m4d
相关产品推荐
相关产品推荐

