JavaScript进行WebSocket字节流通讯示例
websocket进行通讯时,可以选择采用字符串或者字节流的传输模式。但在发送与接收时,需要考虑数据的分包,即分成一个个请求与响应消息。无论是采用哪种传输模式,都不免要遇到这个问题。
采用字符串传输时,接收端可以将每次接收到的字符串拼接到一起,再检测是否出现了某一特定子串,比如连续两个换行,即可将一个长的字符串分隔成一个个的请求或响应消息。这种处理方式比较简单且有效。但这里,介绍另一种模式,即传输字节流。
首先考虑下分包的问题,一般分为消息头与消息体。出于简单目的,消息头里只存放一个消息体的长度,消息体为字节数组。
确定了数据包格式接下来可以写实现代码了,首先是连接:
var socket;
var uri = "ws://" + window.location.host + "/push"; // 示例地址
function Connect(uri) {
socket = new WebSocket(uri);
socket.binaryType = "arraybuffer";
socket.onopen = function (e) {
console.log("已连接至服务器");
};
socket.onclose = function (e) {
console.log("链接已关闭");
};
socket.onmessage = function (e) {
doReceive(e.data);
};
socket.onerror = function (e) {
console.log("出现错误");
};
}
这里将socket变量定义为公共的,因为后续的发送方法会用到这个变量。默认JavaScript里的WebSocket传输是采用字符串模式的,采用UTF-8编码,通过将binaryType属性设置为arraybuffer来使用字节流传输。
当发生onmessage事件时代表接收到数据,保存在参数e.data里。每一次接收都可能接收到一个完整的消息或部分消息,我们通过一个doReceive方法来进行消息数据包的拆分。代码如下:
var receive = [];
var length = 0;
function doReceive(buffer) {
receive = receive.concat(Array.from(new Uint8Array(buffer)));
if (receive.length < 4) {
return;
}
length = new DataView(new Uint8Array(receive).buffer).getUint32(0);
if (receive.length < length + 4) {
return;
}
var bytes = receive.slice(4, length + 4);
doSomething(bytes);
receive = receive.slice(length + 4);
};
其中receive作为接收缓冲区,每次接收到数据时先将其存到该缓冲区里。之后检查其长度是否大于等于4字节,即上文定义的消息头长度。若满足条件,则将其作为Uint32值读取,代表消息体长度。之后检查缓冲区是否大于消息头加消息体长度,若满足则读取消息体,之后得到的bytes字节数组即为完整的消息体。最后,用剩余字节重置缓冲区以备下一次读取。
其中buffer参数为ArrayBuffer类型,其代表原始的字节数组,本身是无意义的。JavaScript通过一个个视图来解释这些字节。Uint8Array即是其中一种视图,它将ArrayBuffer中的字节作为8位无符号整数来对待,正好一字节对应一个uint8整数。类似的还有Uint16Array,它将ArrayBuffer中的字节作为16位无符号整数来对待,则每两位对应一个uint16整数。
而DataView是JavaScript API提供的一种视图,他将ArrayBuffer中的数据作为网络流对待,它采用大端编码,可以用它来读取或写入数据。这里我们用它读取了一个Uint32的值。
接下来是发送方法,代码如下:
function doSend(bytes) {
var buffer = new ArrayBuffer(bytes.length + 4);
var view = new DataView(buffer);
view.setUint32(0, bytes.length);
for (var i = 0; i < bytes.length; i++) {
view.setUint8(i + 4, bytes[i]);
}
socket.send(view);
};
其中参数bytes是已经编码过的字节数组,这里通过DataView视图将其存储到ArrayBuffer对象里,以备发送。按照上文约定,需先设置Uint32型的消息体长度,再设置消息体。
最后,本文按约定的消息格式来进行请求与响应消息的传输,消息体为不定长度的字节序列。其本身是无意义的。我们可以通过API提供的Uint16Array、Uint32Array等视图将其作为整数值序列,也可以自我实现其内容的解释方式。
比如参考这里将其作为采用UTF-8编码的字符串。之后可再将字符串打印或反序列化为JSON对象等。
JavaScript进行WebSocket字节流通讯示例的更多相关文章
- NetCore WebSocket 即时通讯示例
1.新建Netcore Web项目 2.创建简易通讯协议 public class MsgTemplate { public string SenderID { get; set; } public ...
- C# 实现WEBSOCKET聊天应用示例
C# 实现WEBSOCKET聊天应用示例 http://blog.163.com/da7_1@126/blog/static/10407267820121016103055506/ 2012-11-1 ...
- 使用tomcat方式实现websocket即时通讯服务端讲解
使用tomcat方式实现websocket即时通讯服务端讲解 第一种方案:使用Tomcat的方式实现 tomcat版本要求:tomcat7.0+.需要支持Javaee7 导入javeee-api的ja ...
- 微信小程序使用GoEasy实现websocket实时通讯
不需要下载安装,便可以在微信好友.微信群之间快速的转发,用户只需要扫码或者在微信里点击,就可以立即运行,有着近似APP的用户体验,使得微信小程序成为全民热爱的好东西~ 同时因为微信小程序使用的是Jav ...
- iOS-多线程--介绍NSThread和GCD及其它们的线程通讯示例
前言:下面就不一一列出 pthread.NSThread.GCD.NSOperation 的完整的各种方法了,只分别将最常用的列出来,以便偶尔瞄一眼. 一.NSThread 1> 线程间的通讯/ ...
- JavaScript创建读取cookie代码示例【附:跨域cookie解决办法】
使用JavaScript 原生存取cookie代码示例: var cookie = { set : function(name, value, expires, path, domain, secur ...
- Java 与 JavaScript 对websocket的使用
ebsocket,HTML5中新一代全双工通信协议.其底层仍然是http协议. 传统 HTTP 请求响应客户端服务器交互图 WebSocket 请求响应客户端服务器交互图 WebSocket 客户端支 ...
- java SSM 框架 多数据源 代码生成器 websocket即时通讯 shiro redis 后台框架源码
A 调用摄像头拍照,自定义裁剪编辑头像 [新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统]B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单; 技 ...
- java SSM 框架 代码生成器 websocket即时通讯 shiro redis
1. 权限管理:点开二级菜单进入三级菜单显示 角色(基础权限)和按钮权限 角色(基础权限): 分角色组和角色,独立分配菜单权限和增删改查权限. 按钮权限: 给角色分配按钮权限. ...
随机推荐
- 浅谈前端H5自定义分享实现方法
引入jweinxin相关js文件,然后才可以做H5的分享 <script src="js/jweixin-1.2.0.js"></script> let ...
- Windbg命令的语法规则系列(一)
本文介绍使用调试器命令必须遵循的语法规则.使用Windbg调试时,应遵守以下一般语法规则: 您可以在命令和参数中使用大小写字母的任意组合,除非在本节的主题中特别指出. 可以用一个或多个空格或逗号(,) ...
- REdis之maxmemory解读
redis.conf中的maxmemory定义REdis可用最大物理内存,有多种书写方式,以下均为合法: maxmemory 1048576 maxmemory 1048576B maxmemory ...
- SQL基础-过滤数据
一.过滤数据 1.使用WHERE子句 过滤数据:关键字WHERE SELECT 字段列表 FROM 表名 WHERE 过滤条件; 过滤条件一般由要过滤的字段.操作符.限定值三部分组成: 如: SELE ...
- vue使用axios发送请求,都会发送两次请求
vue 使用axios,每次的请求都会发送两次,第一次的请求头为options CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sha ...
- 微信小程序之页面导航栏
效果图: 页面有点丑,作为初次学习,页面可以要求不那么美观,先学会再说.毕竟后面可以优化的很漂亮. 代码实例如下: <view class="section btn-area" ...
- IDEA实现SpringBoot热部署
1.pom.xml添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifac ...
- Spring Cloud Ribbon---微服务调用和客户端负载均衡
前面分析了Eureka的使用,作为服务注册中心,Eureka 分为 Server 端和 Client 端,Client 端作为服务的提供者,将自己注册到 Server 端,Client端高可用的方式是 ...
- semi-join子查询优化 -- Duplicate Weedout策略
duplicate weedout是执行semi-join子查询的一种策略. 将semi-join作为一个常规的inner join.然后使用一个临时表,将重复的记录排除. 假设,你有一个查询,你在寻 ...
- linux进程守护脚本
为了防止进程异常挂掉,为了避免影响业务,编写一个守护进程,定时检查某个进程是否存在,如果不存在则自动启动该进程.编写脚本文件daemon.sh文件 while true; do server=`ps ...