websocket之旅

Netty框架介绍并编写WebSocket服务端与客户端 阅读详情

 一次偶然的机会在群里有人提问到这样的问题,一台socket通信服务器,用其他客户端联接正常,用websocket就不行。

于是自己写了个程序验证一下,也就开始了websocket 的hello word之旅。

先了解下websocket的通信原理。

 

这里简单说明一下WebSocket握手的过程。

当Web应用程序调用new WebSocket(url)接口时,Browser就开始了与地址为url的WebServer建立握手连接的过程。

1.   TCP握手阶段, Browser与WebSocket服务器通过TCP三次握手建立连接,如果这个建立连接失败,那么后面的过程就不会执行,Web应用程序将收到错误消息通知。

2.   websocket 握手阶段,  在TCP建立连接成功后,Browser/UA通过http协议传送WebSocket支持的版本号,协议的字版本号,原始地址,主机地址等等一些列字段给服务器端。

例如:

GET /chat HTTP/1.1

Host: server.example.com

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==

Origin: http://example.com

Sec-WebSocket-Protocol: chat,superchat

Sec-WebSocket-Version: 13

3.     WebSocket服务器收到Browser/UA发送来的握手请求后,如果数据包数据和格式正确,客户端和服务器端的协议版本号匹配等等,就接受本次握手连接,并给出相应的数据回复,同样回复的数据包也是采用http协议传输。

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Protocol: chat

4.     Browser收到服务器回复的数据包后,如果数据包内容、格式都没有问题的话,就表示本次连接成功,触发onopen消息,此时Web开发者就可以在此时通过send接口想服务器发送数据。否则,握手连接失败,Web应用程序会收到 onerror消息,并且能知道连接失败的原因。

 

第一步是走TCP底层三次握手,第二步和第三步是http协议。

回到之前的问题:一台socket通信服务器,用其他客户端联接正常,用websocket就不行。

是因为其他客户端没有第二步和第三步的websocket握手,直接进入传输业务数据,用websocket传输需要websocket握手,socket服务端把握手的报文当做业务数据格式处理,服务端报错了,服务端没有响应websocket握手包给websocket客户端,websocket客户端当做连接失败处理。

 

要让socket服务端支持websocket的通讯,必须先支持第二步和第三步的websocket握手,接下来看netty是怎么支持的。

以netty 5.0版本为例

   privateclassChildChannelHandler extends ChannelInitializer<SocketChannel> {

 

        @Override

        protected void initChannel(SocketChannel ch) throws Exception {

            ch.pipeline().addLast("http-codec",newHttpServerCodec());

            ch.pipeline().addLast("aggregator",newHttpObjectAggregator(65536)) ;

        ch.pipeline().addLast("http-chunked",newChunkedWriteHandler());

        ch.pipeline().addLast("handler",newWebSocketServerHandler());         

        }

 

   }

Websocket握手是基于http协议,先添加一些http编解码器。下面是WebSocketServerHandler的实现

 

