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;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> <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 + "\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) { // 先判断 socket 是否创建好 if (!window.socket) { return; } if (socket.readyState == WebSocket.OPEN) { // 通过 socket 发送消息 socket.send(message); } else { alert("连接失败"); } } </script> </html>
测试:
1)启动服务端 WSServer;
2)启动客户端
3)客户端发送消息给服务器,服务器返回消息给客户端
---
posted on 2020-05-04 03:55 wenbin_ouyang 阅读(1432) 评论(0) 编辑 收藏 举报