zoukankan      html  css  js  c++  java
  • netty 详解(四)netty 开发 WebSocket 长连接程序

     

      WSServer

    package com.oy.ws;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    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 WSServer {
        private int port;
        public WSServer(int port) {
            this.port = port;
        }
    
        public static void main(String[] args) {
            new WSServer(8002).run();
        }
    
        public void run() {
            EventLoopGroup boss = new NioEventLoopGroup(1);
            EventLoopGroup work = new NioEventLoopGroup();
    
            try {
                ServerBootstrap bootstrap = new ServerBootstrap();
                bootstrap
                        .group(boss, work)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                // 因为基于 HTTP 协议,使用 http 的编码解码器
                                pipeline.addLast(new HttpServerCodec());
                                // 以块的方式写
                                pipeline.addLast(new ChunkedWriteHandler());
                                // 因为 http 数据在传输过程中时分段的,HttpObjectAggregator 就可以将多个段聚合
                                pipeline.addLast(new HttpObjectAggregator(8192));
                                // websocket 数据是以帧(frame)的形式传递
                                // webSocketFrame 下面有六个子类
                                // WebSocketServerProtocolHandler:将 http 协议升级为 ws 协议,保持长连接
                                pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));
                                pipeline.addLast(new WSServerHandler());
                            }
                        });
    
                // 绑定端口,启动服务
                ChannelFuture future = bootstrap.bind(port).sync();
                System.out.println("server started and listen " + port);
                // 监听关闭
                future.channel().closeFuture().sync();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                boss.shutdownGracefully();
                work.shutdownGracefully();
            }
        }
    }

      

      WSServerHandler

    package com.oy.ws;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
    
    import java.time.LocalDateTime;
    
    /**
     * WebSocketFrame: 表示一个文本帧
     */
    public class WSServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
            System.out.println("服务器收到消息:" + msg.text());
    
            // 回复消息
            ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器时间:" + LocalDateTime.now()
                    + ", " + msg.text()));
        }
    
        /**
         * 当 web 客户端连接后,触发该方法
         */
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            // longText 是唯一的
            System.out.println("handlerAdded 被调用" + ctx.channel().id().asLongText());
            System.out.println("handlerAdded 被调用" + ctx.channel().id().asShortText());
        }
    
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            System.out.println("handlerRemoved 被调用" + ctx.channel().id().asLongText());
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            System.out.println("发生异常:" + cause.getMessage());
            ctx.close();
        }
    }

      hello.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form onsubmit="return false">
            <textarea name="message" style="height:300px;300px;"></textarea>
            <input type="button" value="发送消息" onclick="send(this.form.message.value)"/>
            <textarea id="responseText" style="height:300px;300px;"></textarea>
            <input type="button" value="清空" onclick="document.getElementById('responseText').value=''"/>
        </form>
    </body>
    <script>
        var socket;
        // 判断当前浏览器是否支持 websocket
        if(window.WebSocket){
            socket = new WebSocket("ws://localhost:8002/hello");
            // ev:收到服务器返回的消息
            socket.onmessage = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = rt.value + "
    " + ev.data;
            }
    
            // 连接开启
            socket.onopen = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = "连接开启了";
            }
            // 连接关闭
            socket.onclose = function (ev) {
                var rt = document.getElementById("responseText");
                rt.value = rt.value + "
    " + "连接关闭了";
            }
        } else {
            alert("当前浏览器不支持 WebSocket");
        }
    
        // 客户端发送消息给服务器
        function send(message) {
            // 先判断 socket 是否创建好
            if (!window.socket) {
                return;
            }
            if (socket.readyState == WebSocket.OPEN) {
                // 通过 socket 发送消息
                socket.send(message);
            } else {
                alert("连接失败");
            }
        }
    
    </script>
    </html>

    测试:

      1)启动服务端 WSServer;

      2)启动客户端

     

      3)客户端发送消息给服务器,服务器返回消息给客户端

      ---

  • 相关阅读:
    防止SQL注入
    Sql Server参数化查询之where in和like实现详解
    NET下载文件报错System.UnauthorizedAccessException的解决方法
    hibernate 中的session和事务(Transaction)
    ASP.net MVC 文件下载的几种方法
    SQLServer中查询表结构(表主键 、列说明、列数据类型、所有表名)的Sql语句
    NHibernate 中删除数据的几种方法
    SQL、LINQ、Lambda 三种用法(转)
    .net MVC 单页面 多个(行)数据修改
    绘制你的第一个图表(jquery-flot-line-chart)
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/12825111.html
Copyright © 2011-2022 走看看