public classWebSocketServerHandler extends SimpleChannelInboundHandler<Object>{

 

   /**

     * 日志

     */

   privatestaticfinalLogger logger=

           Logger.getLogger(WebSocketServerHandler.class.getName());

   /**

     * 全局websocket

     */

   privateWebSocketServerHandshaker handshaker;

   

   @Override

   protectedvoidmessageReceived(ChannelHandlerContext ctx, Object msg)

            throws Exception {

        //普通HTTP接入

        if(msg instanceof FullHttpRequest){

            handleHttpRequest(ctx,(FullHttpRequest) msg);

        }else if(msg instanceofWebSocketFrame){ //websocket帧类型已连接

            handleWebSocketFrame(ctx,(WebSocketFrame) msg);

        }

   }

   

   @Override

   publicvoidchannelReadComplete(ChannelHandlerContext ctx) throws Exception {

        ctx.flush();

   }

   

   privatevoidhandleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request){

        //如果http解码失败则返回http异常并且判断消息头有没有包含Upgrade字段(协议升级)

        if(!request.decoderResult().isSuccess()

                || (!"websocket".equals(request.headers().get("Upgrade")))    ){

            sendHttpResponse(ctx,request, newDefaultFullHttpResponse(

                    HttpVersion.HTTP_1_1,HttpResponseStatus.BAD_REQUEST));

            return ;

        }

        //构造握手响应返回

        WebSocketServerHandshakerFactory ws = newWebSocketServerHandshakerFactory("", null,false);

        handshaker = ws.newHandshaker(request);

        if(handshaker == null){

            //版本不支持

            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());

        }else{

            handshaker.handshake(ctx.channel(), request);

        }

   }

   /**

     * websocket帧

     * @param ctx

     * @param frame

     */

   privatevoidhandleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){

        //判断是否关闭链路指令

        if(frame instanceof CloseWebSocketFrame){

            handshaker.close(ctx.channel(),(CloseWebSocketFrame) frame.retain());

            return ;

        }

        //判断是否Ping消息 -- ping/pong心跳包

        if(frame instanceof PingWebSocketFrame){

            ctx.channel().write(newPongWebSocketFrame(frame.content().retain()));

            return ;

        }

        //本程序仅支持文本消息,不支持二进制消息

        if(!(frame instanceof TextWebSocketFrame)){

            throw new UnsupportedOperationException(

                   String.format("%s frame types not supported", frame.getClass().getName()));

        }

       

        //返回应答消息 text文本帧

        String request = ((TextWebSocketFrame)frame).text();

        //打印日志

        if(logger.isLoggable(Level.FINE)){

            logger.fine(String.format("%s received %s",ctx.channel(), request));

        }

        //发送到客户端websocket

        ctx.channel().write(newTextWebSocketFrame(request

                + ", 欢迎使用Netty WebSocket服务,现在时刻:"

                + new java.util.Date().toString()));

   }

   

   /**

     * response

     * @param ctx

     * @param request

     * @param response

     */

   privatestaticvoidsendHttpResponse(ChannelHandlerContext ctx,

            FullHttpRequest request,FullHttpResponse response){

        //返回给客户端

   

        if(response.status().code() !=HttpResponseStatus.OK.code()){

            ByteBuf buf = Unpooled.copiedBuffer(response.status().toString(),CharsetUtil.UTF_8);

           response.content().writeBytes(buf);

            buf.release();

            HttpHeaderUtil.setContentLength(response,response.content().readableBytes());

        }

        //如果不是keepalive那么就关闭连接

        ChannelFuture f =ctx.channel().writeAndFlush(response);

        if(!HttpHeaderUtil.isKeepAlive(response)

                || response.status().code() !=HttpResponseStatus.OK.code()){

           f.addListener(ChannelFutureListener.CLOSE);

        }

      

   }

   

   /**

     * 异常出错

     */

   @Override

   publicvoidexceptionCaught(ChannelHandlerContext ctx, Throwable cause)

            throws Exception {

        cause.printStackTrace();

        ctx.close();

   }

}

 

重点讲述下messageReceived的实现

   protectedvoidmessageReceived(ChannelHandlerContext ctx, Object msg)

            throws Exception {

        //普通HTTP接入,websocket握手协议是http请求,返回websocket握手包

        if(msg instanceof FullHttpRequest){

            handleHttpRequest(ctx,(FullHttpRequest) msg);

        }else if(msg instanceofWebSocketFrame){ //websocket连接已建立,websocket帧类型编解码

            handleWebSocketFrame(ctx,(WebSocketFrame) msg);

        }

   }

   

 

服务端给客户端推送消息用Netty+WS实现 # 前言 曾几何时,不知道大家有没有在项目里遇到过需要服务端给客户端推送消息的需求,是否曾经苦恼过、纠结过,我们知道要想实现这样的需求肯定离不开websocket长连接方式,那么到底是该选原生的websocket还是更加高级的netty框架呢?在此我极力推荐netty,因为一款好的框架一般都是在原生的基础上进行包装成更好、更方便、更实用的东西,很多我们需要自己考虑的问题都基本可以不用去考虑... 阅读详情

相关推荐

spring boot websocket 的使用

