1、初识 ByteBuffer

官方文档:ByteBuffer:网络编程前置技能

https://www.tiocloud.com/doc/tio/83
  • ByteBuffer是nio/aio编程所必须掌握的一个数据结构,也是掌握tio所必须要学会的基础知识。
  • 设想你不懂Map,不懂List,不懂Set,那么你在编程领域将会一事无成,同样的道理,如果你不懂ByteBuffer,你无法在nio/aio编程领域立足

我们可以把bytebuffer理解成如下几个属性组成的一个数据结构

byte[] bytes:用来存储数据
int capacity:用来表示bytes的容量,那么可以想像capacity就等于bytes.size(),此值在初始化bytes后,是不可变的。
int limit:用来表示bytes实际装了多少数据,可以容易想像得到limit <= capacity,此值是可灵活变动的
int position:用来表示在哪个位置开始往bytes写数据或是读数据,此值是可灵活变动的

2、ByteBuffer 的简单使用

import java.nio.ByteBuffer;/*** ByteBuffer的简单使用*/
public class ByteBufferDemo {public static void main(String[] args) {// 创建ByteBufferByteBuffer byteBuffer = ByteBuffer.allocate(6);// 写数据byteBuffer.put("Test".getBytes());// ByteBuffer的三要素System.out.println(new String(byteBuffer.array()));System.out.println(byteBuffer.capacity());System.out.println(byteBuffer.limit());System.out.println(byteBuffer.position());// 读数据byteBuffer.position(1);byteBuffer.limit(3);System.out.println((char) byteBuffer.get());System.out.println((char) byteBuffer.get());}
}

输出内容:

3、接收 byte[] bytes 数据

在 t-io 的消息处理器中,有这么一个方法:

    /*** <li>当收到Opcode.BINARY消息时,执行该方法。也就是说如何你的ws是基于BINARY传输的,就会走到这个方法</li>** @param wsRequest* @param bytes* @param channelContext* @return 可以是WsResponse、byte[]、ByteBuffer、String或null,如果是null,框架不会回消息* @throws Exception* @author tanyaowu*/@Overridepublic Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {return null;}

当收到 Opcode.BINARY 消息时,执行该方法,也就是说发送方的消息类型为 Opcode.BINARY 时则会执行该方法,byte[] bytes 就是发送的内容,我们需要按照约定的规则进行解析消息体

4、byte[] 处理工具类 ByteUtil.java

/*** byte 处理工具类*/
public class ByteUtils {/*** byte[] 转 int(高字节序)** @param b* @return*/public static int toInt(byte[] b) {int res = 0;for (int i = 0; i < b.length; i++) {res += (b[i] & 0xff) << ((3 - i) * 8);}return res;}/*** int 转 byte[](高字节序)** @param n* @return*/public static byte[] toByte(int n) {byte[] b = new byte[4];b[3] = (byte) (n & 0xff);b[2] = (byte) (n >> 8 & 0xff);b[1] = (byte) (n >> 16 & 0xff);b[0] = (byte) (n >> 24 & 0xff);return b;}/*** 合并多个byte[]** @param values* @return*/public static byte[] toByte(byte[]... values) {int length_byte = 0;for (int i = 0; i < values.length; i++) {length_byte += values[i].length;}byte[] all_byte = new byte[length_byte];int countLength = 0;for (int i = 0; i < values.length; i++) {byte[] b = values[i];System.arraycopy(b, 0, all_byte, countLength, b.length);countLength += b.length;}return all_byte;}/*** 组装消息格式** @param msgId     消息id* @param byteArray 消息体* @return*/public static byte[] toByte(int msgId, byte[] byteArray) {return toByte(toByte(msgId), toByte(byteArray.length), byteArray);}
}

5、消息转换体

import lombok.Data;@Data
public class MessageVO {/*** 消息类型*/private int msgId;/*** 消息长度*/private int length;/*** 消息体*/private byte[] body;/*** 判断是否是正确的消息** @return*/public boolean isSuccess() {return length == body.length ? true : false;}
}
  • 1、我们事先约定,在消息的前四位为 msgId,用来区分是什么消息事件
  • 2、在消息的第四位到第八位为 length,length 也就是 body 的长度
  • 3、如果 length != body.length,则表示不是合法的消息,拒绝接收

6、消息转换过程

我们需要将收到的 byte[] 消息转换为 messageVO,并判断消息是否合法

