zoukankan      html  css  js  c++  java
  • netty结合websocket使用

    首先需要在后台建立netty服务器启动类;

    package com.cxy;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    
    /***
     * @ClassName: WsNetty
     * @Description:
     * @Auther: cxy
     * @Date: 2019/2/5:14:15
     * @version : V1.0
     */
    public class WsNetty {
        public static void main(String[] args) throws InterruptedException {
            /* 主从线程组模型
            */
            EventLoopGroup mainGroup =new NioEventLoopGroup();
            EventLoopGroup subGroup=new NioEventLoopGroup();
            try {
          //创建核心类 ServerBootstrap serverBootstrap
    =new ServerBootstrap(); serverBootstrap.group(mainGroup,subGroup) .channel(NioServerSocketChannel.class) .childHandler(new WSServerInitialzer());//添加助手类 ChannelFuture channelFuture= serverBootstrap.bind(8088).sync(); channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); }finally { mainGroup.shutdownGracefully(); subGroup.shutdownGracefully();//优雅的关闭主从线程池 } } }

    第二创建初始化类;

    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.http.HttpObjectAggregator;
    import io.netty.handler.codec.http.HttpServerCodec;
    import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
    import io.netty.handler.stream.ChunkedWriteHandler;
    
    public class WSServerInitialzer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            
            // websocket 基于http协议,所以要有http编解码器
            pipeline.addLast(new HttpServerCodec());
            // 对写大数据流的支持 
            pipeline.addLast(new ChunkedWriteHandler());
            // 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
            // 几乎在netty中的编程,都会使用到此hanler
            pipeline.addLast(new HttpObjectAggregator(1024*64));
            
            // ====================== 以上是用于支持http协议    ======================
            
            // ====================== 以下是支持httpWebsocket ======================
            
            /**
             * websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws
             * 本handler会帮你处理一些繁重的复杂的事
             * 会帮你处理握手动作: handshaking(close, ping, pong) ping + pong = 心跳
             * 对于websocket来讲,都是以frames进行传输的,不同的数据类型对应的frames也不同
             */
            pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
            
            // 自定义的handler
            pipeline.addLast(new ChatHandler());
        }
    
    }

    第三步:创建助手类

    import java.time.LocalDateTime;
    
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.channel.group.ChannelGroup;
    import io.netty.channel.group.DefaultChannelGroup;
    import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
    import io.netty.util.concurrent.GlobalEventExecutor;
    
    /**
     * 
     * @Description: 处理消息的handler
     * TextWebSocketFrame: 在netty中,是用于为websocket专门处理文本的对象,frame是消息的载体
     */
    public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    
        // 用于记录和管理所有客户端的channle
        private static ChannelGroup clients = 
                new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) 
                throws Exception {
            // 获取客户端传输过来的消息
            String content = msg.text();
            System.out.println("接受到的数据:" + content);
            
    //        for (Channel channel: clients) {
    //            channel.writeAndFlush(
    //                new TextWebSocketFrame(
    //                        "[服务器在]" + LocalDateTime.now() 
    //                        + "接受到消息, 消息为:" + content));
    //        }
            // 下面这个方法,和上面的for循环,一致
            clients.writeAndFlush(
                    new TextWebSocketFrame(
                            "[服务器在]" + LocalDateTime.now() 
                            + "接受到消息, 消息为:" + content));
            
        }
    
        /**
         * 当客户端连接服务端之后(打开连接)
         * 获取客户端的channle,并且放到ChannelGroup中去进行管理
         */
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            clients.add(ctx.channel());
        }
    
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            // 当触发handlerRemoved,ChannelGroup会自动移除对应客户端的channel
    //        clients.remove(ctx.channel());
            System.out.println("客户端断开,channle对应的长id为:" 
                                + ctx.channel().id().asLongText());
            System.out.println("客户端断开,channle对应的短id为:" 
                                + ctx.channel().id().asShortText());
        }
    
        
        
    }

    前端页面:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8" />
            <title></title>
        </head>
        <body>
            <div>发送消息</div>
            <input type="text" id="msgContent" />
            <input type="button" value="点我发送" onclick="chat.chat1()" />
            <div>接受消息</div>
            <div id="receiveMsg" style="background-color: gainsboro;"> </div>
            <script type="application/javascript">
                
                window.chat={
                    
                    socket:null,
                    init:function(){
                        if(window.WebSocket){
                            chat.socket =new WebSocket("ws://127.0.0.1:8088/ws");
                            chat.socket.onopen =function(){
                                console.log("连接建立成功");
                            },
                            chat.socket.onclose =function(){
                                console.log("连接关闭");
                                
                            },
                            chat.socket.onerror =function(){
                                console.log("连接出错");
                            },
                            chat.socket.onmessage =function(e){
                                console.log("接受到消息"+e.data);
                                var receiveMsg =document.getElementById("receiveMsg");
                                var html =receiveMsg.innerHTML;
                                receiveMsg.innerHTML=html+"<br/>"+e.data;
                                
                            }
                            
                        }else{
                            alert("浏览器不支持协议");
                        }
                        
                    },
                    chat1:function(){
                        var msg =document.getElementById("msgContent");
                        chat.socket.send(msg.value);
                        
                    }
                    
                };
                chat.init();
            </script>
        </body>
    </html>

    测试结果:

  • 相关阅读:
    MySQL迁移升级解决方案
    Python json和simplejson的使用
    ASP.NET使用Memcached高缓存实例的初级介绍
    Spring Cloud Stream在同一通道根据消息内容分发不同的消费逻辑
    JS高级---函数的几个成员
    JS高级---bind方法的使用
    JS高级---bind方法
    JS高级---总结apply和call方法的使用
    JS高级---apply和call都可以改变this的指向
    JS高级---复习
  • 原文地址:https://www.cnblogs.com/xiufengchen/p/10352841.html
Copyright © 2011-2022 走看看