/如果spingboot配置文件中中配置了server.servlet.context-path,则格式为ws//ip接口启动的端口/server.servlet.context-path的名称/webSocketDemo。//连接到WebSocket的url地址。格式为ws//ip接口启动的端口/webSocketDemo。//连接发生错误的回调方法。//连接成功建立的回调方法。//ws连接断开的回调方法。//接收到消息的回调方法。//将消息显示在网页上。...

张小三的博客 3070

吃透Netty源码系列四十七之WebSocketServerProtocolHandler详解

吃透Netty源码系列四十七之WebSocketServerProtocolHandler详解handlerAdded处理器添加事件WebSocketServerProtocolHandshakeHandler的channelReadisNotWebSocketPath验证URLsendHttpResponse发送消息WebSocketServerHandshakerFactory的newHand...

王伟王胖胖的博客 1万+

WebSocket奇妙之旅

WebSocket奇妙之旅:双向通信的魔法隧道

m0_72030584的博客 750

9.基于netty实现WebSocket服务器

1.本文总结自B站《netty-尚硅谷》,很不错;2.本文示例代码基于netty实现 WebSocket服务器功能;

PacosonSWJTU的博客 4552

WebSocket的奇妙之旅:在JavaScript中实现实时通信

WebSocket是HTML5引入的一种网络通信协议,它使得客户端和服务器之间的数据交换变得更加简单和高效。与传统的HTTP请求相比,WebSocket可以减少不必要的带宽消耗,提高通信的实时性。

2401_85842555的博客 1041

基于Sentinel-2(哨兵2)遥感卫星的植被覆盖度提取

基于Sentinel-2(哨兵2)遥感卫星的植被覆盖度提取 一、Sentinel-2简单介绍 哨兵-2系列卫星的主要载荷多光谱成像仪拥有13个谱段,从可见光到近红外再到短波红外,空间分辨率从10m到60m,能实现全所未有的陆地海洋监测水平。其幅宽高达290KM,且A、B双星组合,覆盖能力比美国Landsat8卫星强很多。目前哨兵-2A和哨兵-2B已经实现了5天的重访时间,即使在之前仅有单颗卫星时,...

weixin_44143671的博客 2万+

WebSocket之旅

很好的一篇WebSocket教程 websocket原理

xiaolizh的博客 211

Ubuntu系统下搭建QtCreator开发环境详细过程(Qt简介;Linux下安装QtCreator;Ubuntu安装后闪退蓝屏的解决方法)

Qt 是一个跨平台的 C++开发库。主要用来开发图形用户界面 (Graphical User Interface,简称 GUI) 程序。Qt 支持的操作系统有很多,例如通用操作系统 Windows、Linux、Unix、智能手机系统Android、ios、WinPhone, 嵌入式系统 QNX、VxWorks 等。

分享学习成长历程,Winter is coming! 8585

WebSocket和Netty的Protobuf之旅

WebSocket是一种在单个TCP连接上进行全双工通讯的协议。它使得客户端和服务器之间能够进行低延迟的消息传递,是实时应用(如聊天应用、在线游戏等)的理想选择。Netty是一个基于Java的异步事件驱动网络应用框架,用于快速开发可维护的高性能协议服务器和客户端。它极大地简化了网络编程的复杂性。Protocol Buffers(Protobuf)是Google开发的一种高效的序列化结构数据的方法。与JSON或XML相比,Protobuf更紧凑,解析速度更快,非常适合在高性能需求的场景下使用。

全栈工程师,热爱编程,喜欢探索各种技术栈。分享前端、后端、数据库等技术学习心得,以及在项目开发中的实践经验。 880

测绘无人船避坑指南:云卓H12Pro遥控器接海康摄像头,从网络设置到RTSP流延迟优化全流程

本文详细解析了测绘无人船视频子系统的优化方案,重点介绍海康威视摄像头与云卓H12Pro遥控器的深度适配流程。从网络设置到RTSP流延迟优化,提供了一套经过实测的低延迟(<200ms)解决方案,适用于复杂水域环境下的测绘任务。

weixin_30415113的博客 627

特征图与token的区别以及两者之间的转换

特征图和token之间的联系以及两者之间的转换

mariodf的博客 1013

一文搞懂!C# 实现 WebSocket 的奇妙之旅

