我是公众号线下派对游戏作者HullQin(欢迎关注公众号,发加微信,交个朋友),授权转载此文需要作者HullQin。我独立开发了《联机桌游合集》,这是一个网页,在这里你可以轻松地和朋友一起玩网络游戏,五子棋等游戏,不收费,也没有广告。还为GameJam2022开发了《Dice Crush》,喜欢的话可以关注我HullQin哦~有空我会分享制作游戏的相关技术。后台在线功能是通过WebSocket实现的,途中踩了一些坑,分享给大家。ws.close()有一个参数。这个参数最好填写为错误码,表示关闭连接的原因:当WebSocket断开连接时,会向对方发送一个错误码。如果浏览器主动断开连接,浏览器会向服务器发送错误代码。如果服务器断开连接,服务器会向浏览器发送一个错误代码。所有错误码可以参考MDN:CloseEventCode。在浏览器中,当调用ws.close()函数关闭连接时,默认的错误代码是1005,这意味着没有提供状态代码,即使是预期的。这是容易出错的,很多人可能会认为它的默认值是1000(正常关闭)。结果服务器收到1005,解决前端关机是否正常关机,可以使用ws.close(1000)。如果前端没有正常关闭,需要自定义一个异常错误码,范围是4000-4999。另外,如果您正在开发一个框架,您可以使用的错误代码范围是3000-3999。如果接收到的数据是二进制的,一定要设置ws.binaryTypews.binaryType有2个值:blob和arraybuffer。blob是它的默认值。如果接收的是二进制数据:当ws.binaryType为blob,event.data为Blob类型时,需要调用awaitevent.data.arrayBuffer()获取ArrayBuffer类型的数据。如果你接收的是二进制数据,当ws.binaryType是arraybuffer时,event.data是ArrayBuffer类型。我的《联机桌游合集》刚上线的时候,一个用iOS的朋友跟我说,她重试了很多次都进不了游戏。但我已经在我的Android、iPad、iPhone、Mac和Windows上对其进行了测试。经过排查,发现是她iOS14中的Safari浏览器。虽然我没有设置ws.binaryType为arraybuffer,但是因为Safari检测到了二进制数据,所以直接将event.data转为ArrayBuffer类型,而不是Blob类型,导致调用awaitevent.data.arrayBuffer()时出错。查看当时的commit记录:如果你的ws接收到的数据是二进制格式,调用constws=newWebSocket()后立即设置ws.binaryType='arraybuffer'。但是如果你的ws可能接收到的是二进制数据或者文本数据,建议参考官方MDN案例,将ws.binaryType设置为arraybuffer,但是要加条件判断:constws=newWebSocket("ws://localhost:8080");//将二进制类型从"blob"更改为"arraybuffer"ws.binaryType="arraybuffer";ws.onmessage=(event)=>{if(event.datainstanceofArrayBuffer){//二进制帧console.log(事件.数据);}else{//文本框console.log(event.data);}});关于消息的合并和拆分我在Mac环境下使用Safari浏览器和Chrome浏览器的WebSocket,有两种不同的现象:如果从后端发送到前端的消息包含\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)=>{//处理每条消息});};这里的坑不是说多个ws实例的并发量很大,而是做压力测试的话,可能会遇到坑。你需要知道:Chrome有一个特点:如果同时建立多个WebSocket连接,它们只会一个接一个建立。等待前面的ws建立连接成功,后面的ws开始建立连接。如果要测试后台服务被多个客户端同时连接,如果有并发问题,请不要使用同一个ChromeTab进行测试。您可以打开多个选项卡和多个浏览器,或使用Safari进行测试。因为在Safari上:如果同时建立多个WebSocket连接,ws连接请求是同时发送的(当然注意同时ws连接数是有上限的,在做压测的时候,一次连接太多选项卡是没用的。)。我在写文章《多房间的聊天室(六)为什么要加锁?不加锁行不行啊?》的时候发现了这个问题。最后,我是公众号线下派对游戏的作者HullQin(欢迎关注公众号,发送加微信,交友),转载本文需作者HullQin授权。我独立开发了《联机桌游合集》,这是一个网页,在这里你可以轻松地和朋友一起玩网络游戏,五子棋等游戏,不收费,也没有广告。还为GameJam2022开发了《Dice Crush》,喜欢的话可以关注我HullQin哦~有空我会分享制作游戏的相关技术。
