代码地址如下:
http://www.demodashi.com/demo/13577.html

一款基于Netty开发的WebSocket服务器

这是一款基于Netty框架开发的服务端,通信协议为WebSocket。主要用于Java后台服务器向浏览器进行消息推送。

需求

对于一个Web项目而言,客户端一般均为各种各样的浏览器,如何从后端服务器向浏览器客户端进行消息推送,便成了一个棘手的问题,好在在HTTP1.1之后,HTTP可以支持长连接,由此,我在Netty框架的基础上开发了这个WebSocket服务端。

当然,你依旧可以下载源码进行测试,集成,二次开发等等。

环境

  • Intellij IDEA2018
  • JDK 1.8
  • 插件:Simple WebSocket Client 0.1.3
    • FireFox Quantum 60.0.1 (64 位)
    • Google Chrome 67.0.3396.99(正式版本)(64 位)

运行结果

请看下图:

实现步骤及源码

WebSocket

WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。 WebSocket通信协议于2011年被IETF定为标准RFC 6455,WebSocketAPI被W3C定为标准。 在WebSocket API中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

目录结构

核心类讲解

  • WebSocketChildHandler
  • WebSocketServerHandler

WebSocketChildHandler

这个类的主要作用就是为Netty的通道注册事件。其核心代码见下,其中webSocketUrl就是客户端与服务端进行连接的请求路径,我将其写入了配置文件,交由Spring管理,以注入的方式传递到WebSocketServerHandler中。

ChannelPipeline pipeline = socketChannel.pipeline();// 将请求与应答消息编码或者解码为HTTP消息pipeline.addLast("http-codec", new HttpServerCodec());// 将http消息的多个部分组合成一条完整的HTTP消息pipeline.addLast("aggregator", new HttpObjectAggregator(HttpObjectConstant.MAX_CONTENT_LENGTH));// 向客户端发送HTML5文件。主要用于支持浏览器和服务端进行WebSocket通信pipeline.addLast("http-chunked", new ChunkedWriteHandler());// 服务端Handlerpipeline.addLast("handler", new WebSocketServerHandler(webSocketUrl));

WebSocketServerHandler

这个类是真正的核心类,这个类的主要功能为:

  • 进行第一次握手
  • 对消息进行处理
    • 可以实现点对点通信
    • 可以实现广播功能
    • 可以实现点对端通信
