Android Java WebSocket服务器发送数据时出现无效帧头错误
Android WebSocket服务器发送消息时出现"Invalid frame header"错误
我正在开发一款Android(Java)应用,用于创建WebSocket服务器,连接建立一切正常。但向浏览器WebSocket客户端发送消息时遇到问题:
发送消息的代码:
OutputStream writer = client.getOutputStream(); // FIN OPCODE 1000 0001 writer.write(0x81); // message length writer.write(0x5); writer.write('H'); writer.write('e'); writer.write('l'); writer.write('l'); writer.write('o'); writer.flush();
出现错误:failed: Invalid frame header
用Wireshark抓包后发现数据中多了0x0A(换行符),正确应该发送的帧头及内容是:
- 0x81 -> FIN & OPCODE (10000001)
- 0x05 -> 消息长度
- 0x48 0x65 0x6c 0x6c 0x6f -> Hello
更多相关代码
读取客户端请求头部
private String readClientInputStream() { String str = null; try { InputStream in = client.getInputStream(); byte[] buffer = new byte[1024]; int countBytesRead = in.read(buffer); if (countBytesRead > 0) { str = new String(buffer, 0, countBytesRead); } } catch (IOException e) { e.printStackTrace(); } return str; }
发送WebSocket握手响应
public void sendWebSocketHandShake(String str) { String[] result = str.split("Sec-WebSocket-Key: ", -1)[1].split("\\n"); String key = makeKeyAccept(result[0]); StringBuilder handshake_str = new StringBuilder(); handshake_str.append("HTTP/1.1 101 Switching Protocols\n"); handshake_str.append("Upgrade: websocket\n"); handshake_str.append("Connection: Upgrade\n"); handshake_str.append("Sec-WebSocket-Accept: ").append(key).append("\n"); handshake_str.append("\n"); try { OutputStream out = client.getOutputStream(); byte[] b = handshake_str.toString().getBytes(StandardCharsets.UTF_8); out.write(b, 0, b.length); out.flush(); } catch (IOException e) { e.printStackTrace(); } }
生成Sec-WebSocket-Accept密钥
public String makeKeyAccept(String key) { String _acceptKey = key.trim() + WEBSOCKET_KEY_MAGIC; MessageDigest digest = null; String base64 = null; try { digest = MessageDigest.getInstance("SHA-1"); digest.update(_acceptKey.getBytes(StandardCharsets.UTF_8)); byte[] encoded = android.util.Base64.encode(digest.digest(), 0, digest.getDigestLength(), android.util.Base64.DEFAULT); base64 = new String(encoded, 0, encoded.length, StandardCharsets.UTF_8); } catch (Exception ignore){} return base64; }
问题原因与解决方案
核心问题
在makeKeyAccept方法中,使用android.util.Base64.DEFAULT编码会自动添加换行符(0x0A),这个换行符会残留到输出流中。当后续发送WebSocket帧时,残留的换行符会被作为帧的第一个字节发送,导致浏览器收到无效的帧头。
修复步骤
替换Base64编码模式:将
android.util.Base64.DEFAULT改为android.util.Base64.NO_WRAP,避免编码后添加换行符。修改后的代码:public String makeKeyAccept(String key) { String _acceptKey = key.trim() + WEBSOCKET_KEY_MAGIC; MessageDigest digest = null; String base64 = null; try { digest = MessageDigest.getInstance("SHA-1"); digest.update(_acceptKey.getBytes(StandardCharsets.UTF_8)); // 使用NO_WRAP模式避免添加换行符 byte[] encoded = android.util.Base64.encode(digest.digest(), android.util.Base64.NO_WRAP); base64 = new String(encoded, StandardCharsets.UTF_8); } catch (Exception ignore){} return base64; }重置连接测试:由于之前的连接输出流中已有残留换行符,需要重新建立WebSocket连接验证修复效果。
额外建议
- 发送WebSocket帧必须严格遵循RFC 6455规范,确保帧头、长度、负载的格式完全正确。
- 操作字节流后需确认输出状态,避免残留数据影响后续通信。
内容的提问来源于stack exchange,提问作者obeid salem
相关产品推荐
相关产品推荐