通过本文的深入探索,我们详细了解了 C# 实现 WebSocket 的全过程,从基础概念的剖析、环境搭建的准备,到服务端与客户端的精细构建,再到握手与数据传输的深度揭秘,以及实战案例的精彩展示与常见问题的巧妙化解。若是 WebSocket 请求,立即执行握手流程,这一过程涉及复杂的协议交互,双方如同交换 “信物”,确认彼此身份与通信规则,成功后建立稳定的 WebSocket 连接,开启数据传输通道,之后便持续监听该连接上的数据收发,确保信息流畅无阻,直至连接关闭。配置文件的设置同样不可小觑。

qq_22232065的博客 3860

华为OD机试 - 猴子吃桃 - 二分查找(Java 新系统 100分)

每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天优快云在线答疑。

学Java,找哪吒 3851

【WebSocket✨】入门之旅(一):初识 WebSocket

摘要: 本文介绍了WebSocket的核心概念及其优势。相比传统HTTP协议,WebSocket通过持久化全双工连接实现低延迟双向通信,适用于实时聊天、股票推送、在线游戏等场景。文章对比了WebSocket与HTTP的区别,并通过代码示例演示了其基本用法,包括建立连接、收发消息及事件监听。WebSocket解决了HTTP的高延迟、频繁请求等问题,成为实时应用开发的理想选择。后续将深入探讨WebSocket的握手与消息传输机制。

2301_77798916的博客 888

9 硬件工程师笔面试高频知识考点真题解析——运算放大器

运算放大器(运放)摘要 运放是一种高增益、差分输入的模拟集成电路,具有虚短(线性区输入电压相等)和虚断(输入电流为零)特性,支持负反馈(线性放大)和开环/正反馈(饱和区比较)两种工作模式。关键特性包括高输入阻抗、低输出阻抗,理想运放参数(如无限增益)与实际参数(如有限带宽)的差异。 选型要点: 信号特性:直流/低频信号关注失调电压(Vos)、温漂;高频信号侧重带宽(GBW)和压摆率(SR)。 电源条件:单/双电源供电、电压范围及功耗需求(如电池设备需低静态电流)。 精度与噪声:微弱信号需低噪声运放,高精度场

XU157303764的博客 1677

2026年江苏省职业院校技能大赛高职组“软件测试”赛项智能体辅助测试参考答案

2026年江苏省职业院校技能大赛高职组“软件测试”赛项智能体辅助测试参考答案

我是网络安全兼技能大赛工程师,专注网络安全技术学习与技能大赛实战!持续分享最新的技术文章,帮你少走弯路,一起在技术赛道上进步~ 1354

【WebSocket✨】入门之旅(五):WebSocket 的安全性

WebSocket 是一种高效的实时通信协议,但由于其持久连接的特性,WebSocket 在安全方面面临一些挑战。中间人攻击(MITM)跨站脚本攻击(XSS)跨站请求伪造(CSRF)数据篡改为了确保 WebSocket 连接的安全,我们必须采取相应的措施来预防这些安全问题。

2301_77798916的博客 1282

【2026年阿里巴巴集团暑期实习- 4月25日-算法岗-第二题- 矩阵计数】(题目+思路+Java&C++&Python解析+在线测试)

摘要: 给定两个非负整数序列a和b,构造n×m矩阵C,其中C[i][j]=a[i]×b[j]。统计矩阵中元素≥k的数量。解法是先对数组b排序,然后对于每个a[i],若k=0则直接累加m;若a[i]=0且k>0则跳过;否则计算需要的最小b[j]值,在排序后的b中使用二分查找确定满足条件的元素数量。时间复杂度为O((n+m)log m),空间复杂度O(1)。代码实现了排序和二分查找的高效组合。

m0_73659489的博客 65

【WebSocket✨】入门之旅(三):WebSocket 的实战应用

本文通过构建实时聊天应用,演示了WebSocket技术的实战应用。首先使用Node.js和ws库搭建WebSocket服务器(8080端口),实现消息广播功能;然后创建基于原生JavaScript的WebSocket客户端,建立双向通信。文章包含完整代码示例,并针对常见连接问题提供解决方案。这一案例展示了WebSocket在实时通信中的关键优势:低延迟、双向性和高效性,适用于聊天、游戏等实时场景。最后预告了后续将探讨WebSocket性能优化内容。

