zoukankan      html  css  js  c++  java
  • Netty 应用:WebSocket服务

    考虑一个场景:如何实现网页版的聊天程序? 不同于Socket的聊天程序

    在以往的http1.0,http1.1当中,是没法实现长连接的。 没出现Websocket之前,采用的是一种轮询的方式,如Comet技术

    术语实时Web:利用技术和实践,使用户在信息的作者发布信息之后就能够立即收到信息,而不需要他们或者他们的软件周期性的检查信息源以获取更新。

    • Websocket是重新设计的协议,目的是为Web上的双向数据传输问题提供一个可行的解决方案,使得客户端和服务器能在任意时刻传输消息,因此要求他们异步的处理消息回调(websocket作为html5的一部分,大部分浏览器已经支持)。

    下面的例子实现的功能:基于websocket协议,客户端能向服务端发送消息,服务端返回服务器的当前时间。

     

    服务端实现

    /**
     * Created by fubin on 2019/7/14.
     */
    public class WebsocketServer {
        public static void main(String[] args) {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try{
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup,workerGroup)
                        .channel(NioServerSocketChannel.class)
                        //增加日志handler
                        .handler(new LoggingHandler(LogLevel.INFO))
                        .childHandler(new WebsocketInitializer());
    
                ChannelFuture channelFuture = serverBootstrap.bind(new InetSocketAddress(8899)).sync();
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    class WebsocketInitializer extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel ch) {
            ChannelPipeline pipeline = ch.pipeline();
    
            /**
             * 处理http请求
             */
            //http编解码
            pipeline.addLast("httpCodec",new HttpServerCodec());
            //以块的方式写的处理器
            pipeline.addLast(new ChunkedWriteHandler());
            //http消息聚合 -> FullHttpRequest或FullHttoResponse
            pipeline.addLast(new HttpObjectAggregator(8192));
    
            /**
             * 处理websocket
             */
    
            //websocket握手,控制帧Frames的处理
            // ws://server:port/content_path(hellowebsocket)
            pipeline.addLast(new WebSocketServerProtocolHandler("/hellowebsocket"));
            pipeline.addLast(new TextWebsocketFrameHandler());
        }
    }
    /**
     * 范型使用TextWebSocketFrame,Websocket传输使用Frame来传递的
     */
    class TextWebsocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame>{
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
            System.out.println("收到的消息:" + msg.text());
            ctx.channel().writeAndFlush(new TextWebSocketFrame("server发送websocket frame ,服务器时间:" + LocalDateTime.now()));
        }
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            System.out.println("handlerAdded: channel的全局id - " + ctx.channel().id().asLongText());
        }
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            System.out.println("handlerRemoved: channel的全局id - " + ctx.channel().id().asLongText());
        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            System.out.println("异常发生");
            ctx.close();
        }
    }

    Netty服务端提供的websocket六种frame类型

    客户端实现

    websocket需要浏览器支持

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>websocket html</title>
    </head>
    <body>
    
    <script type="text/javascript">
        var socket;
    
        if(window.WebSocket){
            socket = new WebSocket("ws://localhost:8899/hellowebsocket");
            //客户端回调,收到服务器端发送的消息
            socket.onmessage = function (event) {
                var serverData = event.data;
                var responseTextVal = document.getElementById("responseText");
                responseTextVal.value = responseTextVal.value + serverData;
            }
            //连接打开
            socket.onopen = function (event) {
                var responseTextVal = document.getElementById("responseText");
                responseTextVal.value = "连接打开...";
            }
            socket.onclose = function (ev) {
                var responseTextVal = document.getElementById("responseText");
                responseTextVal.value = "连接断开...";
            }
        }else{
            alert('浏览器不支持websocket!');
        }
        function send(message) {
            if(!window.WebSocket){
                return;
            }
            if(socket.readyState == WebSocket.OPEN){
                socket.send(message);
            }else {
                alert("连接尚未开启!");
            }
        }
    </script>
    
    <form onsubmit="return false">
        <textarea name="message" style=" 400px; height: 200px"></textarea>
        <input type="button" value="发送数据" onclick="send(this.form.message.value)">
        <h1>服务端输出:</h1>
        <textarea id="responseText" style=" 400px;height: 200px;"></textarea>
        <input type="button" onclick="javascript: document.getElementById('responseText').value = ''" value="清空内容">
    
    </form>
    
    </body>
    </html>

    websocket请求头

    浏览器查看websocket帧

    Netty提供的处理WebSocket服务的Handler WebSocketServerProtocolHandler的API解释

    这个处理程序为您运行websocket服务器做了所有繁重的工作。 它负责websocket握手以及控制框架的处理(Close,Ping,Pong)。 文本和二进制数据帧将传递给管道中的下一个处理程序(由您实现)进行处理。 有关用法,请参阅io.netty.example.http.websocketx.html5.WebSocketServer。 此处理程序的实现假定您只想运行websocket服务器而不处理其他类型的HTTP请求(如GET和POST)。 如果您希望在一台服务器中同时支持HTTP请求和websockets,请参阅io.netty.example.http.websocketx.server.WebSocketServer示例。 要知道握手完成后,您可以拦截ChannelInboundHandler.userEventTriggered(ChannelHandlerContext,Object)并检查该事件是否是WebSocketServerProtocolHandler.HandshakeComplete的实例,该事件将包含有关握手的额外信息,例如请求和所选子协议。

     

     

  • 相关阅读:
    Delphi防止同时出现多个应用程序实例CreateMutex
    DLL注入代码
    DLL注入代码
    C语言学习笔记
    随笔
    存储器简介
    随笔
    对偶问题的基本性质
    C语言学习笔记
    对偶问题的基本性质
  • 原文地址:https://www.cnblogs.com/fubinhnust/p/11940681.html
Copyright © 2011-2022 走看看