Java实现websocket发送长文本问题

Java实现websocket时,每次发送的文本长度默认限制在8k范围内,原因是 org.apache.tomcat.websocket.WsSession进行了设置
 
 // Buffers
    static final int DEFAULT_BUFFER_SIZE = Integer.getInteger(
            "org.apache.tomcat.websocket.DEFAULT_BUFFER_SIZE", 8 * 1024)
            .intValue();
    private volatile int maxBinaryMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE;
    private volatile int maxTextMessageBufferSize = Constants.DEFAULT_BUFFER_SIZE;

如果发送超过8k的消息,就会报错:

No async message support and buffer too small Buffer size: [8,192], Message size: [10,240]
那么要实现类似发送文件的base64,网上有两种方式实现,第一种是实现ServletContextInitializer接口,对onStartup进行重载,大体代码如下:
 
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.util.WebAppRootListener;


import javax.servlet.ServletContext;
import javax.servlet.ServletException;


/**
* 设置websocket 传输内容的字节大小。 默认8k  当前设置50M
*/
@EnableWebSocket
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class WebSocketConfig  implements ServletContextInitializer {


    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }


    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.addListener(WebAppRootListener.class);
        servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize","52428800");
        servletContext.setInitParameter("org.apache.tomcat.websocket.binaryBufferSize","52428800");
   }
}
这个方法会出现问题就是,每个websocket会话初始化就会占用设置的内存,如上代码是50M,这样连接达到一定数量就会内存溢出。
我们通常会使用另外一种方式,就是在注解 @OnMessage设置消息大小,代码如下:
 @OnMessage(maxMessageSize=5242880)
    public void onMessage(String message,  Session session, @PathParam("deviceNo")String  deviceNo) {
        log.info("message:"+message +"   ;deviceNo"+deviceNo);
        try {
            JSONObject obj =  JSONObject.parseObject(message);
            String funid  =  (String)obj.get("funid");
            JSONObject contentObj  =  (JSONObject)obj.get("content");
       }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

第二种方式在500个连接情况下经过测试不会造成内存溢出

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Netty是一个基于NIO的网络框架,可以轻松实现WebSocket协议,同时支持发送文本和二进制数据。 以下是一个简单的Netty实现WebSocket发送文本和二进制数据的示例代码: ```java public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> { private WebSocketServerHandshaker handshaker; @Override public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof FullHttpRequest) { // 处理HTTP请求,WebSocket握手请求 handleHttpRequest(ctx, (FullHttpRequest) msg); } else if (msg instanceof WebSocketFrame) { // 处理WebSocket请求,包括文本和二进制数据 handleWebSocketFrame(ctx, (WebSocketFrame) msg); } } private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { // 如果HTTP解码失败,返回HTTP异常 if (!req.decoderResult().isSuccess() || !"websocket".equals(req.headers().get("Upgrade"))) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); return; } // 握手请求 WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:8080/ws", null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } } private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { // 判断是否是关闭链路的指令 if (frame instanceof CloseWebSocketFrame) { handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); return; } // 判断是否是Ping消息 if (frame instanceof PingWebSocketFrame) { ctx.channel().write(new PongWebSocketFrame(frame.content().retain())); return; } // 判断是否是二进制消息 if (frame instanceof BinaryWebSocketFrame) { // 处理二进制消息 ByteBuf binaryData = frame.content(); // TODO: 处理二进制数据 return; } // 处理文本消息 if (frame instanceof TextWebSocketFrame) { String text = ((TextWebSocketFrame) frame).text(); // TODO: 处理文本数据 return; } } private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) { // 返回HTTP响应 if (res.status().code() != 200) { ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8); res.content().writeBytes(buf); buf.release(); HttpHeaderUtil.setContentLength(res, res.content().readableBytes()); } // 如果不是Keep-Alive,关闭连接 boolean keepAlive = HttpHeaderUtil.isKeepAlive(req); if (!keepAlive) { ctx.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE); } else { res.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); ctx.writeAndFlush(res); } } } ``` 在以上示例代码中,`handleHttpRequest()` 方法负责处理HTTP请求,进行WebSocket握手,并将 WebSocketServerHandshaker 对象保存起来。`handleWebSocketFrame()` 方法则负责处理WebSocket请求,包括文本和二进制数据。根据不同的 WebSocketFrame 类型,分别进行处理即可。在处理二进制数据时,可以通过 ByteBuf 对象来获取数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值