GO websocket聊天室设计思路| 青训营笔记

151 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天

青训营的聊天模块有两个解决方案,一个是websocket,另一个是http轮询.

为什么要有websocket? http有什么不足?

: http的服务端不能主动向客户端发送请求,而聊天时A向B发消息首先存储在服务器的数据库里,服务端不能主动向B发送新消息,只能由B轮询发送"是否有新消息?"的请求来获取.websocket就是来赋予服务端主动发送消息能力的协议.

websocket是怎么实现主动能力的?

: websocket就是来赋予服务端主动发送消息能力的协议. websocket的最开始建立连接也是借助http的三次握手,但在建立连接之后,消息的传送就直接使用了tcp报文进行双工传输.建立一个socket连接之后,服务端可以主动向客户端发消息,本质上,服务端和客户端是平等的关系.

Go 语言中gin框架下如何使用websocket?

: 首先,官方提供的websocket不能直接使用在gin框架里,要使用gollira的websocket.代码如下.在gin框架下注册一个路由端口,在回调函数中把context变量c传递给websocket进行连接的升级.

	conn, err := (&websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool { // CheckOrigin解决跨域问题
		return true
	}}).Upgrade(c.Writer, c.Request, nil) // 升级成ws协议

客户端和服务端都是平等的,读数据就用:

err := c.Socket.ReadJSON(&sendMsg) // json格式就用这个

_,msg,_:=c.Socket.ReadMessage() // 不是json格式用这个

写数据就用:

	msg , _ := json.Marshal(replyMsg)
	_ = c.Socket.WriteMessage(websocket.TextMessage,msg)

如何设计websocket聊天室呢?

:

  • 需要自己维护一个管理中心,集中管理所有的socket连接.开一个goroutine监听各种信号来实现.
  • 至少需要两种消息格式: S2C(server to client) 和 C2S(client to server)
  • 业务逻辑是:
    • 当客户端首次连接服务端时,将未读消息和再之前的10条历史消息(S2C)从服务端发送到客户端;
    • 当客户A向客户B发送消息的时候,消息先发送到服务端(C2S),记录在数据库中,在管理中心中查找对方的socket连接是否存在:
      • 如果存在,就向A回复"对方在线",数据库中的"已读"置1(S2C),直接将消息发送到对方的socket中(S2C).
      • 如果不存在,就向A回复"对方离线"(S2C),数据库中的"已读"置0.