共计 2521 个字符,预计需要花费 7 分钟才能阅读完成。
我是 HullQin,公众号 线下团聚游戏 的作者(欢送关注公众号,发送加微信,交个敌人),转发本文前需取得作者 HullQin 受权。我独立开发了《联机桌游合集》,是个网页,能够很不便的跟敌人联机玩斗地主、五子棋等游戏,不免费没广告。还开发了《Dice Crush》加入 Game Jam 2022。喜爱能够关注我 HullQin 噢~我有空了会分享做游戏的相干技术。
背景
其中的联机性能,就是通过 WebSocket 实现的,中途也踩了一些坑,分享给大家。
ws.close()有个参数,最好填上
这个参数就是错误码,表明了敞开连贯的起因:
WebSocket 断开连接时,会发送一个错误码给另一方。如果是浏览器被动断开连接,浏览器发错误码给服务器。如果是服务器断开连接,服务器发错误码给浏览器。
所有错误码可参考 MDN: CloseEvent Code。
在浏览器中,调用 ws.close()
函数敞开连贯时,默认错误码是 1005,含意是 no status code was provided even though one was expected。
这是容易犯错的,可能很多人认为它的默认值是 1000(失常敞开)。后果服务器收到的却是 1005。
解决
如果前端敞开是失常敞开,你能够应用ws.close(1000)
。
如果前端敞开不是失常敞开,你须要自定义一个异样错误码,范畴是 4000-4999。
此外,如果你在开发一个框架,那么你可用的错误码范畴是 3000-3999。
如果接管的数据是二进制,肯定要设置 ws.binaryType
ws.binaryType
有 2 种值:blob
和arraybuffer
。
blob
是它的默认值。
如果你收到了二进制数据:当 ws.binaryType
为blob
时,event.data 是 Blob 类型,你须要调用 await event.data.arrayBuffer()
获取 ArrayBuffer 类型的数据。
如果你收到了二进制数据,当 ws.binaryType
为arraybuffer
时,event.data 是 ArrayBuffer 类型。
踩坑点
我的《联机桌游合集》刚上线时,有个应用 iOS 的敌人通知我,她无奈进入游戏,重试了屡次也不行。
然而我曾经用我手头的安卓、iPad、iPhone、Mac、Windows 全都测试过一遍了。
通过排查,才发现是她的 iOS14 中 Safari 浏览器搞的鬼。尽管我没有设置 ws.binaryType
为arraybuffer
,
然而因为 Safari 检测到是二进制数据,就间接把 event.data
转换为了 ArrayBuffer 类型,不是 Blob 类型,导致我调用 await event.data.arrayBuffer()
时出错了。
回顾过后的 commit 记录:
解决
如果你 ws 收到的数据都是二进制格局,在调用 const ws = new WebSocket()
后,立马设置ws.binaryType = 'arraybuffer'
。
然而如果你 ws 可能收到二进制数据,也可能收到文本数据,倡议参考 MDN 官网案例,设置 ws.binaryType
为arraybuffer
,然而加个条件判断:
const ws = new WebSocket("ws://localhost:8080");
// Change binary type from "blob" to "arraybuffer"
ws.binaryType = "arraybuffer";
ws.onmessage = (event) => {if(event.data instanceof ArrayBuffer) {
// binary frame
console.log(event.data);
} else {
// text frame
console.log(event.data);
}
});
对于音讯合并与拆分
我在 Mac 环境下,应用 Safari 浏览器和 Chrome 浏览器的 WebSocket,有 2 种不同的景象:
如果后端发送给前端的音讯中,蕴含了 \n
换行符。在 Chrome 中,会触发屡次 onmessage
事件,各个音讯是被 Chrome 基于 \n
宰割开了,宰割后的音讯按程序顺次触发 onmessage
来解决。在 Safari 中,只触发了一次 onmessage
事件,Safari 没有帮咱们分隔音讯。
事实上,在 WebSocket 音讯中,\n
换行符自身就是辨别音讯的特殊符号。如果须要短时间内间断发送多条音讯给客户端,一种常见的优化伎俩就是把这些音讯一次性发送过来,用 \n
宰割。
Chrome 做的很好,帮咱们宰割好了。然而像 Safari 这种浏览器没有帮咱们宰割,为了兼容性,咱们也须要解决下。
解决
如果后端有「批量发送」的机制,就在 onmessage
事件中,把音讯按 \n
宰割后,再顺次解决。如果后端没有实现「批量发送」的机制,则能够疏忽。
ws.onmessage = (event) => {event.data.split('\n').forEach((message) => {// 解决各个 message});
};
对于多个 ws 实例并发
这里的坑不是特地大,但如果你要做压力测试,那就可能会遇到坑。你须要晓得:
Chrome 有个特点:如果你同时建设多个 WebSocket 连贯,只会一个一个建设。等前一个 ws 建设连贯胜利,后一个 ws 开始建设连贯。
如果你想测试后盾服务同时被多个客户端连贯,有无并发问题时,不要用同一个 Chrome Tab 来测。能够开多个 Tab 和多个浏览器,或者用 Safari 测试。
因为在 Safari 上:如果你同时建设多个 WebSocket 连贯,是同时发送 ws 连贯申请的(当然留神 ws 同时连接数有下限,做压测时,一个 Tab 没必要一次性连太多,是没用的)。
我在写文章《多房间的聊天室(六)为什么要加锁?不加锁行不行啊?》时,发现了这个问题。
写在最初
我是 HullQin,公众号 线下团聚游戏 的作者(欢送关注公众号,发送加微信,交个敌人),转发本文前需取得作者 HullQin 受权。我独立开发了《联机桌游合集》,是个网页,能够很不便的跟敌人联机玩斗地主、五子棋等游戏,不免费没广告。还开发了《Dice Crush》加入 Game Jam 2022。喜爱能够关注我 HullQin 噢~我有空了会分享做游戏的相干技术。