/*** 接收客户端发送的消息** @param channelHandlerContext ChannelHandlerContext* @param receiveMessage        消息*/@Overrideprotected void messageReceived(ChannelHandlerContext channelHandlerContext, Object receiveMessage) throws Exception {// 传统http接入 第一次需要使用http建立握手if (receiveMessage instanceof FullHttpRequest) {FullHttpRequest fullHttpRequest = (FullHttpRequest) receiveMessage;LOGGER.info("├ [握手]: {}", fullHttpRequest.uri());// 握手handlerHttpRequest(channelHandlerContext, fullHttpRequest);// 发送连接成功给客户端channelHandlerContext.channel().write(new TextWebSocketFrame("连接成功"));}// WebSocket接入else if (receiveMessage instanceof WebSocketFrame) {WebSocketFrame webSocketFrame = (WebSocketFrame) receiveMessage;handlerWebSocketFrame(channelHandlerContext, webSocketFrame);}}/*** 第一次握手** @param channelHandlerContext channelHandlerContext* @param req                   请求*/private void handlerHttpRequest(ChannelHandlerContext channelHandlerContext, FullHttpRequest req) {// 构造握手响应返回,本机测试WebSocketServerHandshakerFactory wsFactory= new WebSocketServerHandshakerFactory(webSocketUrl, Constant.NULL, Constant.FALSE);// region 从连接路径中截取连接用户名String uri = req.uri();int i = uri.lastIndexOf("/");String userName = uri.substring(i + 1, uri.length());// endregionChannel connectChannel = channelHandlerContext.channel();// 加入在线用户WebSocketUsers.put(userName, connectChannel);socketServerHandShaker = wsFactory.newHandshaker(req);if (socketServerHandShaker == null) {// 发送版本错误WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(connectChannel);} else {// 握手响应socketServerHandShaker.handshake(connectChannel, req);}}/*** webSocket处理逻辑** @param channelHandlerContext channelHandlerContext* @param frame                 webSocketFrame*/private void handlerWebSocketFrame(ChannelHandlerContext channelHandlerContext, WebSocketFrame frame) throws IOException {Channel channel = channelHandlerContext.channel();// region 判断是否是关闭链路的指令if (frame instanceof CloseWebSocketFrame) {LOGGER.info("├ 关闭与客户端[{}]链接", channel.remoteAddress());socketServerHandShaker.close(channel, (CloseWebSocketFrame) frame.retain());return;}// endregion// region 判断是否是ping消息if (frame instanceof PingWebSocketFrame) {LOGGER.info("├ [Ping消息]");channel.write(new PongWebSocketFrame(frame.content().retain()));return;}// endregion// region 纯文本消息if (frame instanceof TextWebSocketFrame) {String text = ((TextWebSocketFrame) frame).text();LOGGER.info("├ [{} 接收到客户端的消息]: {}", new Date(), text);channel.write(new TextWebSocketFrame(new Date() + " 服务器将你发的消息原样返回:" + text));}// endregion// region 二进制消息 此处使用了MessagePack编解码方式if (frame instanceof BinaryWebSocketFrame) {BinaryWebSocketFrame binaryWebSocketFrame = (BinaryWebSocketFrame) frame;ByteBuf content = binaryWebSocketFrame.content();LOGGER.info("├ [二进制数据]:{}", content);final int length = content.readableBytes();final byte[] array = new byte[length];content.getBytes(content.readerIndex(), array, 0, length);MessagePack messagePack = new MessagePack();WebSocketMessageEntity webSocketMessageEntity = messagePack.read(array, WebSocketMessageEntity.class);LOGGER.info("├ [解码数据]: {}", webSocketMessageEntity);WebSocketUsers.sendMessageToUser(webSocketMessageEntity.getAcceptName(), webSocketMessageEntity.getContent());}// endregion}

至此,服务端算是开发完成。但可以看出,服务端中仍有很大的发展空间,细心的同学可以发现我在第一次握手时,将Channel存储了起来,对于上述的三种情况也有简易的实现方案。

如果有必要,我也会将非浏览器客户端代码(非Js客户端)写成例子,共享出来。

一款基于Netty开发的WebSocket服务器

代码地址如下:
http://www.demodashi.com/demo/13577.html

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

一款基于Netty开发的WebSocket服务器相关推荐

  1. 基于Netty开发水利通信软件

    水利行业中遥测站点的分布非常广,担负着与这些遥测站点通信的软件就是水利遥测通信软件.早期遥测站点的通信主要采用短波电台,卫星通讯,GPRS等的通信方式,通信协议随着站点RTU生产厂家的不同而不一样,因 ...

  2. 微信小程序基于node.js的websocket服务器搭建和SSL证书申请、配置全家桶

    〇.前言 最近在研究微信小程序的开发,中间遇到了不少问题,趟了不少坑,这里和大家分享一下我的一些经验,希望能给大家提供一些帮助. 一.微信小程序的websocket服务器搭建 微信小程序的网络通信使用 ...

  3. 又一款基于BCH开发出来的社交软件BlockPress

    随着币价的回暖,比特币现金的相关应用在最近出的也很勤,甚至可以说每天都会有新的东西被BCH社区人士开发出来.对此,r/btc上的小伙伴发出了这样的感慨:比特币现金不仅取消了交易上限,而且还取消了开发上 ...

  4. Leo-IM,开源好用的IM(基于Netty开发)

    Leo-IM,开源好用的IM. Leo-IM是基于Java语言.Netty框架.Vue+Element-UI开发的轻量级IM,服务端可独立运行(无需部署到web容器),HTTP服务和Socket服务可 ...

  5. 一款基于Uniapp开发的开源低代码平台

    rtvue-lowcode 简介 rtvue-lowcode是一款基于uni-app框架和uview组件库开发的app可视化拖拽项目,适用于企业.个人等基于uni-app技术栈开发的项目.适合各种小程 ...

  6. 一款基于springboot开发的经典后台管理系统

    项目介绍 一款 Java 语言基于 SpringBoot2.x.Layui.Thymeleaf.MybatisPlus.Shiro.MySQL等框架精心打造的一款模块化.插件化.高性能的前后端分离架构 ...

  7. 安卓sip话机/一款基于linphone开发的,安卓sip话机客户端

    基于linphone sdk,简化登录登录及操作流程,汉化的中文sip客户端. Android和ios,都进行过二次开发.因为ios需要证书和签名的原因,暂时没有发布. 当然,需要源码的可以联系. 默 ...

  8. 一款基于 SpringBoot 开发 OA 系统 !

    嗨喽!Java后端编程的各位小伙伴们,由于公众号做了乱序推送改版,为了保证公众号的推文能够第一时间及时送达到大家手上,大家记得将公众号 加星标置顶 ,公众号每天会送上Java技术干货推文 ! 上篇推文 ...

  9. vue 音乐盒app_VBox 一款基于vue开发的音乐盒 序章

    自己基于vue写了一个 Mplayer, 只有简单的搜索播放随心听功能,样式适配上也很差, 路由就两个,数据都走vuex,数据转发是用nodejs自己转发,而且只是PC能比较好的展现,之后不了了之,偶 ...

最新文章

  1. beats 耳机 android,Beats耳机app
  2. JZOJ 5625. 【NOI2018模拟4.3】Max
  3. 括号配对问题_栈stack
  4. AT2371-[AGC013E]Placing Squares【矩阵乘法】
  5. Oracle Database Appliance
  6. OpenCL用于计算机领域的13个经典案例
  7. 【CodeVS】1023 GPA计算
  8. linux wine 性能,Wine 1.9.16 发布,改善 GDI 性能
  9. Linux-yum在线安装svn步骤
  10. UI设计实用素材|闪屏模板
  11. 开源界也要注意,Apache 基金会与 GitHub 都受美国法律约束
  12. SPOJ Problem 22:Triangle From Centroid
  13. 实现弹出窗口并转到另一个页面
  14. Bailian2973 Skew数【进制】
  15. [AlwaysOn Availability Groups]排查:AG配置
  16. day5 字典 dict
  17. 真实评测 i51155g7和锐龙r75700u选哪个好
  18. python中result函数用法_python中函数的参数和返回值
  19. 【Android笔记 七】Android Sensor感应器介绍(三)获取用户移动方向,指南针原理
  20. 面向对象:赖床运动员,吉尼斯吃不饱记录保持者

热门文章

  1. 秦九韶算法递推公式_如何教会女友递归算法?
  2. 高性能MySQL(第二版)第三章 架构优化和索引(上)——读书笔记
  3. Netfilter框架
  4. java iso-8859-1_如何在Java中的ISO-8859-1和UTF-8之间转换?
  5. 华南理工计算机研究生专业课,华南理工大学(专业学位)计算机技术研究生考试科目和考研参考书目...
  6. 百度android定位 602 key mcode不匹配,我的Android进阶之旅------百度地图学习:BDLocation.getLocType ( )值分析...
  7. php产生订单号不重复,php如何生成不重复订单号
  8. python控制树莓派相机_玩转树莓派-Raspberry,控制单反相机进行可编程摄影
  9. 【LeetCode】【HOT】206. 反转链表(迭代/递归)
  10. 《Reids 设计与实现》第八章 AOF持久化