 
Server
- public class Server {
-     public static void main(String[] args) throws InterruptedException {
-         EventLoopGroup bossGroup = new NioEventLoopGroup(1);
-         EventLoopGroup workerGroup = new NioEventLoopGroup();
-         try {
-             ServerBootstrap serverBootstrap = new ServerBootstrap();
-             serverBootstrap.group(bossGroup, workerGroup)
-                     .channel(NioServerSocketChannel.class)
-                     .handler(new LoggingHandler(LogLevel.INFO))
-                     .childHandler(new ChannelInitializer<SocketChannel>() {
-                         @Override
-                         protected void initChannel(SocketChannel ch) throws Exception {
-                             ChannelPipeline pipeline = ch.pipeline();
-                             //使用Http的编解码器
-                             pipeline.addLast(new HttpServerCodec());
-                             //以块方式写,添加ChunkedWriteHandler处理器
-                             pipeline.addLast(new ChunkedWriteHandler());
-                             /*
-                             1.Http协议在传输过程中是分段的,HttpObjectAggregator就是可以将多个段聚合
-                             2.这就是为什么当浏览器发送大量数据时,就会发出多次http请求的原因
-                              */
-                             pipeline.addLast(new HttpObjectAggregator(8192));
-                             /*
-                             1.对应WebSocket,它的数据是以帧(frame)的形式传递
-                             2.可以看到WEbSocketFrame 下面有六个子类
-                             WebSocketServerProtocolHandler作用:
-                             3.浏览器发送请求时 ws://localhost:7000/hello--识别请求的资源
-                             4.将一个Http协议升级为WS协议,即WebSocket协议--保存长连接
-                              */
-                             pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));
-                             //自定义handler,处理业务逻辑
-                             pipeline.addLast(new TextWebSocketFrameHandler());
-                         }
-                     });
-             ChannelFuture future = serverBootstrap.bind(7000).sync();
-             future.channel().closeFuture().sync();
-         } finally {
-             bossGroup.shutdownGracefully();
-             workerGroup.shutdownGracefully();
-         }
-     }
- }
Handler
- //TextWebSocketFrame表示一个文本帧(frame)
- public 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("服务器时间" + LocalDateTime.now() + "" + msg.text()));
-     }
-     //感知连接
-     @Override
-     public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
-         //id是一个唯一的值, LongText是唯一的
-         System.out.println("handlerAdded 被调用" + ctx.channel().id().asLongText());
-         //ShortText不是唯一的
-         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(); //关闭连接
-     }
- }
- <!DOCTYPE html>
- <html lang="en">
- <head>
-     <meta charset="UTF-8">
-     <title>Title</title>
- </head>
- <!--复制到Vscode-->
- <body>
- <script>
-     var socket;
-     //判断当前浏览器是否支持websocket
-     if(window.WebSocket) {
-         //go on
-         socket = new WebSocket("ws://localhost:7000/hello");
-         //相当于channelReado, ev 收到服务器端回送的消息
-         socket.onmessage = function (ev) {
-             var rt = document.getElementById("responseText");
-             rt.value = rt.value + "\n" + 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 + "\n" + "连接关闭了.."
-         }
-     } else {
-         alert("当前浏览器不支持websocket")
-     }
-     //发送消息到服务器
-     function send(message) {
-         if(!window.socket) { //先判断socket是否创建好
-             return;
-         }
-         if(socket.readyState == WebSocket.OPEN) {
-             //通过socket 发送消息
-             socket.send(message)
-         } else {
-             alert("连接没有开启");
-         }
-     }
- </script>
- <form onsubmit="return false">
-     <textarea name="message" style="height: 300px; width: 300px"></textarea>
-     <input type="button" value="发送消息" onclick="send(this.form.message.value)">
-     <textarea id="responseText" style="height: 300px; width: 300px"></textarea>
-     <input type="button" value="清空内容" onclick="document.getElementById('responseText').value=''">
- </form>
- </body>
- </html>