GlassFish服务器缓冲区大小设置问题:WebSocket传大文件报错
解决WebSocket传输大文件时的Buffer Overflow问题
我来帮你排查这个困扰你的WebSocket缓冲区溢出问题,咱们一步步来分析和解决:
首先,先明确你遇到的错误信息:
Warning: Unexpected error, closing connection. java.lang.IllegalArgumentException: Buffer overflow. at org.glassfish.tyrus.core.Utils.appendBuffers(Utils.java:346) at org.glassfish.tyrus.core.TyrusWebSocketEngine$TyrusReadHandler.handle(TyrusWebSocketEngine.java:523)
这个错误确实是因为Tyrus(GlassFish的WebSocket实现)的默认接收缓冲区太小(默认大概3MB左右),无法容纳你发送的大文件数据。你尝试修改glassfish-web.xml的思路是对的,但可能是配置方式有误,或者还有其他需要调整的地方,下面给你几个可行的解决方案:
1. 修正glassfish-web.xml的配置格式
你可能遗漏了把参数包裹在<parameter>标签里,这是GlassFish web应用配置的必填结构。正确的配置应该是这样的:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd"> <glassfish-web-app> <context-root>/PROJECT</context-root> <!-- 正确添加WebSocket接收缓冲区配置 --> <parameter> <param-name>org.glassfish.tyrus.servlet.incoming-buffer-size</param-name> <param-value>17000000</param-value> <!-- 设为17MB,给16MB的文件留余量 --> </parameter> </glassfish-web-app>
修改完成后一定要重启GlassFish服务器,否则配置不会生效。
2. 尝试全局配置(如果应用级配置不生效)
如果上面的应用级配置还是没起作用,可以试试在GlassFish的全局域配置文件domain.xml中添加参数,作用于整个服务器:
找到domain.xml中的<config>节点(通常是<config name="server-config">),在其中添加:
<property name="org.glassfish.tyrus.incoming-buffer-size" value="17000000"/>
同样,修改后需要重启服务器。
3. 分块传输文件(更稳定的备选方案)
如果调整缓冲区大小的方式始终不生效,建议换个思路:把大文件拆分成多个小的WebSocket帧发送(比如每帧1MB),接收端再拼接成完整文件。这种方式不仅能避开缓冲区限制,还能提升传输的稳定性(大帧更容易在网络中出问题)。
伪代码示例:
发送端分块逻辑
File targetFile = new File("your-large-file.bin"); byte[] chunkBuffer = new byte[1024 * 1024]; // 1MB的块大小 try (FileInputStream fis = new FileInputStream(targetFile)) { int bytesRead; while ((bytesRead = fis.read(chunkBuffer)) != -1) { // 发送单个数据块 webSocketSession.getBasicRemote().sendBinary(ByteBuffer.wrap(chunkBuffer, 0, bytesRead)); } // 发送结束标记,告诉接收端文件传输完成 webSocketSession.getBasicRemote().sendText("FILE_TRANSFER_COMPLETE"); } catch (IOException e) { // 处理传输异常 }
接收端拼接逻辑
private List<ByteBuffer> fileChunks = new ArrayList<>(); @OnMessage public void onBinaryMessage(ByteBuffer chunk, Session session) { // 保存每个数据块 fileChunks.add(chunk); } @OnMessage public void onTextMessage(String message, Session session) { if ("FILE_TRANSFER_COMPLETE".equals(message)) { // 拼接所有块并写入文件 int totalSize = fileChunks.stream().mapToInt(ByteBuffer::remaining).sum(); ByteBuffer fullFileBuffer = ByteBuffer.allocate(totalSize); for (ByteBuffer chunk : fileChunks) { fullFileBuffer.put(chunk); } fullFileBuffer.flip(); // 写入本地文件 try (FileOutputStream fos = new FileOutputStream("received-file.bin")) { fos.write(fullFileBuffer.array()); } catch (IOException e) { // 处理写入异常 } // 清空缓存,准备下一次传输 fileChunks.clear(); } }
4. 额外检查项
- 确认Tyrus版本:如果你的GlassFish版本较新,可能参数名有变化,可以试试去掉
servlet前缀,用org.glassfish.tyrus.incoming-buffer-size。 - 检查JVM内存:如果缓冲区设置过大,JVM堆内存不足也可能导致问题,可以调整GlassFish的JVM参数(比如
-Xmx)增加堆内存。
内容的提问来源于stack exchange,提问作者Mirjan Pecenko
相关产品推荐
相关产品推荐

