zoukankan      html  css  js  c++  java
  • Netty对WebSocket的支持(五)

    Netty对WebSocket的支持(五)

    一.WebSocket简介

      在Http1.0和Http1.1协议中,我们要实现服务端主动的发送消息到网页或者APP上,是比较困难的,尤其是现在IM(即时通信)几乎是很多APP都需要实现的功能,我们往往采用一种轮询的方式让终端去请求服务器获取对应的数据,相信很多做过IM通信的朋友应该深有感触,其实大多数的轮询都是无效的(即没有获得到任何的数据);另外一个方面,每一次轮询都是一个完整的Http请求,而根据Http协议,每一次请求都要在Header中携带大量的参数,这无疑对带宽也是一种极大的消耗。

      html5的诞生为我们带来的WebSocket,这是一个振奋人心的事情,WebSocket是基于Http协议的一种长连接协议,有了这种协议,我们就可以实现服务端主动往客户端发送消息的功能。有关WebSocket协议的相关信息请读者查询相关的文档,在笔者的博文中不再作过多的赘述。因为我们讲的是Netty, 所以今天我们就来说说Netty对WebSocket的支持。

    二.Netty实现WebSocket

    2.1 服务端启动程序

    public class WebsocketServer {
        public static void main(String[] args) throws InterruptedException {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            
            
            try{
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                               .handler(new LoggingHandler(LogLevel.INFO))
                               .childHandler(new WebSocketChannelInitializer());
                
                ChannelFuture channelFuture = serverBootstrap.bind(8989).sync();
                channelFuture.channel().closeFuture().sync();
            }finally{
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }

    2.2 服务端通道初始化

    public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel>{
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            //HttpServerCodec: 针对http协议进行编解码
            pipeline.addLast("httpServerCodec", new HttpServerCodec());
            //ChunkedWriteHandler分块写处理,文件过大会将内存撑爆
            pipeline.addLast("chunkedWriteHandler", new ChunkedWriteHandler());
            /**
             * 作用是将一个Http的消息组装成一个完成的HttpRequest或者HttpResponse,那么具体的是什么
             * 取决于是请求还是响应, 该Handler必须放在HttpServerCodec后的后面
             */
            pipeline.addLast("httpObjectAggregator", new HttpObjectAggregator(8192));
            
            //用于处理websocket, /ws为访问websocket时的uri
            pipeline.addLast("webSocketServerProtocolHandler", new WebSocketServerProtocolHandler("/ws"));
            
            pipeline.addLast("myWebSocketHandler", new MyWebSocketHandler());
        }
    }

    2.3 服务端Handler

    public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
            Channel channel = ctx.channel();
            System.out.println(channel.remoteAddress() + ": " + msg.text());
            ctx.channel().writeAndFlush(new TextWebSocketFrame("来自服务端: " + LocalDateTime.now()));
        }
        
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            System.out.println("ChannelId" + ctx.channel().id().asLongText());
        }
        
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            System.out.println("用户下线: " + ctx.channel().id().asLongText());
        }
        
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.channel().close();
        }
    }

    2.4 网页端的实现

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>Socket</title>
            <script type="text/javascript">
                var websocket;
                
                //如果浏览器支持WebSocket
                if(window.WebSocket){  
                    websocket = new WebSocket("ws://localhost:8989/ws");  //获得WebSocket对象
                    
                    //当有消息过来的时候触发
                    websocket.onmessage = function(event){ 
                        var respMessage = document.getElementById("respMessage");
                        respMessage.value = respMessage.value + "
    " + event.data;
                    }
                    
                    //连接关闭的时候触发
                    websocket.onclose = function(event){
                        var respMessage = document.getElementById("respMessage");
                        respMessage.value = respMessage.value + "
    断开连接";
                    }
                    
                    //连接打开的时候触发
                    websocket.onopen = function(event){
                        var respMessage = document.getElementById("respMessage");
                        respMessage.value = "建立连接";
                    }
                }else{
                    alert("浏览器不支持WebSocket");
                }
                
                function sendMsg(msg) { //发送消息 
                    if(window.WebSocket){
                        if(websocket.readyState == WebSocket.OPEN) { //如果WebSocket是打开状态
                            websocket.send(msg); //send()发送消息
                        }
                    }else{
                        return;
                    }
                }
            </script>
        </head>
    <body>
        <form onsubmit="return false">
            <textarea style=" 300px; height: 200px;" name="message"></textarea>
            <input type="button" onclick="sendMsg(this.form.message.value)" value="发送"><br>
            <h3>信息</h3>
            <textarea style=" 300px; height: 200px;" id="respMessage"></textarea>
            <input type="button" value="清空" onclick="javascript:document.getElementById('respMessage').value = ''">
        </form>
    </body>
    </html>

    2.5 测试

    首先运行服务端启动程序,然后打开网页,发送“Hello world!”,如下图:

  • 相关阅读:
    失效的Eclipse API(一)
    contiki系统分析四:内存分配
    Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]
    Error about updating UI in background thread
    ubuntu 安装ssh server
    [置顶] 树链剖分小节
    [置顶] LCA的树链剖分实现
    飞天开放平台编程指南——阿里云计算的实践
    一道C#面试题
    jQuery参考实例 1.8 将前一次选择的元素集合并到当前选择的元素集中
  • 原文地址:https://www.cnblogs.com/miller-zou/p/7002070.html
Copyright © 2011-2022 走看看