netty 权威指南~第11章——WebSoket协议开发

article/2025/9/14 15:04:32

本章主要学习内容如下:
1、WebSocket入门

2、Netty WebSocket协议开发

第节一:WebSocket入门

WebSocket是HTML5开始提供的一种浏览器与服务器进行全双通信的网络技术,WebSocket通信协议与2011年被IEIF定位标准RFC6455,WebsSocket api被W3c定为标准。

在WebSocket api中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间形成了一条快速通道,两者就可以之间互相传输消息数据了。WebSocket基于TCP双向全双工进行消息传递,同一时刻,既可以发送消息,也可以接受消息,相比HTTP的半双工协议,性能得到很大的提升。

下面总结一下WebSocket的特点

1、单一TCP连接,采用全双工模式通信。

2、对代理、防火墙和路由器透明。

3、无头部信息、Cookie和身份验证

4、无安全开销

5、通过ping/pong 帧保持链路激活状态

6、服务器可以主动传递消息给客户端,不需要客户端轮训。

WebSocket背景

WebSocket设计出来的目的就是取代轮训和Comet技术,使客户端浏览器具备向C/S架构下桌面系统一样的实时通讯能力。浏览器通过javascript 向服务器发出建立WebSocket连接的请求,连接成功后,客户端和服务端可以通过TCP直接交互数据。因为WebSocket连接本质上就是一个TCP连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮训即Comet技术相比,具有很大的优势。WebSocket.org网站对传统的轮训方式和WebSocket 调用方式作了一个详细的测试和比较,将一个简单的web应用分别通过轮训方式和websocket方式来实现,在这里引用一下测试结果,如图所示:
在这里插入图片描述
WebSocket 连接建立

客户端和服务端建立连接的示意图如下:
在这里插入图片描述
建立WebSocket连接时,需要通过客户端或者浏览器发出握手请求,请求消息如图所示:
在这里插入图片描述
为了建立一个WebSocket 连接,客户端浏览器首先向服务器发起一个HTTP请求,这个请求和通常的HTTP请求不同,包含了一些附加头信息,其中附加头信息“Upgrade:Websocket”表明这是一个申请协议升级的HTTP请求。服务端解析这些附加头信息,然后生成应答信息返回客户端,客户端和服务端的WebSoket连接就建立起来了,双方可以通过这个连接通道自由传递信息,并且这个连接会持续存在直到客户端或服务器端的某一方主动关闭连接。
在这里插入图片描述
请求消息中的"sec-websocket-key"是随机的,服务器会用这些数据构造出一个SHA-1的消息摘要,把“sec-websocket-key”加上一个魔幻字符串“*************”。使用SHA-1加密,然后进行Base64编码,将结果作为"sec-websocket-accept"头的值,返回给客户端。
WebSocket 生命周期

第三节:Netty WebSocket协议开发

Websocket服务端的功能如下:支持websocket的浏览器通过websocket协议发送请求消息给客户端,服务端对请求消息进行判断,如果是合法的websocket 请求,则获取请求消息文本,并在后面追加字符串“欢迎使用Netty websocket 服务”。

客户端HTML通过内嵌的js 脚本创建websocke 连接,如果握手成功,在文本框中打印“打开websocket 服务正常,浏览器支持websocket ”。客户端界面如图所示:
在这里插入图片描述
WebSocketServer.java

package com.viagra.chapter11.websocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
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.stream.ChunkedWriteHandler;/*** @Auther: viagra* @Date: 2019/8/2 13:59* @Description:*/
public class WebSocketServer {public void run(int port) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch)throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast("http-codec",new HttpServerCodec());pipeline.addLast("aggregator",new HttpObjectAggregator(65536));ch.pipeline().addLast("http-chunked",new ChunkedWriteHandler());pipeline.addLast("handler",new WebSocketServerHandler());}});Channel ch = b.bind(port).sync().channel();System.out.println("Web socket server started at port " + port+ '.');System.out.println("Open your browser and navigate to http://localhost:"+ port + '/');ch.closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}public static void main(String[] args) throws Exception {int port = 17888;new WebSocketServer().run(port);}
}

