Netty5 + WebSocket 练习

2023-12-19 15:38
文章标签 练习 websocket netty5

本文主要是介绍Netty5 + WebSocket 练习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Netty5 + WebSocket 练习

1. 了解WebSocket知识
  略
2. websocket实现系统简单反馈时间

  WebSocketServerHandler.java

复制代码
 1 package com.jieli.nettytest.websocketserver;
 2 
 3 import io.netty.bootstrap.ServerBootstrap;
 4 import io.netty.channel.ChannelFuture;
 5 import io.netty.channel.ChannelInitializer;
 6 import io.netty.channel.EventLoopGroup;
 7 import io.netty.channel.nio.NioEventLoopGroup;
 8 import io.netty.channel.socket.SocketChannel;
 9 import io.netty.channel.socket.nio.NioServerSocketChannel;
10 import io.netty.handler.codec.http.HttpObjectAggregator;
11 import io.netty.handler.codec.http.HttpServerCodec;
12 import io.netty.handler.stream.ChunkedWriteHandler;
13 
14 public class WebSocketServer {
15     
16     public void run(int port){
17         EventLoopGroup bossGroup = new NioEventLoopGroup();
18         EventLoopGroup workerGroup = new NioEventLoopGroup();
19         try {
20             ServerBootstrap b = new ServerBootstrap();
21             b.group(bossGroup, workerGroup)
22              .channel(NioServerSocketChannel.class)
23              .childHandler(new ChannelInitializer<SocketChannel>() {
24                 @Override
25                 protected void initChannel(SocketChannel ch) throws Exception {
26                     //HttpServerCodec将请求和应答消息编码或解码为HTTP消息
27                     //通常接收到的http是一个片段,如果想要完整接受一次请求所有数据,我们需要绑定HttpObjectAggregator
28                     //然后就可以收到一个FullHttpRequest完整的请求信息了
29                     //ChunkedWriteHandler 向客户端发送HTML5文件,主要用于支持浏览器和服务器进行WebSocket通信
30                     //WebSocketServerHandler自定义Handler
31                     ch.pipeline().addLast("http-codec", new HttpServerCodec())
32                                  .addLast("aggregator", new HttpObjectAggregator(65536)) //定义缓冲大小
33                                  .addLast("http-chunked", new ChunkedWriteHandler())
34                                  .addLast("handler", new WebSocketServerHandler());
35                 }
36             });
37             
38             ChannelFuture f = b.bind(port).sync();
39             System.out.println("start...");
40             f.channel().closeFuture().sync();
41         } catch (Exception e) {
42             e.printStackTrace();
43         } finally {
44             workerGroup.shutdownGracefully();
45             bossGroup.shutdownGracefully();
46         }
47     }
48     
49     public static void main(String[] args) {
50         new WebSocketServer().run(7777);
51     }
52 }
复制代码

  WebSocketServerHandler.java