2301_77798916的博客 880

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

【WebSocket✨】入门之旅(四):WebSocket 的性能优化

本文介绍了优化WebSocket性能的多种方法,主要包括:1)使用连接池管理和复用WebSocket连接,配合负载均衡提升可扩展性;2)采用Gzip/Brotli压缩消息减少带宽消耗,并限制消息大小避免性能瓶颈;3)通过心跳机制保持连接活跃,设置超时处理清理闲置连接;4)服务器端优化包括非阻塞I/O和分布式架构,客户端优化如指数退避重连策略。这些技巧能有效提升WebSocket在高并发场景下的连接稳定性、降低延迟并提高吞吐量,适用于大规模实时应用。

2301_77798916的博客 1189

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【WebSocket✨】入门之旅(七):WebSocket 的未来发展趋势

摘要: WebSocket协议作为实时通信的核心技术,未来将围绕多路复用、拥塞控制等方向优化性能,并与HTTP/3(QUIC)深度融合以降低延迟。结合5G、AI等新兴技术,WebSocket将拓展至AR/VR、自动驾驶、物联网等新兴领域,提升实时交互能力。尽管面临连接稳定性、带宽消耗等挑战,其在高并发、低延迟场景中的潜力仍不可忽视,将持续推动实时通信技术的革新。(149字)

2301_77798916的博客 1210

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

.Net WebSocket学习之旅(一)

原生Websocket在.Net环境的实现 我使用原生的websocket做了个简单的demo,适合初学的知道怎么个实现。 我参考的是网上的,部分雷同,见谅 (聊天室功能可以在此基础上加工,我后面会在SignalR框架中实现) 下面是大致的代码框架,实现是加上自己的业务的,我会在后面提供我的源代码,丰富了框架,一个简单的demo 一、前端Html中的Js

俞祥胜的.Net进阶之旅 1408

实现网页流畅直播:从RTSP到WebSocket的神奇之旅

实现网页流畅直播:从RTSP到WebSocket的神奇之旅 【下载地址】RTSP地址转WebSocket实现网页显示 RTSP地址转WebSocket实现网页显示本仓库提供了一个资源文件,用于将RTSP地址转换为WebSocket流并在网页上进行显示 ...

gitblog_09788的博客 1111

【网络编程学习之旅】Netty之WebSocket编程实战

Netty之WebSocket编程实战 一、Netty初介绍 1.1 什么是Netty? 高性能 事件驱动、异步非阻塞; 基于NIO的客户端、服务端编程框架; 稳定性和 伸缩性; 1.2 Netty使用场景 高性能领域; 多线程并发领域; 异步通信领域; 1.3 不选择Java原生NIO编程的原因 NIO的类库和API繁杂,使用麻烦,你需要熟练掌握Selector、ServerSocketChannel、SocketChannel、ByteBuffer等 需要具备其它的额外技能做铺垫,例如熟悉Ja

Mind_programmonkey的博客 1178

【WebSocket✨】入门之旅(二):WebSocket 的工作原理

本文详细解析WebSocket的实时双向通信机制:首先通过HTTP协议升级握手建立持久连接,利用消息帧结构传输文本/二进制数据;通过心跳机制维护长连接稳定性;并针对常见问题提供排查方法。WebSocket相比传统HTTP轮询具有单连接多次通信、资源节省等优势,适用于聊天、游戏等实时应用场景。

2301_77798916的博客 522

开源精粹:探索Spring Boot下的WebSocket实战之旅

开源精粹:探索Spring Boot下的WebSocket实战之旅 去发现同类优质开源项目:https://gitcode.com/ 在追求实时交互的现代应用开发中,WebSocket已成为不可或缺的技术之一。今天,我们带您深入挖掘一个以Spring Boot为核心驱动的WebSocket实战项目——这不仅是一次技术的探索,更是一扇通往高效实时通讯应用的大门。 项目概览 在这个精心设计的小型示例中...

gitblog_09809的博客 771
上一篇: 故障定位及性能调优
下一篇: 基于springside4 的app token登录鉴权
ChainCode
ChainCode 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄11年 115粉丝 51原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值