这是我参与「第五届青训营 」伴学笔记创作活动的第 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.