WebSocketServerHandler.java

package com.viagra.chapter11.websocket;import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil;import java.util.logging.Level;
import java.util.logging.Logger;
/*** @Auther: viagra* @Date: 2019/8/2 14:02* @Description:*/
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {private WebSocketServerHandshaker handshaker;@Overrideprotected void messageReceived(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {// WebSocket接入if (o instanceof WebSocketFrame) {System.out.println("request meesage body:"+o);handleWebSocketFrame(channelHandlerContext, (WebSocketFrame) o);}else if(o instanceof FullHttpRequest){System.out.println("server receiver message is:"+o);handleHttpRequest(channelHandlerContext, (FullHttpRequest) o);}}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.flush();}private void handleHttpRequest(ChannelHandlerContext ctx,FullHttpRequest req) throws Exception {// 构造握手响应返回,本机测试WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:17888/websocket", null, false);handshaker = wsFactory.newHandshaker(req);if (handshaker == null) {WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());} else {handshaker.handshake(ctx.channel(), req);}}private void handleWebSocketFrame(ChannelHandlerContext ctx,WebSocketFrame frame) {// 判断是否是关闭链路的指令if (frame instanceof CloseWebSocketFrame) {handshaker.close(ctx.channel(),(CloseWebSocketFrame) frame.retain());return;}// 判断是否是Ping消息if (frame instanceof PingWebSocketFrame) {ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));return;}// 本例程仅支持文本消息,不支持二进制消息if (!(frame instanceof TextWebSocketFrame)) {throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass().getName()));}// 返回应答消息String request = ((TextWebSocketFrame) frame).text();System.out.println("server receiver message is:"+request);ctx.channel().write(new TextWebSocketFrame(request+ " , welocme to:"+ new java.util.Date().toString()));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {ctx.close();}
}

client.html

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8">Netty WebSocket 时间服务器
</head>
<br>
<body>
<br>
<script type="text/javascript">var socket;if (!window.WebSocket){window.WebSocket = window.MozWebSocket;}if (window.WebSocket) {socket = new WebSocket("ws://localhost:17888/websocket");socket.onmessage = function(event) {var ta = document.getElementById('responseText');ta.value="";ta.value = event.data};socket.onopen = function(event) {var ta = document.getElementById('responseText');ta.value = "打开WebSocket服务正常,浏览器支持WebSocket!";};socket.onclose = function(event) {var ta = document.getElementById('responseText');ta.value = "";ta.value = "WebSocket 关闭!";};}else{alert("抱歉,您的浏览器不支持WebSocket协议!");}function send(message) {if (!window.WebSocket) { return; }if (socket.readyState == WebSocket.OPEN) {socket.send(message);}else{alert("WebSocket连接没有建立成功!");}}
</script>
<form οnsubmit="return false;"><input type="text" name="message" value="Netty最佳实践"/><br><br><input type="button" value="发送WebSocket请求消息" οnclick="send(this.form.message.value)"/><hr color="blue"/><h3>服务端返回的应答消息</h3><textarea id="responseText" style="width:500px;height:300px;"></textarea>
</form>
</body>
</html>

执行结果服务端:
在这里插入图片描述
客户端:
在这里插入图片描述


http://chatgpt.dhexx.cn/article/VtwcbCDF.shtml

相关文章

Netty权威指南 第2版

https://www.cnblogs.com/plxz/p/9910493.html 第一章  Java的I/O演进之路 1.I/O基础入门 1.Linux网络I/O模型简介 1.阻塞I/O模型&#xff1a;最常用的I/O模型&#xff0c;缺省情况下&#xff0c; 所有文件操作都是阻塞的 2.非阻塞I/O模型&#xff1a;recvform从应用层到内…

Netty权威指南总结(一)

一、为什么选择Netty&#xff1a; API使用简单&#xff0c;开发门槛低&#xff0c;屏蔽了NIO通信的底层细节。 功能强大&#xff0c;预制了很多种编解码功能&#xff0c;支持主流协议。 定制能力强&#xff0c;可以通过ChannelHandler对通信框架进行灵活地拓展。 性能高、成熟、…

Netty权威指南

Chapter1.java I/O演进之路 1.1I/O基础入门 在java 1.4之前&#xff0c;java程序员在开发高性能I/O程序的时候&#xff0c;会面临的问题主要有&#xff1a; 1.没有数据缓冲区&#xff0c;I/O性能存在问题 2.没有c或者c中的Channel概念&#xff0c;只有输入和输出流 3.同步…

三维视觉传感器的类型

三角法测量原理 视觉传感器的坐标系统 单一摄像机二维传感器 点结构光视觉传感器 线结构光视觉传感器 条纹结构光视觉传感器 条纹编码三维视觉传感器 彩色编码视觉传感器 被动双目视觉传感器 编码照明双目视觉传感器

传感器sensor

传感器分类 转换原理 传感器名称 典型应用 转换形式 中间参量 电 参 数 电 阻 移动电位器角点 改变电阻 电位器传感器 位移 改变电阻丝或片尺寸 电阻丝应变传感器、半导体应变传感器 微应变、力、负荷 利用电阻的温度效应 热丝传感器 气流速度、液体流量 电阻…

多任务多传感器数据融合实现3D目标检测

转载自&#xff1a;自动驾驶之心 01 引言 本文介绍一篇uber公司在CVPR上发表的一篇论文&#xff0c;即使用多种传感器&#xff08;LiDAR和RGB相机&#xff09;数据&#xff0c;以及多任务进行数据融合&#xff0c;实现准确高效的3D目标检测。简而言之&#xff0c;自动驾驶领域…

压力传感器

压力传感器 压力传感器是最常用的一种传感器&#xff0c;其应用范围有各种工业互通环境&#xff0c;涉及航空&#xff0c;航天&#xff0c;军工&#xff0c;石化&#xff0c;电力等。按照不同的测试&#xff0c;压力类型可分表压传感器&#xff0c;差压传感器&#xff0c;绝压…

多传感器融合定位(一)——3D激光里程计

目录 一、点云地图整体流程 二、激光里程计方案 2.1 ICP点到点 2.1.1 ICP推导 2.1.2 ICP改进 2.2 NDT 2.2.1 NDT推导 2.2.2 NDT改进 2.3 LOAM系 2.3.1 LOAM 2.3.2 A-LOAM 2.3.3 LEGO-LOAM 2.4 数据集及评价指标 2.4.1 KITTI简介 2.4.2 指标 一、点云地图整体流程…

MMDetection3D 1.1:统一易用的 3D 感知平台

自从两年前 MMDetection3D 发布以来&#xff0c;我们收到了很多用户的反馈&#xff0c;其中有不少有价值的建议&#xff0c;同时也有很多吐槽&#xff08;当然我们非常欢迎大家来吐槽&#xff09;&#xff0c;也有很多社区用户参与到我们代码库的完善中&#xff0c;我们也非常高…

关于传感器

人的眼睛就是传感器。人对光的感应靠眼睛&#xff0c;在光亮条件下&#xff0c;人眼能分辨各种颜色。首先从人眼构造开始讲起。眼睛最里面的膜是视网膜&#xff0c;它布满了整个眼睛后部的内壁。当眼球适当地聚焦时&#xff0c;来自眼睛外部的光在视网膜上成像。在视网膜表面分…

ToF 3D视觉传感技术详解、应用场景和市场前景

‍转载自&#xff1a;3d tof 现行的深度传感镜头作为智能手机的一大创新&#xff0c;已在目前主流智能手机上广泛应用。现因苹果在最新版iPad Pro上搭载了D-ToF&#xff08;直接飞行时间法&#xff09;深度传感镜头引起了极大的关注&#xff0c;推动了3D视觉在消费场景的新应用…

奥比中光Orbbec Astra Pro RGBD 3D视觉传感器在ROS(indigo和kinetic)使用说明

作者&#xff1a;童虎 编辑&#xff1a;3D视觉开发者社区 Orbbec Astra Pro传感器在ROS&#xff08;indigo和kinetic&#xff09;使用说明 这款摄像头使用uvc输入彩色信息&#xff0c;需要libuvc和libuvc_ros这样才能在ROS正常使用彩色功能。 请在下面网址&#xff0c;分别下载…

3D传感相关

这里涉及了各种3D传感相关的工作&#xff0c;包含单目、双目、ToF等传感器&#xff0c;涉及了计算摄影、ToF深度测量、双目深度估计、多视角深度估计、相机离线标定、相机在线标定、NeRF等技术&#xff0c;可谓3D视觉集大成者。 这里简单介绍下本文将会提到的两种3D成像技术&a…

3D激光雷达SLAM算法学习02——3D激光雷达传感器

1.本篇思维导图 2. 3D激光雷达传感器分类 3. 机械激光雷达 直观视频感受&#xff1a;Velodyne 优点&#xff1a;360视野&#xff0c;精度高&#xff0c;工作稳定&#xff0c;成像快 缺点&#xff1a;成本较高&#xff0c;不符合自动驾驶车规&#xff0c;生命周期短&#xff0c…

Lidar 3D传感器点云数据与2D图像数据的融合标注

2D&3D融合 以自动驾驶场景为例&#xff0c;自动驾驶汽车需要使用传感器来识别车辆周围的物理环境&#xff0c;用来捕获2D视觉数据&#xff0c;同时在车辆顶部安装雷达,用以捕捉精确目标定位的3D位置数据。 激光雷达生成的点云数据可用于测量物体的形状和轮廓&#xff0c;估…

3D视觉传感器产业现状-2018年

总结一下&#xff0c;主要参考于MEMS市场调研 MEMS.ME&#xff0c; 必须找专业的分析和咨询公司才行&#xff0c;或者活跃在前沿的资深行业专家。市场分析只能给出大致的销售状况&#xff0c;还不能给出详细的技术数据对比。 从三维重建的算法、技术原理和效果参数上分析&#…

三种常见的3D传感器比较

作者 | dianyunPCL 编辑 | 点云PCL 本文只做学术分享&#xff0c;如有侵权&#xff0c;联系删文 点击下方卡片&#xff0c;关注“自动驾驶之心”公众号 ADAS巨卷干货&#xff0c;即可获取 点击进入→自动驾驶之心【硬件交流】技术交流群 摘要 在过去的十年里&#xff0c;3D传感…

3D视觉|了解下工业上常见的3D相机

说起相机&#xff0c;大家估计都很熟悉了。那么相对于平常使用的2D相机&#xff0c;3D相机又有哪些区别呢&#xff0c;顾名思义&#xff0c;3D相机可以让我们获取我们物理世界的空间信息&#xff0c;即立体三维的物理信息。多了一个维度的信息&#xff0c;似乎打开了一扇大门&a…

基于多传感器的3D多目标跟踪算法汇总

1. IROS 2020-AB3DMOT&#xff1a;A Baseline for 3D Multi-Object Tracking and New Evaluation Metrics 代码链接&#xff1a;https://github.com/xinshuoweng/AB3DMOT 文章链接&#xff1a;http://www.xinshuoweng.com/papers/AB3DMOT_eccvw/camera_ready.pdf 出发点&#x…

3D相机技术 | 立体视觉传感器+TOF相机

转自 | 睿慕课 文章结构 前言立体视觉传感器原理简介工业领域应用主流立体视觉的产品TOF相机工作原理TOF工业领域应用一些TOF研究机构 1.前言 在机器视觉应用中&#xff0c;物体三维形状的获取变得越来越重要。在这个系列里&#xff0c;我们将讨论目前在机器视觉行业中可用的3…