写点什么

[Go WebSocket] 多房间的聊天室(一)思考篇

作者:HullQin
  • 2022 年 9 月 09 日
    广东
  • 本文字数:1939 字

    阅读完需:约 6 分钟

我是 HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者 HullQin 授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加 Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。

背景

第一篇文章:《为什么我选用 Go 重构 Python 版本的 WebSocket 服务?》,介绍了我的目标。


第二篇文章:《你的第一个 Go WebSocket 服务: echo server》,介绍了一下怎么写一个 WebSocket server。


第三篇文章:《单房间的聊天室》,介绍了如何实现一个单房间的聊天室。


今天我们实现一个多房间的聊天室。如果你没阅读上面的文章,一定要先看一下,因为这篇文章更复杂,如果你不弄懂上面几篇,这篇可能跟不上节奏噢。

以第三篇文章的代码为起点

今天,我们修改上次「聊天室」的代码即可。


因为gorilla/websocket官方并未提供多房间聊天室的 demo,只提供了单房间聊天室的 demo(就是上篇文章所讲的),这次我们要自己动手开发啦!

思考

还记得上次绘制的架构图吗?



这次,我们要动手改代码了!先不要直接写代码,我们先画图!理清思路,代码就信手拈来了!


以前,我们全局只有 1 个Hub goroutine,而广播(broadcast)正是依赖了这个 goroutine。客户端把希望广播的消息传到 broadcast 这个 channel 里,由Hub goroutine读取 broadcast channel,遍历它的 clients,把消息写入 send channel,再由各个客户端的Write goroutine读取 send channel,发送消息。


现在既然要实现多房间,Hub goroutine应该有多个。具体表现应该是这样:


何时创建房间

上一篇文章,我们只有一个房间,所以在服务启动时,在 main 函数里已经启动了Hub goroutine,但是这次不行了。我们可能有多个房间,所以有两种方案。

方案一:设置固定的几个房间

如果房间数目是固定的,例如你设置了一共只有 10 个房间,那么你完全可以参考上篇文章,只不过这次要调用 10 次go hub.run()了。因为每次调用就启动一个 goroutine,10 个房间就是 10 次。

方案二:动态创建房间

如果房间允许动态创建,那么你就需要在客户端连接时,给你传入一个「房间号」参数,你需要判断当前「房间号」是否存在,如果不存在,需要主动创建(调用go hub.run()),如果存在,就用存在的房间。

结论

如果是方案一,没有挑战性,参考上篇文章,你也可以轻松实现。今天我们按照方案二来做。

如何决定客户端连哪个房间

既然我们有多个房间,客户端是一定需要告诉服务端:我要进哪个房间的。有 3 个常用方案:

方案一:URL 里指定

我们可以在连接 WebSocket 时,在 URL 里指定(通过路径或参数)。上篇文章,我们对 WebSocket 服务定义的路有规则是/ws。可以再扩充一下,变为/ws/【房间号】。读取【房间号】即可。

方案二:cookie 里指定

在连接 WebSocket 时,会把当前域名的 cookie 也带过去,服务端可以读取的到。因此,也可以把房间号信息存到 cookie 里。


注:「cookie 指定」这种方式很常用,尤其是网页里的【用户消息】,如果有人给你点赞、关注,这个消息需要实时推送给用户。而且如果你多开了几个 Tab,这些 Tab 都应该收到。这种情况下,你的每个浏览器 Tab 就是一个「Client」,你这个账号就是一个「Room」。(这时候 Room 就是一个抽象概念了,不能把它当作是一个真实的房间,只能当作一个连接池子,广播消息时,这个池子里的所有 Client 会收到相同的消息)

方案三:连接完成时,客户端主动发一个消息,表明房间

这个跟方案一、二有本质不同。方案一、二在 WebSocket 连接时,就确定了房间号,效率更高。但是方案三是在连接完成时,客户端主动发一个消息,告知服务端房间号。


虽然效率不如方案一、二,但是更加灵活,扩展性好。因为那个消息里可以附带更多的信息。


这也是很多应用采取的方案,大胆用吧!因为效率影响可以忽略不计,但是可扩展性影响太大了,会影响你未来几年的维护成本!

为什么不放在 header 信息?

因为 WebSocket 协议其实不建议把信息放在自定义 header 里。你看建立 WebSocket 连接的 JS API 的语法:



不像 Http 请求 APIfetchWebSocket不允许用户传入 header 参数。如果你想传递额外信息,官方建议就是三种:URL、cookie、连接建立后发个消息。本文均已罗列。


好了。以上就是本篇内容了,下一篇,我们进入【实践篇】,写代码,实现一个多房间的聊天室。

写在最后

我是 HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者 HullQin 授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加 Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。

发布于: 刚刚阅读数: 4
用户头像

HullQin

关注

公众号【线下聚会游戏】 2020.10.07 加入

game.hullqin.cn 我做了一些联机桌游网页:支持2-10人联机的UNO、2-4人联机的斗地主、2人联机的五子棋。无需下载,点开即玩!叫上朋友,即刻开局!不看广告,不做任务,享受「纯粹」的游戏!

评论

发布
暂无评论
[Go WebSocket] 多房间的聊天室(一)思考篇_Go_HullQin_InfoQ写作社区