Netty 入门应用之Http服务WebSocket

Netty实现Http服务

主要的变化是在初始化器中引入了新的编解码器
一些创建的类作用和Netty HelloWorld的小demo一样我这里就不再次重复了

1、Http服务端代码

public class HttpServer {public static void main(String[] args) {// 创建Reactor// 用来管理channel 监听事件 ,是无限循环的事件组(线程池)EventLoopGroup bossLoopGroup = new NioEventLoopGroup();EventLoopGroup workerLoopGroup = new NioEventLoopGroup();// 服务端的启动对象ServerBootstrap serverBootstrap = new ServerBootstrap();// 设置相关参数  这是一个链式编程serverBootstrap.group(bossLoopGroup,workerLoopGroup)// 声明通道类型.channel(NioServerSocketChannel.class)// 设置处理器  我这里设置了netty提供的Handler 处理器.handler(new LoggingHandler(LogLevel.INFO))// 定义客户连接端处理器的使用// ChannelInitializer 通道处理化// 可以自定义通道初始化器,如实现编码解码器时.childHandler(new ChannelInitializer<SocketChannel>() {protected void initChannel(SocketChannel ch) throws Exception {// 需要处理的是客户端通道// 通道代表的是 连接的角色 管道代表的是 处理业务的逻辑管理// 管道相当与一个链表, 将不同的处理器连接起来,管理的是处理器的顺序ch.pipeline().addLast(new HttpMyInitializer());}});System.out.println("服务端初始化完成");// 启动需要设置端口  还需要设置是异步启动try {// 设置异步的futureChannelFuture future = serverBootstrap.bind(9988).sync();// 将关闭的通道也设置成异步的// 阻塞finally 中的代码future.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();}finally {// 优雅关闭bossLoopGroup.shutdownGracefully();workerLoopGroup.shutdownGracefully();}}
}

1.1 Http服务自定义初始化器

下面是需要了解的组件
请求和响应的编码解码器:
客户端
HttpResponseDecoder 解码器,
处理服务端的响应(客户端)
HttpRequestEncoder 编码器,
处理服务端的请求(客户端)
服务端
HttpRequestDecoder 解码器,
处理客户端的请求(服务端)
HttpResponseEncoder 编码器,
处理客户端的响应(服务端)
由于上面的编码解码器都比较绕,所以还有两个组合的类提供
HttpClientCodeC :
编码解码器,用于客户端 HttpResponseDecoder + HttpRequestEncoder
HttpServerCodeC:
编码解码器,用于服务端 HttpRequestDecoder + HttpResponseEncoder

聚合
由于http的请求和响应,可能由很多部分组成,需要聚合成一个完整的消息
HttpObjectAggregator -> FullHttpRequest / FullHttpResponse

压缩
由于网络上有些情况文件或者图片需要压缩,所以需要压缩处理器
HttpContentCompressor 压缩,用于服务端
HttpContentDecompressor 解压缩,用于客户端

自定义初始化器HttpMyInitializer 需要继承ChannelInitializer泛型是Channel


public class HttpMyInitializer extends ChannelInitializer<Channel> {@Overrideprotected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// 先解码后编码
//        pipeline.addLast("decoder",new HttpRequestDecoder());
//        pipeline.addLast("encoder",new HttpResponseEncoder());// 相当于上面两行pipeline.addLast("codec",new HttpServerCodec());// 压缩数据pipeline.addLast("compressor",new HttpContentCompressor());// 聚合成完整的消息  参数代表处理的最大值pipeline.addLast("aggregator",new HttpObjectAggregator(512 * 1024));// 添加处理器pipeline.addLast(new MyHttpHandler());}
}

1.2 Http服务自定义处理器

需要继承SimpleChannelInboundHandler类注意的是泛型需要定义为 FullHttpRequest


/*** 泛型需要定义为 FullHttpRequest**/
public class MyHttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {/**** @param ctx 通道处理器上下文* @param msg 接收客户端数据消息* @throws Exception*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {// 设定 版本 、响应码、响应的数据(ByteBuf) 等DefaultFullHttpResponse response =new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer("http hello netty demo ".getBytes()));// 还需要设置响应头 HttpHeaders 来接收// 设置字段名 使用HttpHeaderNames ,字段值使用HttpHeaderValuesHttpHeaders headers = response.headers();//content/type ;text/plainheaders.add(HttpHeaderNames.CONTENT_TYPE,HttpHeaderValues.TEXT_PLAIN+"charset=UTF-8");// 设置包的大小时, 调用 readableBytes方法headers.add(HttpHeaderNames.CONTENT_LENGTH,response.content().readableBytes());// 将response 写入通道  这里不用writeAndFlush方法, 而是在channelReadComplete读完成的方法内来刷新通道ctx.write(response);}/***  用来刷新channelRead0 写入通道里面的response 数据* @param ctx* @throws Exception*/@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.flush();}
}

