原文:https://huan1993.iteye.com/blog/2433552

最近在学习netty相关的知识,看到netty可以实现 websoket,因此记录一下在netty中实现websocket的步骤,主要实现传递文本消息传递二进制消息,传递二进制消息由于需要传递额外信息,因此使用自定义消息协议。

需求:

1、使用 netty 实现 websocket 服务器

    2、实现 文本信息 的传递

    3、实现 二进制 信息的传递,如果是图片则传递到后台后在前台直接显示,非图片提示。(此处的图片和非图片是前端传递到后台的二进制数据然后后端在原封不动的直接返回到前台)

    4、只需要考虑 websocket 协议,不用处理http请求

实现细节:

1、netty中对websocket增强的处理器

WebSocketServerProtocolHandler 

>> 此处理器可以处理了 webSocket 协议的握手请求处理,以及 ClosePingPong控制帧的处理。对于文本和二进制的数据帧需要我们自己处理

>> 如果我们需要拦截 webSocket 协议握手完成后的处理,可以实现ChannelInboundHandler#userEventTriggered方法,并判断是否是 HandshakeComplete 事件。

>> 参数:websocketPath 表示 webSocket 的路径

>> 参数:maxFrameSize 表示最大的帧,如果上传大文件时需要将此值调大

2、文本消息的处理

客户端: 直接发送一个字符串即可

服务端: 服务端给客户端响应文本数据,需要返回  TextWebSocketFrame 对象,否则客户端接收不到。

3、二进制消息的处理

客户端:向后台传递一个 blob 对象即可,如果我们需要传递额外的信息,那么可以在 blob 对象中进行添加,此例中自定义前4个字节表示数据的类型。

服务端:处理 BinaryWebSocketFrame 帧,并获取前4个字节,判断是否是图片,然后返回 BinaryWebSocketFrame对象给前台。

4、针对二进制消息的自定义协议如下:(此处实现比较简单)

前四个字节表示文件类型,后面的字节表示具体的数据。

在java中一个int是4个字节,在js中使用Int32表示

此协议主要是判断前端是否传递的是 图片,如果是图片就直接传递到后台,然后后台在返回二进制数据到前台直接显示这个图片。非图片不用处理。

5、js中处理二进制数据

见 webSocket.html 文件中的处理。

实现步骤:

1、主要的依赖

  1. <dependency>
  2. <groupId>io.netty</groupId>
  3. <artifactId>netty-all</artifactId>
  4. <version>4.1.31.Final</version>
  5. </dependency>

2、webSocket服务端编写

  1. @Slf4j
  2. public class WebSocketServer {
  3. public static void main(String[] args) throws InterruptedException {
  4. EventLoopGroup bossGroup = new NioEventLoopGroup();
  5. EventLoopGroup workGroup = new NioEventLoopGroup();
  6. try {
  7. ServerBootstrap bootstrap = new ServerBootstrap();
  8. bootstrap.group(bossGroup, workGroup)
  9. .option(ChannelOption.SO_BACKLOG, 128)
  10. .childOption(ChannelOption.TCP_NODELAY, true)
  11. .childOption(ChannelOption.SO_KEEPALIVE, true)
  12. .handler(new LoggingHandler(LogLevel.TRACE))
  13. .channel(NioServerSocketChannel.class)
  14. .childHandler(new ChannelInitializer<SocketChannel>() {
  15. @Override
  16. protected void initChannel(SocketChannel ch) throws Exception {
  17. ch.pipeline()
  18. .addLast(new LoggingHandler(LogLevel.TRACE))
  19. // HttpRequestDecoder和HttpResponseEncoder的一个组合,针对http协议进行编解码
  20. .addLast(new HttpServerCodec())
  21. // 分块向客户端写数据,防止发送大文件时导致内存溢出, channel.write(new ChunkedFile(new File("bigFile.mkv")))
  22. .addLast(new ChunkedWriteHandler())
  23. // 将HttpMessage和HttpContents聚合到一个完成的 FullHttpRequest或FullHttpResponse中,具体是FullHttpRequest对象还是FullHttpResponse对象取决于是请求还是响应
  24. // 需要放到HttpServerCodec这个处理器后面
  25. .addLast(new HttpObjectAggregator(10240))
  26. // webSocket 数据压缩扩展,当添加这个的时候WebSocketServerProtocolHandler的第三个参数需要设置成true
  27. .addLast(new WebSocketServerCompressionHandler())
  28. // 服务器端向外暴露的 web socket 端点,当客户端传递比较大的对象时,maxFrameSize参数的值需要调大
  29. .addLast(new WebSocketServerProtocolHandler("/chat", null, true, 10485760))
  30. // 自定义处理器 - 处理 web socket 文本消息
  31. .addLast(new TextWebSocketHandler())
  32. // 自定义处理器 - 处理 web socket 二进制消息
  33. .addLast(new BinaryWebSocketFrameHandler());
  34. }
  35. });
  36. ChannelFuture channelFuture = bootstrap.bind(9898).sync();
  37. log.info("webSocket server listen on port : [{}]", 9898);
  38. channelFuture.channel().closeFuture().sync();
  39. } finally {
  40. bossGroup.shutdownGracefully();
  41. workGroup.shutdownGracefully();
  42. }
  43. }
  44. }

注意:

1、看一下上方依次引入了哪些处理器

2、对于 webSocket 的握手、Close、Ping、Pong等的处理,由 WebSocketServerProtocolHandler 已经处理了,我们自己只需要处理 Text和Binary等数据帧的处理。

