当前位置: 首页 > Web前端 > HTML5

【GoWebSocket】多房间聊天室(二)代码实现

时间:2023-04-05 21:38:13 HTML5

我是公众号线下派对游戏的作者HullQin(欢迎关注公众号,发送加微信,交个朋友),之前转发本文由作者胡琴授权。我独立开发了《联机桌游合集》,这是一个网页,在这里你可以轻松地和朋友一起玩网络游戏,五子棋等游戏,不收费,也没有广告。还为GameJam2022开发了《Dice Crush》,喜欢的话可以关注我HullQin哦~有空我会分享制作游戏的相关技术。背景第一篇:《为什么我选用Go重构Python版本的WebSocket服务?》,介绍我的目标。第二篇文章:《你的第一个Go WebSocket服务: echo server》,介绍了如何编写WebSocket服务端。第三篇:《单房间的聊天室》,介绍如何实现单间聊天室。第四篇:《多房间的聊天室(一)思考篇》,介绍实现多房间聊天室的思路。今天我们实现一个多房间聊天室。如果你还没有读过上面的文章,你必须先阅读它,因为这篇文章比较复杂。如果以上文章看不懂,这篇文章可能跟不上节奏。场景回顾上一篇文章,有2个决策点:什么时候创建房间?如何决定客户端连接到哪个房间?上一篇文章提到了多种方案,都是可选的。但本文即将开始写代码实现,必须做出选择,选择如下:决策点1选择“方案2:动态创建房间”。对于决策点2,选择“选项1:在URL中指定”。这也是我的《在线桌游宝典》采用的方案。直接看chat-multi-rooms文件夹下的多房间聊天室案例代码源码地址:https://github.com/HullQin/go-websocket-examples,文章可以搭配commit记录读取:wshandler逻辑对应“URL指定房间号:路由参数”、“动态创建房间逻辑”。httphandler逻辑对应“修改http服务”。对于初始代码,我们以《单房间的聊天室》的代码为基础,进行改造。URL指定房间号:路由参数因为我们要在URL中指定房间号,怎么实现呢?我们可以使用gorilla/mux库,它可以实现强大的路由能力。Github介绍如下:packagegorilla/mux实现了一个请求路由器和调度器,用于将传入的请求匹配到它们各自的处理程序。安装依赖:gogetgithub.com/gorilla/mux我们把之前的代码改成:import("github.com/gorilla/mux")//...r:=mux.NewRouter()r.HandleFunc("/",serveHome)r.HandleFunc("/ws/{room}",func(whttp.ResponseWriter,r*http.Request){vars:=mux.Vars(r)roomId:=vars["room"]//...}err:=http.ListenAndServe(*addr,r)可以看到,我们在路中间添加了{room},这是一个动态参数,可以匹配字符串赋值给room。如何获取具体参数的值呢?通过vars:=mux.Vars(r)可以得到一个map,这个map的key是Parametername,value是参数的值,都是string类型。所以现在,我们已经从url中获取到了roomId,动态创建房间的逻辑不像是单间聊天室,我们需要在全局开启一个hubgoroutine,这个时候,我们必须动态添加hubgoroutine,我们应该怎么办做什么?我们需要有一个全局变量来存储所有的hub,可以使用map。每当有连接过来的时候,检查roomId是否存在,如果存在,则取对应的hub,如果不存在,则需要创建一个新的枢纽。在addr定义下方,创建一个新的house定义。varaddr=flag.String("addr","localhost:8080","httpserviceaddress")varhouse=make(map[string]*Hub)完成处理器逻辑。r.HandleFunc("/ws/{room}",func(whttp.ResponseWriter,r*http.Request){vars:=mux.Vars(r)roomId:=vars["room"]房间,ok:=house[roomId]varhub*Hubifok{hub=room}else{hub=newHub()house[roomId]=hubgohub.run()}serveWs(hub,w,r)})到目前为止,我们有完成更改后端逻辑!你相信吗?多亏了上一篇文章的优秀设计(hub设计成可扩展成多房间),单房间变多房间就这么简单!但这还没有结束。为了测试方便,我们还需要修改home.html。修改http服务home.html第32行代码如下:conn=newWebSocket("ws://"+document.location.host+"/ws"+document.location.pathname);即你的前端访问是localhost:8080/ha,你就会进入ha机房。当然你可以修改ha进入其他房间。先删除main.go中的这几行代码://ifr.URL.Path!="/"{//http.Error(w,"Notfound",http.StatusNotFound)//return//}因为我们之后访问的是localhost:8080/ha而不是localhost:8080/,所以r.URL.Path不能是/,否则会不知道房间号。此外,路由逻辑还适配房间号参数:r.HandleFunc("/{room}",serveHome)至此,大功告成!去测试一下!在浏览器中打开3个标签,分别访问http://localhost:8080/123、http://localhost:8080/123、http://localhost:8080/444。然后去发消息,会发现123房间互相广播消息,不会发到444房间;而且444房间的消息不会发到123房间!多房间聊天室,我们实现了!待优化的房间数量只会不断增加,房子的地图会越来越大,最终会导致内存不足。这不是一件好事。所以我们后面需要加一个优化:当最后一个客户端断开连接时,回收(删除)这个房间。最后,我是公众号线下派对游戏的作者HullQin(欢迎关注公众号,发送加微信,交友),转载本文需作者HullQin授权。我独立开发了《联机桌游合集》,这是一个网页,在这里你可以轻松地和朋友一起玩网络游戏,五子棋等游戏,不收费,也没有广告。还为GameJam2022开发了《Dice Crush》,喜欢的话可以关注我HullQin哦~有空我会分享制作游戏的相关技术。