复制代码
  1 package com.jieli.nettytest.websocketserver;
  2 
  3 import java.util.logging.Level;
  4 import java.util.logging.Logger;
  5 
  6 import io.netty.buffer.ByteBuf;
  7 import io.netty.buffer.Unpooled;
  8 import io.netty.channel.ChannelFuture;
  9 import io.netty.channel.ChannelFutureListener;
 10 import io.netty.channel.ChannelHandlerContext;
 11 import io.netty.channel.SimpleChannelInboundHandler;
 12 import io.netty.handler.codec.http.DefaultFullHttpResponse;
 13 import io.netty.handler.codec.http.FullHttpRequest;
 14 import io.netty.handler.codec.http.FullHttpResponse;
 15 import io.netty.handler.codec.http.HttpHeaderUtil;
 16 import io.netty.handler.codec.http.HttpResponseStatus;
 17 import io.netty.handler.codec.http.HttpVersion;
 18 import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
 19 import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
 20 import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
 21 import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
 22 import io.netty.handler.codec.http.websocketx.WebSocketFrame;
 23 import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
 24 import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
 25 import io.netty.util.CharsetUtil;
 26 
 27 public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>{
 28 
 29     /**
 30      * 日志
 31      */
 32     private static final Logger logger = 
 33             Logger.getLogger(WebSocketServerHandler.class.getName());
 34     /**
 35      * 全局websocket
 36      */
 37     private WebSocketServerHandshaker handshaker;
 38     
 39     @Override
 40     protected void messageReceived(ChannelHandlerContext ctx, Object msg)
 41             throws Exception {
 42         //普通HTTP接入
 43         if(msg instanceof FullHttpRequest){
 44             handleHttpRequest(ctx, (FullHttpRequest) msg);
 45         }else if(msg instanceof WebSocketFrame){ //websocket帧类型 已连接
 46             //BinaryWebSocketFrame CloseWebSocketFrame ContinuationWebSocketFrame 
 47             //PingWebSocketFrame PongWebSocketFrame TextWebScoketFrame
 48             handleWebSocketFrame(ctx, (WebSocketFrame) msg);
 49         }
 50     }
 51     
 52     @Override
 53     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
 54         ctx.flush();
 55     }
 56     
 57     private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request){
 58         //如果http解码失败 则返回http异常 并且判断消息头有没有包含Upgrade字段(协议升级)
 59         if(!request.decoderResult().isSuccess() 
 60                 || (!"websocket".equals( request.headers().get("Upgrade")))    ){
 61             sendHttpResponse(ctx, request, new DefaultFullHttpResponse(
 62                     HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
 63             return ;
 64         }
 65         //构造握手响应返回
 66         WebSocketServerHandshakerFactory ws = new WebSocketServerHandshakerFactory("", null, false);
 67         handshaker = ws.newHandshaker(request);
 68         if(handshaker == null){
 69             //版本不支持
 70             WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
 71         }else{
 72             handshaker.handshake(ctx.channel(), request);
 73         }
 74     }
 75     /**
 76      * websocket帧
 77      * @param ctx
 78      * @param frame
 79      */
 80     private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){
 81         //判断是否关闭链路指令
 82         if(frame instanceof CloseWebSocketFrame){
 83             handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
 84             return ;
 85         }
 86         //判断是否Ping消息 -- ping/pong心跳包
 87         if(frame instanceof PingWebSocketFrame){
 88             ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
 89             return ;
 90         }
 91         //本程序仅支持文本消息, 不支持二进制消息
 92         if(!(frame instanceof TextWebSocketFrame)){
 93             throw new UnsupportedOperationException(
 94                     String.format("%s frame types not supported", frame.getClass().getName()));
 95         }
 96         
 97         //返回应答消息 text文本帧
 98         String request = ((TextWebSocketFrame) frame).text();
 99         //打印日志
100         if(logger.isLoggable(Level.FINE)){
101             logger.fine(String.format("%s received %s", ctx.channel(), request));
102         }
103         //发送到客户端websocket
104         ctx.channel().write(new TextWebSocketFrame(request 
105                 + ", 欢迎使用Netty WebSocket服务, 现在时刻:" 
106                 + new java.util.Date().toString()));
107     }
108     
109     /**
110      * response
111      * @param ctx
112      * @param request
113      * @param response
114      */
115     private static void sendHttpResponse(ChannelHandlerContext ctx, 
116             FullHttpRequest request, FullHttpResponse response){
117         //返回给客户端
118         if(response.status().code() != HttpResponseStatus.OK.code()){
119             ByteBuf buf = Unpooled.copiedBuffer(response.status().toString(), CharsetUtil.UTF_8);
120             response.content().writeBytes(buf);
121             buf.release();
122             HttpHeaderUtil.setContentLength(response, response.content().readableBytes());
123         }
124         //如果不是keepalive那么就关闭连接
125         ChannelFuture f = ctx.channel().writeAndFlush(response);
126         if(!HttpHeaderUtil.isKeepAlive(response) 
127                 || response.status().code() != HttpResponseStatus.OK.code()){
128             f.addListener(ChannelFutureListener.CLOSE);
129         }
130     }
131     
132     /**
133      * 异常 出错
134      */
135     @Override
136     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
137             throws Exception {
138         cause.printStackTrace();
139         ctx.close();
140     }
141 }
复制代码

  WebSocketServer.html (这个随便放都可以,到时候双击打开这个即可,不由服务器提供)