3、对于传递比较大的文件,需要修改 maxFrameSize 参数。

3、自定义处理器握手后和文本消息

netty实现websocket发送文本和二进制数据的更多相关文章

  1. 【python】3.x,string与bytes的区别(文本,二进制数据)

    Python 3对文本和二进制数据作了更为清晰的区分.文本总是Unicode,由str类型表示, 二进制数据则由bytes类型表示. 不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也 ...

  2. 前端如何接收 websocket 发送过来的实时数据

    WebSocket protocol 是HTML5一种新的协议,它实现了浏览器与服务器全双工通信(full-duple).刚开始的握手需要借助HTTP请求完成,在 WebSocket API,浏览器和 ...

  3. 详细解读XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度

    本文主要参考:MDN 分析并操作 responseXML属性 如果你使用 XMLHttpRequest 来获得一个远程的 XML 文档的内容,responseXML 属性将会是一个由 XML 文档解析 ...

  4. IO流-文本IO\读写二进制数据

    文本IO 一.简述 OutputStreamWriter类使用选定的编码方式吧Unicode字符流转换为字节流,InputStreamReader类将包含字节的输入流转为可以产生Unicode字符的读 ...

  5. Asp.net Core中SignalR Core预览版的一些新特性前瞻,附源码(消息订阅与发送二进制数据)

    目录 SignalR系列目录(注意,是ASP.NET的目录.不是Core的) 前言 一晃一个月又过去了,上个月有个比较大的项目要验收上线.所以忙的脚不沾地.现在终于可以忙里偷闲,写一篇关于Signal ...

  6. 背水一战 Windows 10 (89) - 文件系统: 读写文本数据, 读写二进制数据, 读写流数据

    [源码下载] 背水一战 Windows 10 (89) - 文件系统: 读写文本数据, 读写二进制数据, 读写流数据 作者:webabcd 介绍背水一战 Windows 10 之 文件系统 读写文本数 ...

  7. Java模拟POST请求发送二进制数据

    在进行程序之间数据通信时我们有时候就需要自定义二进制格式,然后通过HTTP进行二进制数据交互.交互的示例代码如下: public static void main(String[] args) { S ...

  8. Hibernate 中 联合主键映射 组合关系映射 大对象映射(或者说文本大对象,二进制数据大对象)

    Clob:文本大对象,最长4G Blob:二进制数据大对象,最长4G util: public class HibUtil { private static SessionFactory sessio ...

  9. [ActionScript 3.0] AS利用ByteArray向PHP发送二进制数据生成图片

    flash as3向php发送二进制数据,通过php保存成图片. AS端: package { import com.JPEGEncoder.JPGEncoder; import flash.disp ...

随机推荐

  1. 创建slackapp prometheus告警发到slack

    创建slackapp: https://blog.walterlv.com/post/slack-api-starter-incoming-webhooks.html#%E5%88%9B%E5%BB% ...

  2. [LeetCode] 291. Word Pattern II 词语模式 II

    Given a pattern and a string str, find if str follows the same pattern. Here follow means a full mat ...

  3. 【SSH进阶之路】Spring的IOC逐层深入——为什么要使用IOC[实例讲解](二)

    上篇博客[SSH进阶之路]Spring简介,搭建Spring环境——轻量级容器框架(一),我们简单的介绍了Spring的基本概念,并且搭建了两个版本的Spring开发环境,但是我们剩下了Spring最 ...

  4. 【编程开发】x86,I386,i686, x86_64, x64,amd64、Windows Linux AIX下查看CPU位数和操作系统位数、rpm包名

    a2ps-4.13b-57.2.el5.i386.rpm 每一个rpm包的名称都由"-"和"."分成了若干部分.就拿 a2ps-4.13b-57.2.el5.i ...

  5. Qt信号-槽原理剖析--(2)自己实现信号槽

    时间乃是最大的革新家--培根 先了解一下相关宏: qt为c++增加的相关宏:signals, slots,emit 在qt的预编译过程中,这些宏会被替换. 1)#define signals publ ...

  6. 面试官:知道你的接口QPS是多少么?(转)

    面试官:知道你的接口QPS是多少么? 原创: 孤独烟 孤独烟 9月24日 引言 大家好,我是渣渣烟. 我又来水文章了.这篇文章我个人感觉含金量不是太大,大概5分钟左右就能看完!其实大家都知道,我不爱写 ...

  7. GraphQL简介

    原文地址 https://flaviocopes.com/graphql/ 中译文地址 什么是GraphQL GraphQL的原则 GraphQL vs REST Rest是一个概念 单个端点 根据你 ...

  8. Linux中buff/cache内存占用过高解决办法

    在Linux系统中,我们经常用free命令来查看系统内存的使用状态.在一个centos7的系统上,free命令的显示内容大概是这样一个状态: 这个命令几乎是每一个使用过Linux的人必会的命令,但越是 ...

  9. Java开发笔记(一百二十二)AWT选择框

    前面介绍了两种文本输入框的用法,不过实际应用很少需要用户亲自文字,而是在界面上列出几个选项,让用户勾勾点点完成选择,这样既方便也不容易弄错.依据选择的唯一性,可将选项控件分为两类:一类是在方框中打勾的 ...

  10. python函数知识五 推导式和内置函数一(了解)

    17.推导式: 推导式:将for循环多行变成一行 list推导式:[] #普通模式 print([i for i in range(20)]) #循环模式 #[变量 for i in range(20 ...