JavaScript进⾏WebSocket字节流通讯⽰例
websocket进⾏通讯时,可以选择采⽤字符串或者字节流的传输模式。但在发送与接收时,需要考虑数据的分包,即分成⼀个个请求与响应消息。⽆论是采⽤哪种传输模式,都不免要遇到这个问题。
采⽤字符串传输时,接收端可以将每次接收到的字符串拼接到⼀起,再检测是否出现了某⼀特定⼦串,⽐如连续两个换⾏,即可将⼀个长的字符串分隔成⼀个个的请求或响应消息。这种处理⽅式⽐较简单且有效。但这⾥,介绍另⼀种模式,即传输字节流。
⾸先考虑下分包的问题,⼀般分为消息头与消息体。出于简单⽬的,消息头⾥只存放⼀个消息体的长度,消息体为字节数组。
确定了数据包格式接下来可以写实现代码了,⾸先是连接:
var socket;
var uri = "ws://" + window.location.host + "/push"; // ⽰例地址
function Connect(uri) {
socket = new WebSocket(uri);
socket.binaryType = "arraybuffer";
console.log("已连接⾄服务器");
};
console.log("链接已关闭");
};
doReceive(e.data);
};
console.log("出现错误");
};
}
这⾥将socket变量定义为公共的,因为后续的发送⽅法会⽤到这个变量。默认JavaScript⾥的WebSocket传输是采⽤字符串模式的,采⽤UTF-8编码,通过将binaryType属性设置为arraybuffer来使⽤字节流传输。
当发⽣onmessage事件时代表接收到数据,保存在参数e.data⾥。每⼀次接收都可能接收到⼀个完整的消息或部分消息,我们通过⼀个doReceive⽅法来进⾏消息数据包的拆分。代码如下:
var receive = [];
var length = 0;
function doReceive(buffer) {
receive = at(Array.from(new Uint8Array(buffer)));
websocket和socket
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对象等。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论