Java 11 java.net.http.WebSocket分段发送超16k数据失败求助
Java 11 WebSocket分段发送超16k数据失败问题解决
问题背景
使用Java 11原生java.net.http.WebSocket向Tomcat WebSocket服务器发送分段二进制数据时,遇到如下问题:
- 当分段总大小超过16k时,第二个(最后一个)分段发送失败,触发关闭码1009的错误:
SEVERE: WebSocketClientPeer#onClose statusCode [1009], reason [No async message support and buffer too small. Buffer size: [16,384], Message size: [1,656]]
- 测试验证:若两个分段总大小≤16k则发送成功,仅超出1字节就失败;服务器端支持分段处理,且已有C++客户端可正常发送大分段数据,Java客户端能接收服务器发来的大分段数据。
根本原因
Java 11的java.net.http.WebSocket实现未遵循RFC6455第5.4节的分段规范——该规范要求WebSocket支持逐段发送消息,无需缓冲完整内容。但Java 11的实现会将所有分段缓冲至最后一个分段标记last=true时,再尝试发送合并后的完整消息,当总大小超过默认16k缓冲区时,就会触发缓冲区不足的错误。
可行解决方案
1. 切换至第三方WebSocket客户端库
选择严格遵循RFC6455规范的第三方库,比如Tyrus(Java EE官方WebSocket实现),它会逐段发送数据,不会缓冲整个消息。
示例代码:
import javax.websocket.ClientEndpoint; import javax.websocket.ContainerProvider; import javax.websocket.Session; import javax.websocket.WebSocketContainer; import java.net.URI; import java.nio.ByteBuffer; @ClientEndpoint public class SegmentedWsClient { public static void main(String[] args) throws Exception { WebSocketContainer container = ContainerProvider.getWebSocketContainer(); // 建立连接 Session session = container.connectToServer(SegmentedWsClient.class, URI.create("wss://myserver.dummy.com/wsweb")); // 发送第一个分段(非最后一段) ByteBuffer segment1 = ByteBuffer.wrap(new byte[16 * 1024]); session.getBasicRemote().sendBinary(segment1, false); // 发送最后一个分段 ByteBuffer segment2 = ByteBuffer.wrap(new byte[2048]); session.getBasicRemote().sendBinary(segment2, true); } }
Maven依赖配置:
<dependency> <groupId>org.glassfish.tyrus</groupId> <artifactId>tyrus-client</artifactId> <version>2.1.3</version> </dependency>
2. 升级Java版本至17+
Java 17及以上的java.net.http.WebSocket修复了分段发送的缓冲问题,严格遵循RFC6455规范,无需修改代码即可正常发送超16k的分段数据。
3. 临时规避:调整服务器端缓冲区(不推荐)
若无法修改客户端,可尝试调整Tomcat WebSocket服务器的缓冲区大小,但这只是治标不治本,且可能影响其他客户端的兼容性,不推荐作为长期解决方案。
验证结果
使用Tyrus客户端或升级至Java 17后,发送总大小超过16k的分段数据时,服务器可正常接收并合并为完整消息,无缓冲区错误。
内容的提问来源于stack exchange,提问作者zdenko.s
相关产品推荐
相关产品推荐