1.3 Http服务最后展示结果

启动服务端、客户端我展示代码,可以随便启动一个我之前的小demo客户端记得改端口9988就行

在这里插入图片描述

客户端控制台展示

访问localhost:9988
在这里插入图片描述

在Edge浏览器展示

Netty实现WebSocket服务

http协议的缺陷: 通信只能由客户端发起。需要一种服务端能够主动推送的能力—websocket。这种双向通信的能力,也叫“全双工”。
协议标识符: http://127.0.0.1/ -> ws://127.0.0.1/
通信的最小单位是frame。

2、WebSocket服务服务端代码

同样的配方,大同小异, 只是初始化器和处理器不同,需要自定义


public class WebSocketServer {public static void main(String[] args) {// 创建Reactor// 用来管理channel 监听事件 ,是无限循环的事件组(线程池)EventLoopGroup bossLoopGroup = new NioEventLoopGroup();EventLoopGroup workerLoopGroup = new NioEventLoopGroup();// 服务端的启动对象ServerBootstrap serverBootstrap = new ServerBootstrap();// 设置相关参数  这是一个链式编程serverBootstrap.group(bossLoopGroup,workerLoopGroup)// 声明通道类型.channel(NioServerSocketChannel.class)// 设置处理器  我这里设置了netty提供的Handler 处理器.handler(new LoggingHandler(LogLevel.INFO))// 定义客户连接端处理器的使用// ChannelInitializer 通道处理化// 可以自定义通道初始化器,如实现编码解码器时.childHandler(new WebSocketInitializer());System.out.println("服务端初始化完成");// 启动需要设置端口  还需要设置是异步启动try {// 设置异步的futureChannelFuture future = serverBootstrap.bind(7777).sync();// 将关闭的通道也设置成异步的// 阻塞finally 中的代码future.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();}finally {// 优雅关闭bossLoopGroup.shutdownGracefully();workerLoopGroup.shutdownGracefully();}}
}

2.1 WebSocket服务自定义初始化器

继承ChannelInitializer 泛型是SocketChannel


public class WebSocketInitializer extends ChannelInitializer<SocketChannel> {/**** @param ch* @throws Exception*/@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();// 设置编码解码器pipeline.addLast(new HttpServerCodec());// 用于处理较大的数据pipeline.addLast(new ChunkedWriteHandler());// 设置聚合器pipeline.addLast(new HttpObjectAggregator(512 * 1024));// 声明请求路径 ws://127.0.0.1:7777/hellopipeline.addLast(new WebSocketServerProtocolHandler("/hello"));// 自定义处理器pipeline.addLast(new WebSocketHandler());}
}

2.2 WebSocket服务自定义处理器

主要的是channelRead0方法

/***  本次业务处理的数据是文本, WebSocket通信是通过帧来传输*  所以泛型为 TextWebSocketFrame*/
public class WebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {// 当多个通道传入handler , 使用通道组的管理方法// GlobalEventExecutor 全局事件执行器//INSTANCE 代表的是单例private  static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);/**** @param ctx 通道处理器上下文* @param msg 文本消息帧* @throws Exception*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {// 浏览器返回的信息帧System.out.println("msg:"+msg.text());Channel channel = ctx.channel();// 需要响应会浏览器的信息, 需要是TextWebSocketFrame 类型TextWebSocketFrame webSocketFrame = new TextWebSocketFrame(ctx.channel().remoteAddress()+"客户端:"+msg.text()+"\r\n");channel.writeAndFlush(webSocketFrame);}/***  连接成功, 此时通道是活跃的时候触发* @param ctx* @throws Exception*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {LocalDate today = LocalDate.now();String dateStr = today.toString(); // 默认格式为 "yyyy-MM-dd"ctx.writeAndFlush("Welcome to server-- now :"+dateStr+"\r\n");}/***  通道不活跃 ,用于处理用户下线的逻辑* @param ctx* @throws Exception*/@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {System.out.println(ctx.channel().remoteAddress()+"下线了\r\n");}/**** @param ctx 通道处理器上下文* @throws Exception* 连接刚刚建立时 ,第一个被执行的方法,*/@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {System.out.println("[服务端地址]:"+ctx.channel().remoteAddress()+"连接成功\r\n");// 添加到通道组中管理channelGroup.add(ctx.channel());}/**** @param ctx  通道处理器上下文* @throws Exception* 当连接断开 最后执行的方法* 连接断开时 , channel 会自动从 通道组中移除*/@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception {System.out.println("[服务端地址]:"+ctx.channel().remoteAddress()+"断开连接\r\n");}/***  通用异常处理类* @param ctx 通道处理器上下文* @param cause* @throws Exception*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// 关闭ctx.close();}
}

2.3 WebSocket服务前端界面

实现一个聊天的小demo

在这里插入图片描述

WebSocket客户端建立连接流程

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Hello WebSocket</title>
</head>
<body><script>var socket;// 判断当前浏览器是否支持websocktif (!window.WebSocket) {alert("不支持websocket")} else {socket = new WebSocket("ws://127.0.0.1:7777/hello");// 设置开启连接的方法socket.onopen = function (ev) {var tmp = document.getElementById("respText");tmp.value = "连接已开启";}// 设置关闭连接的方法socket.onclose = function (ev) {var tmp = document.getElementById("respText");tmp.value = tmp.value + "\n" + "连接已关闭";}// 设置接收数据的方法socket.onmessage = function (ev) {var tmp = document.getElementById("respText");tmp.value = tmp.value + "\n" + ev.data;}}function send(message) {// 先判断socket是否已经创建if (!window.socket) {return}// 判断socket的状态//   CONNECTING  正在连接    CLOSING  正在关闭//   CLOSED  已经关闭或打开连接失败//   OPEN  连接成功 可以正常通信if (socket.readyState == WebSocket.OPEN) {socket.send(message);} else {alert("连接未开启");}}
</script><!--防止表单自动提交-->
<form onsubmit="return false"><textarea name="message" style="height: 400px;width: 400px"></textarea><input type="button" value="发送" onclick="send(this.form.message.value)"><textarea id="respText" style="height: 400px;width: 400px"></textarea>
</form></body>
</html>

2.3 WebSocket结果展示

启动WebSocke服务器,运行前端代码如下如所示:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/805409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hot100【十一】:最大子数组和

// 定义dp&#xff1a;以i结尾的最大子数组和 dp[i] max(dp[i-1] nums[i],nums[i]) class Solution {public int maxSubArray(int[] nums) {// 1. 不需要特殊处理// 2. 定义dpint[] dp new int[nums.length];dp[0] nums[0];int maxResult nums[0];// 3. dp递推for (int i …

微服务面试题一

1.SOA、分布式、微服务之间有什么关系和区别&#xff1f; 分布式架构是指将单体架构中的各个部分拆分&#xff0c;然后部署不同的机器或进程中去&#xff0c;SOA和微服务基 本上都是分布式架构的SOA是⼀种⾯向服务的架构&#xff0c;系统的所有服务都注册在总线上&#xff0c;…

TLF9471 - High-Speed CAN FD Transceiver

1 框图描述 2 功能描述 CAN收发器被设计用来承受汽车应用的恶劣条件&#xff0c;并支持12V应用。   SBC的控制器区域网络&#xff08;CAN&#xff09;收发器部分在汽车和工业应用中提供高速&#xff08;HS&#xff09;差分模式数据传输&#xff08;最高可达2Mbaud&#xff09…

【Java基础】BigDecimal使用避坑规范

BigDecimal使用 解决浮点型运算时&#xff0c;出现结果失真的问题&#xff0c;比如0.10.2 —示例— public class ErrorCase {public static void main(String[] args) {// 0.30000000000000004System.out.println(0.1 0.2);} }构造方法 把string转成BigDecimal把double转B…

备战蓝桥杯Day40 - 第11届python组真题 - C跑步锻炼

一、题目描述 二、思路 1、使用datetime库中的方法可以很好的解决这个问题。 2、定义起始时间和结束时间&#xff0c;判断是否是周一或者是1号&#xff0c;结果res加上相应的里程数。 3、最后输出 res 即为本题答案。 三、代码实现 import datetimestart datetime.date(2…

深度学习图像处理04:图像分类模型训练实战——动物分类

这篇博文不涉及理论知识&#xff0c;主要通过一个完整的深度学习模型训练流程&#xff0c;直观地了解深度学习图像分类任务。有关理论的部分&#xff0c;之前几篇博文已经涉及基础部分&#xff0c;之后也会对一些理论进行补充。 本文将结合代码&#xff0c;主要介绍三部分内容…

OpenHarmony应用编译 - 如何在源码中编译复杂应用(4.0-Release)

文档环境 开发环境&#xff1a;Windows 11 编译环境&#xff1a;Ubuntu 22.04 开发板型号&#xff1a;DAYU 200&#xff08;RK3568&#xff09; 系统版本&#xff1a;OpenHarmony-4.0-Release 功能简介 在 OpenHarmony 系统中预安装应用的 hap 包会随系统编译打包到镜像中&a…

SpringBoot常用注解及其使用示例

Spring Boot是一个用于快速构建Java应用程序的框架&#xff0c;它简化了Spring应用程序的创建和部署过程。 Spring Boot提供了很多注解&#xff0c;用于简化开发过程&#xff0c;提高开发效率。本文将介绍几个Spring Boot常用注解的使用案例&#xff0c;包括Controller、Reques…

c#获取Web.Config中的值出现的错误及解决办法

c#获取Web.Config中的值出现的错误及解决办法 1.错误提示 2.原因寻找 问题出在Web.Config文件中 <add key"mchid " value"1495103432"/>//mchid 后面不应该有空格图示如下&#xff1a; 3.改正代码如下&#xff1a; <?xml version"1.0…

022——设计通信帧格式

本期没想好怎么排版以流水账形式展示了 int tcp_server(int argc, char *argv[]) {int server_fd, client_fd; struct sockaddr_in server_addr, client_addr; socklen_t client_len sizeof(client_addr); char *ip_address argv[1]; int port atoi(argv[2]); // 创建T…

Capture One 23 Enterprise for Mac中文版 全面的图像处理工具

Capture One 23 Enterprise for Mac中文版一款专业的图像编辑和管理软件&#xff0c;具备强大的功能和工具&#xff0c;适用于摄影师、摄影工作室和专业用户。 软件下载&#xff1a;Capture One 23 Enterprise for Mac中文版下载 该软件为用户提供了全面的图像处理工具&#xf…

SpringCloudAlibaba-整合nacos(二)

目录地址&#xff1a; SpringCloudAlibaba整合-CSDN博客 一、nacos服务部分 1.下载nacos&#xff0c;并执行数据库脚本&#xff1a;nacos-mysql.sql 2.修改配置文件&#xff0c;配置mysql 3.启动nacos ./startup.sh -m standalone 4.访问&#xff1a;http://127.0.0.1:884…

Terraform 扩展

Terraform 扩展 Terraform Meta-Arguments 元参数 count 创建相似的资源for_each 创建相似的资源depends_on 定义资源或者模块的依赖provider 定义provider选项lifecycle 资源的生命周期行为 参数使用范围备注countresource module适用于创建多个相似的资源&#xff0c;使用…

1999-2022年各省研究与试验发展人员全时当量数据/省研发人员全时当量数据/(RD)人员全时当量(无缺失)

1999-2022年各省研究与试验发展人员全时当量数据/省研发人员全时当量数据/(R&D)人员全时当量&#xff08;无缺失&#xff09; 1、时间&#xff1a;1999-2022年 2、来源&#xff1a;科技年鉴 3、指标&#xff1a;研究与试验发展人员全时当量/研发人员全时当量 4、范围&a…

软考-系统集成项目管理中级-新一代信息技术

本章历年考题分值统计 本章重点常考知识点汇总清单(掌握部分可直接理解记忆) 本章历年考题及答案解析 32、2019 年上半年第 23 题 云计算通过网络提供可动态伸缩的廉价计算能力&#xff0c;(23)不属于云计算的特点。 A.虚拟化 B.高可扩展性 C.按需服务 D.优化本地存储 【参考…

Docker快速上手及常用命令速查

Docker快速上手 安装 在ubuntu上安装docker: sudo apt-get install docker docker -v #查看版本在centos7上安装docker&#xff1a;(docker在YUM源的Extras仓库中) yum install docker systemctl start dockerdocker常用命令速查 #查看docker信息 docker info #查看本地镜…

hive 数据库表常用操作及相关函数讲解

创建数据库并指定hdfs存储位置 create database myhive2 location ‘/myhive2’; 使用location关键字&#xff0c;可以指定数据库在HDFS的存储路径。 Hive的库在HDFS上就是一个以.db结尾的目录 默认存储在&#xff1a; /user/hive/warehouse内 当你为Hive表指定一个LOCATION时…

NumPy入门(一)

NumPy入门(一) 工具: jupyter notebook jupyter notebook 功能 : 数据处理 &#xff08;python 处理数据功能&#xff09; coding文字型的描述 富文本 word可视化支持 官网: https://jupyter.org/ 启动命令 jupyter notebook 1.1 numpy简介 Python的拓展库, 提供数据对象 nda…

【数据下载】SODA数据更新至2022并教学下载

【数据下载】SODA数据更新至2022并教学下载 我为什么那么喜欢使用SODA数据&#xff1f; 就是三维网格化的数据&#xff0c;好用。 但是需要高分辨率还是需要找别的。 以前分享过SODA数据下载&#xff0c;但上次版本过于凌乱。因此重新借助更新再分享一次&#xff0c;不为过。…