复制代码
 1 <html>
 2     <head>
 3         <meta charset="utf-8">
 4         <title>Netty websocket 时间服务器</title>
 5     </head>
 6     <body>
 7         <form action="" onsubmit="return false;">
 8             <input type="text" name="message" value="..."/>
 9             <br>
10             <input type="button" value="send" value="发送websocket请求消息" onclick="send(this.form.message.value);" /> 
11             <hr color="blue">
12             <h3>服务器返回信息</h3>
13             <textarea id="responseText" rows="10" cols=""></textarea>
14         </form>
15     </body>
16     
17     <script type="text/javascript">
18         var socket;
19         if(!window.WebSocket){
20             window.WebSocket = window.MozWebSocket;
21         }
22         if(window.WebSocket){
23             socket = new WebSocket("ws://localhost:7777/websocket");
24             socket.onmessage = function(event){
25                 var ta = document.getElementById('responseText');
26                 ta.value="";
27                 ta.value=event.data;
28             };
29             socket.onopen = function(event){
30                 var ta = document.getElementById('responseText');
31                 ta.value = "打开websocket服务正常";
32             }
33             socket.onclose = function(event){
34                 var ta = document.getElementById('responseText');
35                 ta.value="";
36                 ta.value="websocket关闭";
37             }
38         }else{
39             alert("对不起,您的浏览器不支持WebSocket.");
40         }
41         
42         function send(message){
43             if(!window.WebSocket){
44                 return ;
45             }
46             if(socket.readyState == WebSocket.OPEN){
47                 socket.send(message);
48             }else{
49                 alert("WebSocket 连接创建失败.");
50             }
51         }
52     </script>
53 </html>
复制代码

  运行结果

3. websocket实现简单聊天室

  WebSocketChatServer.java

 

复制代码
 1 package com.jieli.nettytest.websocket;
 2 
 3 import io.netty.bootstrap.ServerBootstrap;
 4 import io.netty.channel.ChannelFuture;
 5 import io.netty.channel.ChannelOption;
 6 import io.netty.channel.EventLoopGroup;
 7 import io.netty.channel.nio.NioEventLoopGroup;
 8 import io.netty.channel.socket.nio.NioServerSocketChannel;
 9 
10 public class WebsocketChatServer {
11     
12     private int port;
13     
14     public WebsocketChatServer(int port){
15         this.port = port;
16     }
17     
18     public void run() throws Exception{
19         EventLoopGroup bossGroup = new NioEventLoopGroup();
20         EventLoopGroup workerGroup = new NioEventLoopGroup();
21         try {
22             ServerBootstrap b = new ServerBootstrap();
23             b.group(bossGroup, workerGroup)
24              .channel(NioServerSocketChannel.class)
25              .childHandler(new WebsocketChatServerInitializer())
26              .option(ChannelOption.SO_BACKLOG, 128)
27              .childOption(ChannelOption.SO_KEEPALIVE, true);
28             
29             System.out.println("websocket start..");
30 
31             ChannelFuture f = b.bind(port).sync();
32             
33             f.channel().closeFuture().sync();
34         } catch (Exception e) {
35             e.printStackTrace();
36         } finally {
37             workerGroup.shutdownGracefully();
38             bossGroup.shutdownGracefully();
39             System.out.println("websocket close.");
40         }
41     }
42     
43     public static void main(String[] args) throws Exception{
44         new WebsocketChatServer(8080).run();
45     }
46 }
复制代码

 

  WebsocketChatServerInitializer.java

复制代码
 1 package com.jieli.nettytest.websocket;
 2 
 3 import io.netty.channel.ChannelInitializer;
 4 import io.netty.channel.ChannelPipeline;
 5 import io.netty.channel.socket.SocketChannel;
 6 import io.netty.handler.codec.http.HttpObjectAggregator;
 7 import io.netty.handler.codec.http.HttpServerCodec;
 8 import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
 9 import io.netty.handler.stream.ChunkedWriteHandler;
