zoukankan      html  css  js  c++  java
  • Netty---入门程序,搭建Websocket 服务器

    Netty 常用的场景:

        1.充当HTTP 服务器,但Netty 并没有遵循servlet 的标准,反而实现了自己的一套标准进行Http 服务;

        2,RPC 远程调用,在分布式系统中常用的框架

        3.Socket 长连接

     

    需要了解的名词

     1.NioEventLoopGroup: 对线程的控制,线程组,事件循环组,死循环,需要定义两个线程组,一个只用于接收客户端的请求,一个负责具体的处理

     2.Bootstrap :对服务启动的封装,可以很轻松的启动服务管道,进行服务的启动

     3.Channel:渠道,每一个请求都会形成一个渠道

     4.initChannel:连接一旦被创建,就会执行initChannel方法

     5.ChannelPipline:连接的管道,里面装有很多的ChannelHandler处理器(第6)

     6.ChannelHandler:定义我们自己的处理器,因为流程进行到这里我们的请求已经进来了,需要我们进行自己的逻辑处理与响应,相当于filter 一样; netty也提供了很多的处理器;

     7.ByteBuf:很重要,以后详细讲解

     8.ChannelGroup :用来存放一个一个的Channel 对象的Channel 组 ,可以通过  new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);进行获取

    接下来是示例代码:我们目前刚接触,我们先不用管它里面具体怎么实现的,只要先对netty 有一个全局的认识,知道它的执行流程就可以,知道执行流程后再深入学习每一步的作用,这样我们就不会太迷茫

    基本上,所有netty 编程中都会遵循以下三点:

      1. 创建线程组,即EventLoopGroup

      2.进行服务启动类,即bootstrap

      3.针对自己的业务,创建自己的Handler

    1.我们的启动类

    public class WebSocketService {
    
        public static void main(String[] args) throws Exception {
            
            //一样,定义线程组
            EventLoopGroup boosGroup =new NioEventLoopGroup();
            EventLoopGroup workGroup =new NioEventLoopGroup();
            
            //服务启动类
            try
            {
            ServerBootstrap bootstrap=new ServerBootstrap();
            bootstrap.group(boosGroup,workGroup)
                    .channel(NioServerSocketChannel.class)
                    //添加日志
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new WebSocketInitializer());
            
            
            //端口绑定
            ChannelFuture channelFuture=bootstrap.bind(9077).sync();
            channelFuture.channel().closeFuture().sync();
            }
            finally {
                boosGroup.shutdownGracefully();
                workGroup.shutdownGracefully();
                
            }
            
            
        }
    }

    2.初始化器,用来存放Hander 的

    /**
     * initializer 初始化器
     * @author cys
     *
     */
    public class WebSocketInitializer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            
            ChannelPipeline pip =ch.pipeline();
            
            //=====websocket 是基于http协议基础之上的,所以要有http的支持=======//
            //编解码器
            pip.addLast(new HttpServerCodec());
            //对大数据的支持
            pip.addLast(new ChunkedWriteHandler());
            // 对httpMessage进行聚合,聚合成FullHttpRequest或FullHttpResponse
            // 几乎在netty中的编程,都会使用到此hanler
            pip.addLast(new HttpObjectAggregator(1024*64));
            
            
            //This handler does all the heavy lifting for you to run a websocket server.
            //这个handler 做了所有的繁重的工作,对于你运行的websocket服务器
            //处理了frame 的 close ping pang binary text ,运行中并带到下一个关于你的实现的handler
            pip.addLast(new WebSocketServerProtocolHandler("/ws"));//===>ws://localhost:8066/ws
            
            //自定义自己的处理类,WebSocketServerProtocolHandler 会将数据帧带到你的handler中
            
            pip.addLast(new WebSocketMyHandler());
            
            
        }
    
    }

    3.定义自己的Handler ,也就是自己的逻辑处理

    /**
     * webSocket 自定义handler
     * webSocket 对于数据的传输都是基于Frame(帧)的 ,关于frame 一共有五种类型,遵循RFC标准,netty 实现了这五种标准,所有netty 对websocket 有很好的支持
     *                                 1.BinaryWebSocketFrame
     *                                 2.TextWebSocketFrame
     *                                 3.PongWebSocketFrame
     *                                 4.PingWebSocketFrame
     *                                 5.CloseWebSocketFrame
     * ping、pong 的操作,对应的是 WebSocket 的两个控制帧 ==心跳
     * 
     * @author cys
     *
     */
    public class WebSocketMyHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    
        //当前的channel 组
        private static ChannelGroup channelGroup =new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
            
            Channel ch =ctx.channel();
            //msg.text()接收客户端的消息
            String text=msg.text();
            System.out.println("收到消息"+text);
            for(Channel self :channelGroup) {
                
                if(ch ==self) {
                    ch.writeAndFlush(new TextWebSocketFrame("我:===>"+text));
                    
                }
                else {
                    self.writeAndFlush(new TextWebSocketFrame(ch.remoteAddress()+"===>"+text));
                }
            }
            
        }
        
        
        
        /**
         * 当有新的Channel连接 时候会触发
         */
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            
            Channel ch = ctx.channel();
            
            channelGroup.writeAndFlush(new TextWebSocketFrame(ch.remoteAddress()+"---上线"));
            System.out.println(ch.remoteAddress()+"已经连接");
            channelGroup.add(ctx.channel());
        }
    
        /**
         * 连接断开的时候触发
         */
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            
            
            
            Channel ch = ctx.channel();
            
            System.out.println(new TextWebSocketFrame(ch.remoteAddress()+"已经断开"));
            channelGroup.writeAndFlush(ch.remoteAddress()+"---下线");
        }
        
        /**
         * 出现异常时候触发,关闭当前连接
         */
        
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            
             ctx.channel().close();
        }
        
    }

    4.因为websocket 是基于HTML5的,所以客户端就是我们支持websocket的浏览器,

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>web socket连接</title>
    </head>
    <body>
    
    <div>发送消息</div>
    <input type="text" id="msgContent"/>
    <input type="button"  value="send" onclick="CHAT.chat()"/>
    <div>接收消息</div>
    <div id="reciveMsg" style="background-color:pink"></div>
    
    <script type="text/javascript">
    
    
    window.CHAT ={
            socket:null,
            init: function(){
                if(window.WebSocket){
                    CHAT.socket =new WebSocket("ws://10.9.121.91:9077/ws");
                    CHAT.socket.onopen = CHAT.onopen,
                    CHAT.socket.onclose =CHAT.onclose,
                    CHAT.socket.onerror =CHAT.onerror,
                    CHAT.socket.onmessage =CHAT.onmessage
                    
                    
                }
                else{
                    alert("不支持socket");
                }
            },
            chat: function(){
                //消息发送
                var content =document.getElementById("msgContent");
                
                if (CHAT.socket != null 
                        && CHAT.socket != undefined  
                        && CHAT.socket.readyState == WebSocket.OPEN) {
                        CHAT.socket.send(content.value);
                } else {
                    // 重连websocket
                    CHAT.init();
                    
                }
    
            
                
            }
            ,
            //客户端与服务器链接触发
            onopen :function(){
                
            
                    console.log("链接已经链接");
                
            },
            onclose :function(){
                    console.log("链接已经关闭");
            },
            
            onerror:function(){
                console.log("出现错误");
                    
            },
           onmessage:function(e){
            
                    console.log("链接消息");
                    var reciveMsg =document.getElementById("reciveMsg");
                    var html =reciveMsg.innerHTML;
                    reciveMsg.innerHTML =html+"<br/>"+e.data;
            
                
            }
            
    }
    
    
    
    CHAT.init();
    
    </script>
    
    </body>
    </html>

      

     

     

    原创打造,多多指教
  • 相关阅读:
    TreeMap Red-Black tree
    Java实现生产者消费者问题与读者写者问题
    一个对象占用多大内存
    MySQL索引背后的数据结构及算法原理
    Java并发编程与技术内幕:线程池深入理解
    Java Spring 中你不知道的注入方式
    面试中的排序算法总结
    JAVA反射
    StringBuilder与StringBuffer的区别
    Java多线程总结【转】
  • 原文地址:https://www.cnblogs.com/iscys/p/9631807.html
Copyright © 2011-2022 走看看