基于java nio netty websocket protobuf javascript等技术实现前后端高性能实时数据传输

硅谷探秘者 Md nginx,前端,java基础 1583 0 0

  基于java nio + netty + websocket + protobuf +javascript等技术实现前后端高性能实时数据传输的demo模型。

  github地址:https://github.com/18438301593/NettyWebsocketProtoDemo

主要过程分析:

一、.proto文件编写,生成java类,以及javacript文件。

  参考文章:

  http://www.jiajiajia.club/blog/artical/351psy9r6l0g/464

  http://www.jiajiajia.club/blog/artical/ydn9dpg64gkf/466

二、集成websocket

  websocket协议的建立连接的阶段采用了http协议的方式,所以会看到http协议相关的解码器和编码器。如下:

        pipeline.addLast(new HttpServerCodec());
        //支持写大数据流
        pipeline.addLast(new ChunkedWriteHandler());
        //http聚合器
        pipeline.addLast(new HttpObjectAggregator(1024*62));
        //websocket支持,设置路由
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));

        // 协议包解码
        pipeline.addLast(new MessageToMessageDecoder<WebSocketFrame>() {
            @Override
            protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> objs) throws Exception {
                System.out.println("received client msg ------------------------");
                if (frame instanceof TextWebSocketFrame) {
                    // 文本消息
                    TextWebSocketFrame textFrame = (TextWebSocketFrame)frame;
                    System.out.println("MsgType is TextWebSocketFrame");
                } else if (frame instanceof BinaryWebSocketFrame) {
                    // 二进制消息
                    ByteBuf buf = ((BinaryWebSocketFrame) frame).content();
                    objs.add(buf);
                    // 自旋累加
                    buf.retain();
                    System.out.println("MsgType is BinaryWebSocketFrame");
                } else if (frame instanceof PongWebSocketFrame) {
                    // PING存活检测消息
                    System.out.println("MsgType is PongWebSocketFrame ");
                } else if (frame instanceof CloseWebSocketFrame) {
                    // 关闭指令消息
                    System.out.println("MsgType is CloseWebSocketFrame");
                    channel.close();
                }

            }
        });

三、 支持protobuf协议

  主要配置解码器和编码器

        //解码器,通过Google Protocol Buffers序列化框架动态的切割接收到的ByteBuf
        pipeline.addLast(new ProtobufVarint32FrameDecoder());
        //Google Protocol Buffers 长度属性编码器
        pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());

        // 协议包编码,编码成二进制数据,通过websocket发送
        pipeline.addLast(new MessageToMessageEncoder<MessageLiteOrBuilder>() {
            @Override
            protected void encode(ChannelHandlerContext ctx, MessageLiteOrBuilder msg, List<Object> out) throws Exception {
                ByteBuf result = null;
                if (msg instanceof MessageLite) {
                    result = wrappedBuffer(((MessageLite) msg).toByteArray());
                }
                if (msg instanceof MessageLite.Builder) {
                    result = wrappedBuffer(((MessageLite.Builder) msg).build().toByteArray());
                }
                // 封装二进制数据
                WebSocketFrame frame = new BinaryWebSocketFrame(result);
                out.add(frame);
            }
        });

        // protobuf解码器
        channel.pipeline().addLast("decoder",new ProtobufDecoder(MyMessage.MyMessageInfo.getDefaultInstance()));

四、支持心跳检测,超时关闭连接

  解码器配置

        // 超时心跳检测
        channel.pipeline().addLast(new IdleStateHandler(5,5,5, TimeUnit.SECONDS));

  业务处理在NettyServerHandler类的userEventTriggered()方法。

@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt)throws Exception{
        System.out.println("::::"+evt);
        if(evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent)evt;
            String eventType = null;
            switch (event.state()){
                case READER_IDLE:
                    eventType = "读空闲";
                    readIdleTimes ++; // 读空闲的计数加1
                    break;
                case WRITER_IDLE:
                    eventType = "写空闲";
                    // 不处理
                    break;
                case ALL_IDLE:
                    eventType ="读写空闲";
                    // 不处理
                    break;
            }
            System.out.println(ctx.channel().remoteAddress() + "超时事件:" +eventType);
            if(readIdleTimes > 3){
                System.out.println(" [server]读空闲超过3次,关闭连接");
                ctx.channel().close();
            }
        }
    }

五、前端websocket接受到数据如何解析?

  websocket是一帧一帧发送的,所以要读取所有数据,在转成字节数据,才能反序列化成js对象。

    ws.onmessage = function (event) {
        var reader = new FileReader();
        reader.readAsArrayBuffer(event.data);
        reader.onload = function (e) {
            var buf = new Uint8Array(reader.result);
            var j = proto.MyMessageInfo.deserializeBinary(buf);
            var t = document.getElementById("message");
            t.innerHTML = j.getName();
        }
    };

评论区
请写下您的评论...
暂无评论...
猜你喜欢
official 1183   javanio+netty+websocket+protobuf+javascript的demo模型。  github地址:https
official 1044 的文章介绍了protobuf的概念参考:http://www.jiajiajia.club/blog/artical/351psy9r6l0g/464以及protobuf的编码方式参考:http
official 963 Websocket协议和http协议的关系websocketTCP的一个应用协议,与HTTP协议的关联之处在websocket的握手被HTTP服务器当作HTTP包来处理,主要通过
official 1043 在上一节《一起学netty(6)》的文章中,简要说明了用nio原生代码写程序的一些不足和问题,以及nettynio础上大致做了那些工作。其中提到一点就是当活跃客户量太多,单线程处理所带
official 937 。ServiceSocketChannel本身不具备力,它只监听新进来的TCP链接通道。当有新的TCP链接通道建立,它会创建一个SocketChannel的对象,代表和客户的唯一连接通道
spring/springmvc 3917 springmvc集成websocket环境:spring+springmvc+tomcat8注意:本测试项目运行环境不tomcat81.websocket配置
official 1090 netty的包中,发也有ServerSocketChannel和SocketChannel,以及NioServerSocketChannel和NioSocketChannel,概念上来说
算法基础 1303 自然结果也就是省电:因为大量的必然需要更久的网络操作、序列化及反序列化操作,这些都是电量消耗过快的根源。当通讯应用中最热门的通信协议无疑就是Google的Protobuf了,它的优
归档
2018-11  12 2018-12  33 2019-01  28 2019-02  28 2019-03  32 2019-04  27 2019-05  33 2019-06  6 2019-07  12 2019-08  12 2019-09  21 2019-10  8 2019-11  15 2019-12  25 2020-01  9 2020-02  5 2020-03  16 2020-04  4 2020-06  1 2020-07  7 2020-08  13 2020-09  9 2020-10  5 2020-12  3 2021-01  1 2021-02  5 2021-03  7 2021-04  4 2021-05  4 2021-06  1 2021-07  7 2021-08  2 2021-09  8 2021-10  9 2021-11  16 2021-12  14 2022-01  7 2022-05  1 2022-08  3 2022-09  2 2022-10  2 2022-12  5 2023-01  3 2023-02  1 2023-03  4 2023-04  2 2023-06  3 2023-07  4 2023-08  1 2023-10  1 2024-02  1 2024-03  1 2024-04  1
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础 xxl-job rabbitmq haproxy srs 音视频 webrtc javascript
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。