10 
11 public class WebsocketChatServerInitializer extends ChannelInitializer<SocketChannel>{
12 
13     @Override
14     protected void initChannel(SocketChannel ch) throws Exception {
15         ChannelPipeline pipeline = ch.pipeline();
16         pipeline.addLast(new HttpServerCodec())
17                 .addLast(new HttpObjectAggregator(64*1024))
18                 .addLast(new ChunkedWriteHandler())
19                 .addLast(new HttpRequestHandler("/ws")) //如果访问的是RUI"/ws",处理WebSocket升级
20                 .addLast(new WebSocketServerProtocolHandler("/ws"))
21                 .addLast(new TextWebSocketFrameHandler());
22     }
23     
24 }
复制代码

   HttpRequestHandler.java

  View Code

  html/index.html

  View Code

  运行结果,依次运行1,2,3

  服务器打印结果

这篇关于Netty5 + WebSocket 练习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/512747

相关文章

JavaWeb-WebSocket浏览器服务器双向通信方式

《JavaWeb-WebSocket浏览器服务器双向通信方式》文章介绍了WebSocket协议的工作原理和应用场景,包括与HTTP的对比,接着,详细介绍了如何在Java中使用WebSocket,包括配... 目录一、概述二、入门2.1 POM依赖2.2 编写配置类2.3 编写WebSocket服务2.4 浏

SpringBoot实现websocket服务端及客户端的详细过程

《SpringBoot实现websocket服务端及客户端的详细过程》文章介绍了WebSocket通信过程、服务端和客户端的实现,以及可能遇到的问题及解决方案,感兴趣的朋友一起看看吧... 目录一、WebSocket通信过程二、服务端实现1.pom文件添加依赖2.启用Springboot对WebSocket

RabbitMQ练习(AMQP 0-9-1 Overview)

1、What is AMQP 0-9-1 AMQP 0-9-1(高级消息队列协议)是一种网络协议,它允许遵从该协议的客户端(Publisher或者Consumer)应用程序与遵从该协议的消息中间件代理(Broker,如RabbitMQ)进行通信。 AMQP 0-9-1模型的核心概念包括消息发布者(producers/publisher)、消息(messages)、交换机(exchanges)、

【Rust练习】12.枚举

练习题来自:https://practice-zh.course.rs/compound-types/enum.html 1 // 修复错误enum Number {Zero,One,Two,}enum Number1 {Zero = 0,One,Two,}// C语言风格的枚举定义enum Number2 {Zero = 0.0,One = 1.0,Two = 2.0,}fn m

MySql 事务练习

事务(transaction) -- 事务 transaction-- 事务是一组操作的集合,是一个不可分割的工作单位,事务会将所有的操作作为一个整体一起向系统提交或撤销请求-- 事务的操作要么同时成功,要么同时失败-- MySql的事务默认是自动提交的,当执行一个DML语句,MySql会立即自动隐式提交事务-- 常见案例:银行转账-- 逻辑:A给B转账1000:1.查询

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

html css jquery选项卡 代码练习小项目

在学习 html 和 css jquery 结合使用的时候 做好是能尝试做一些简单的小功能,来提高自己的 逻辑能力,熟悉代码的编写语法 下面分享一段代码 使用html css jquery选项卡 代码练习 <div class="box"><dl class="tab"><dd class="active">手机</dd><dd>家电</dd><dd>服装</dd><dd>数码</dd><dd

014.Python爬虫系列_解析练习

我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈 入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈 虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈 PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈 Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈 优

如何快速练习键盘盲打

盲打是指在不看键盘的情况下进行打字,这样可以显著提高打字速度和效率。以下是一些练习盲打的方法: 熟悉键盘布局:首先,你需要熟悉键盘上的字母和符号的位置。可以通过键盘图或者键盘贴纸来帮助记忆。 使用在线打字练习工具:有许多在线的打字练习网站,如Typing.com、10FastFingers等,它们提供了不同难度的练习和测试。 练习基本键位:先从学习手指放在键盘上的“家位”开始,通常是左手的

anaconda3下的python编程练习-csv翻译器

相关理解和命令 一、环境配置1、conda命令2、pip命令3、python命令 二、开发思路三、开发步骤 一、环境配置 1、conda命令 镜像源配置 conda config --show channels //查看镜像源conda config --remove-key channels //删除添加源,恢复默认源#添加镜像源conda config --ad