    /*** 获取消息对象** @param bytes* @return*/public MessageVO getMessageVO(byte[] bytes) {// 消息对象MessageVO messageVO = new MessageVO();// 解析消息体ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);// 读取msgIdbyteBuffer.position(0).limit(4);byte[] dst = new byte[byteBuffer.limit() - byteBuffer.position()];byteBuffer.get(dst);messageVO.setMsgId(ByteUtils.toInt(dst));// 读取lengthbyteBuffer.position(4).limit(8);byte[] dst1 = new byte[byteBuffer.limit() - byteBuffer.position()];byteBuffer.get(dst1);messageVO.setLength(ByteUtils.toInt(dst1));// 读取bodybyteBuffer.position(8).limit(byteBuffer.capacity());byte[] dst2 = new byte[byteBuffer.limit() - byteBuffer.position()];byteBuffer.get(dst2);messageVO.setBody(dst2);return messageVO;}

我们得到了 messageVO,后,只需要判断 length == body.length ? true : false 就能判断此消息是否合法

此时,我们的消息体依然是 byte[],我们需要将 byte[] 解析成为我们具体能看懂的消息内容,我们需要借助 protobuf,如下:

7、引入 protobuf 依赖

  • 1、protobuf 简介

protobuf (protocol buffer) 是谷歌内部的混合语言数据标准。通过将结构化的数据进行序列化(串行化),用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

我们说的 protobuf 通常包括下面三点:

一种二进制数据交换格式。可以将 C++ 中定义的存储类的内容 与 二进制序列串 相互转换,主要用于数据传输或保存
定义了一种源文件,扩展名为 .proto (类比 .cpp 文件),使用这种源文件,可以定义存储类的内容 protobuf 有自己的编译器 protoc,可以将 .proto
编译成.cc文件,使之成为一个可以在 C++ 工程中直接使用的类
序列化:将数据结构或对象转换成二进制串的过程。反序列化:将在序列化过程中所产生的二进制串转换成数据结构或对象的过程。

  • 2、引入 maven 依赖
<!-- Protocol Buffer -->
<dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.2.0</version>
</dependency>
<dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java-util</artifactId><version>3.2.0</version>
</dependency>

8、建立 .proto 文件

在 src.main 目录下新建 proto 包,在 proto 包中新建 .proto 文件,例如 login.proto:

syntax = "proto3";option java_package = "com.asurplus.websocket.protobuf";// 用户登录请求
message UserLoginC2S {// 1000int32 msgId = 1;// 用户名string username = 2;// 密码string password = 3;
}// 用户登录响应
message UserLoginS2C {// 1001int32 msgId = 1;// 用户名string username = 2;// 密码string password = 3;// 是否成功(0-失败1-成功)int32 isSuccess = 4;
}

类似于 api 接口文档的一种东西,规定了接口的参数,前面是参数的数据类型,后面的 1,2,3是序号,而不是默认值

9、安装 proto 编译插件

在 pom.xml 文件中,增加插件:

<build><defaultGoal>package</defaultGoal><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.5.0.Final</version></extension></extensions><plugins><!-- protobuf 编译组件 --><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>0.5.1</version><extensions>true</extensions><configuration><protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot><protocArtifact>com.google.protobuf:protoc:3.2.0:exe:${os.detected.classifier}</protocArtifact></configuration><executions><execution><goals><goal>compile</goal></goals></execution></executions></plugin><!-- 编译jar包的jdk版本 --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><includeSystemScope>true</includeSystemScope></configuration></plugin></plugins>
</build>
  • 1、com.asurplus.AsurplusApplication 为你项目的启动类
  • 2、src/main/proto 为你 .proto 文件存放的位置
  • 3、3.2.0 最好使用你 proto 依赖的版本号

插件安装成功后,如图:

你的 maven 插件出现了 protobuf 则表示你的插件安装成功,点击 protobuf:compile 就能编译你的 .proto 文件为 java 的 .class 文件

打包成功后,就能得到这样一个 java 文件,我们在代码中就能使用它了

10、byte[] 转换为 proto 对象接收消息

我们在第 6 步已经得到了 messageVO,如果我们确认了该消息体是合法的,我们根据 msgId 边能将 messageVO 中的 body 解析成功 proto 的实体类,例如:

/*** <li>当收到Opcode.BINARY消息时,执行该方法。也就是说如何你的ws是基于BINARY传输的,就会走到这个方法</li>** @param wsRequest* @param bytes* @param channelContext* @return 可以是WsResponse、byte[]、ByteBuffer、String或null,如果是null,框架不会回消息* @throws Exception* @author tanyaowu*/
@Override
public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {MessageVO message = TioMsgUtils.getMessage(bytes);// 消息不合法if (!message.isSuccess()) {return null;}// 假设消息的 msgId 为 1000Login.UserLoginC2S userLoginC2S = Login.UserLoginC2S.parseFrom(message.getBody());// 消息idSystem.out.println(userLoginC2S.getMsgId());// 用户名System.out.println(userLoginC2S.getUsername());// 密码System.out.println(userLoginC2S.getPassword());/*** TODO 执行你的业务逻辑*/return null;
}

这样,我们就使用 proto 解析了 messageVO 中的 byte[] 数据,得到了我们想要的消息内容,接收消息的过程就结束了

11、proto 对象 转化为 byte[] 发送消息

/*** 发送消息*/
public void sendMessage() {// new 一个对象Login.UserLoginS2C.Builder builder = Login.UserLoginS2C.newBuilder();builder.setMsgId(1001);builder.setUsername("test");builder.setPassword("123456");builder.setIsSuccess(1);// 拼接byte[]byte[] bytes = ByteUtil.toByte(builder.getMsgId(), builder.build().toByteArray());// 响应对象WsResponse wsResponse = WsResponse.fromBytes(bytes);// 指定发送给用户Tio.sendToUser(TioCoreConfig.serverTioConfig, "1", wsResponse);
}

同样使用的 proto 生成的对象,通过 byteUtil 工具类组装响应对象,通过 t-io 发送消息

t-io 中使用ByteBuffer收发消息的过程就到这儿,希望能够帮助到你

如您在阅读中发现不足,欢迎留言!!!

【tio-websocket】6、tio-websocket-server使用ByteBuffer收发消息相关推荐

  1. websocket之一:websocket简介

    Websocket websocket为一次HTTP握手后,后续通讯为tcp协议的通讯方式. WebSocket 使用一种被称作"Upgrade handshake(升级握手)"的 ...

  2. 未能分析从服务器收到的消息,WebSocket Javascript客户端未收到来自服务器的消息...

    我已经在本地GlassFish 4.1服务器上部署了Java Web应用程序,该服务器实现了与Web客户端互操作的WebSockets.我能够通过套接字成功执行客户端到服务器的通信,但由于某种原因,服 ...

  3. java websocket原理_Java WebSocket基本原理

    WebSocket协议介绍 WebSocket协议是一个网络协议,允许两个相连的端在一个单一TCP连接上进行全双工消息通信. 在WebSocket的场景中,连接通过HTTP和WebSocket端点交互 ...

  4. WebSocket使用javax.websocket.RemoteEndpoint.Basic.sendObject(Object arg0)向页面方法发送对象

    WebSocket接口中有一个直接发送对象给页面的方法: voidjavax.websocket.RemoteEndpoint.Basic.sendObject(Object arg0) throws ...

  5. springboot+websocket+token验证+jedis支持集群部署发消息

    目录 websocket主要代码 pom.xml MyWebSocketHandler WSInterceptor WebSocketConfig Redis订阅广播实现Session共享 pom.x ...

  6. SpringBoot 集成 webSocket,实现后台向客户端推送消息

    图文等内容参考链接 SpringBoot2.0集成WebSocket,实现后台向前端推送信息_Moshow郑锴的博客-CSDN博客_springboot websocket WebSocket 简介 ...

  7. php通知websocket,php实现websocket实时消息推送

    php实现websocket实时消息推送,供大家参考,具体内容如下 SocketService.php /** * Created by xwx * Date: 2017/10/18 * Time: ...

  8. android websocket封装,Android WebSocket 方案选型OkHttp

    目前Android WebSocket 框架 主要包括: SocketIO Java-WebSocket OkHttp WebSocket 一开始我首选的是采用SocketIO方案,因为考虑该方案封装 ...

  9. SpringBoot2+Netty+WebSocket(netty实现websocket,支持URL参数)

    关于Netty Netty 是一个利用 Java 的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的 API 的客户端/服务器框架. 更新 2019-7-11 新增URL参数支持,并解决了带参U ...

最新文章

  1. 技术总监需要会些什么?
  2. 要获得“机器学习或数据科学”的工作,到底选哪种编程语言更好?
  3. vs2008页面布局GridLayout绝对定位的设置
  4. rust比java慢,rust为什么跑得比js慢
  5. 机会只留给有准备的人
  6. 基于深度学习的多目标跟踪算法(上):端到端的数据关联
  7. 求你别自己瞎写工具类了,Spring自带的这些他不香吗?
  8. TikTok 已经成为影响力营销的新战场
  9. u-boot之autoconf.mk解析
  10. bzoj4695 最假女选手(势能线段树/吉司机线段树)题解
  11. C语言程序段的定义、实际应用分析
  12. 年底绩效考核期又来临,企业如何挑选一款好用的绩效考核管理系统?
  13. JavaScript系列之注释
  14. lintcode triangle 数字三角形
  15. 当你发现微信好友朋友圈是“一条杠”,你会把她、他删除吗?
  16. word使用技巧-批量删除图片技巧
  17. 无法访问yunlong.wj0920wjx.net指向的web服务器(或虚拟主机)的目录,请检查网络设置
  18. Gurobi--Error code: 10005. Unable to retrieve attribute solved ‘Pi‘ 解决
  19. HTTPS是什么幺蛾子
  20. 假如不小心因病去世,怎么给家人留下足够的财富呢?

热门文章

  1. Eclipse常见问题之英文状态下输入的英文字体不正确的解决方法
  2. 985计算机学校2017排名,2017年全国“985”大学排名及王牌专业全解析
  3. 计算机教研组活动目的,教研组活动方案
  4. 婚姻出现危机最终做出妥协的多是女人
  5. 关于正当防卫的几个案例分析
  6. phpstorm集成phpunit
  7. 加州大学伯克利分校计算机科学专业,加州大学伯克利分校之计算机科学系
  8. Android学习-通知的使用详解
  9. 互联网企业数据安全体系建设(美团点评)
  10. 2021.10.22-23科研日志