当前位置: 首页 > news >正文

Go 即时通讯体系:客户端与服务端 WebSocket 通信交互

客户端和服务端的交互

客户端与服务端建立连接

// router/socket.go
func RunSocket(c *gin.Context) {
user := c.Query("user"
) // 获取用户标识
if user == "" {
return // 无用户标识则拒绝连接
}
log.Info("newUser"
, log.String("newUser"
, user)
)
// 升级 HTTP 连接为 WebSocket 连接
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil
)
if err != nil {
return
}
// 创建客户端对象
client := &server.Client{
Name: user,
Conn: ws,
Send: make(
chan []byte
)
,
}
// 注册客户端到服务器
server.MyServer.Register <- client
// 启动读写协程
go client.Read(
)
go client.Write(
)
}
  • 服务端:服务端接收到请求后,使用 websocket.Upgrader 将 HTTP 连接升级为 WebSocket 连接。然后创建一个 Client 实例,并将其发送到 ServerRegister 通道。

客户端注册到服务端

// internal/server/server.go
func (s *Server) Start(
) {
for {
select {
// 处理客户端注册
case conn := <-s.Register:
log.Info("login"
, log.String("login"
, conn.Name)
)
s.Clients[conn.Name] = conn
msg := &protocol.Message{
From: "System"
,
To: conn.Name,
Content: "welcome!"
,
}
protoMsg, _ := proto.Marshal(msg) // 序列化为字节切片
conn.Send <- protoMsg
}
}
}
  • 客户端:无特定操作,等待服务端响应。
  • 服务端:服务端的 Start 方法会监听 Register 通道,当有新的客户端注册时,将客户端信息保存到 Clients 映射中,并向客户端发送欢迎消息。

客户端发送消息到服务端

// internal/server/client.go
func (c *Client) Read(
) {
// 消息读取
for {
c.Conn.PongHandler(
)
_
, message, err := c.Conn.ReadMessage(
)
if err != nil {
log.Error("client read message error"
, log.Err(err)
)
MyServer.Ungister <- c
c.Conn.Close(
)
break
}
msg := &protocol.Message{
}
proto.Unmarshal(message, msg)
// 处理心跳消息
if msg.Type == constant.HEAT_BEAT {
pong := &protocol.Message{
Content: constant.PONG,
Type: constant.HEAT_BEAT,
}
pongBytes, err2 := proto.Marshal(pong)
if err2 != nil {
log.Error("client marshal message error"
, log.Err(err)
)
}
c.Conn.WriteMessage(websocket.BinaryMessage, pongBytes)
}
else {
MyServer.Broadcast <- message
}
}
}
  • 服务端:服务端的 Start 方法会监听 Broadcast 通道,当接收到消息时,根据消息的类型(单聊、群聊)将消息转发给相应的客户端。
// internal/server/server.go
func (s *Server) Start(
) {
for {
select {
// 处理消息广播
case message := <-s.Broadcast:
msg := &protocol.Message{
}
proto.Unmarshal(message, msg)
if msg.To != "" {
// 有指定接收者的消息处理
if msg.ContentType >= constant.TEXT && msg.ContentType <= constant.VIDEO {
// 一般消息,比如文本消息,视频文件消息等
_
, exists := s.Clients[msg.From]
if exists {
// 检查发送者是否在连接列表中
saveMessage(msg)
}
if msg.ContentType == constant.MESSAGE_TYPE_USER {
// 单人消息处理
s.sendUserMessage(msg)
}
else
if msg.ContentType == constant.MESSAGE_TYPE_GROUP {
// 多人消息处理
s.sendGroupMessage(msg)
}
else {
// 语音电话,视频电话等,仅支持单人聊天,不支持群聊
// 不保存文件,直接进行转发
client, ok := s.Clients[msg.To]
if ok {
client.Send <- message
}
}
}
else {
// 无指定接收者的广播消息处理
for id, conn :=
range s.Clients {
log.Info("allUser"
, log.String("allUser"
, id)
)
select {
case conn.Send <- message: // 发送消息给客户端,成功继续处理
default: // 失败关闭客户端
close(conn.Send)
delete(s.Clients, conn.Name)
}
}
}
}
}
}
}

服务端发送消息到客户端

// internal/server/server.go
client.Send <- msgByte
client.Send <- message
  • 客户端:客户端的 Write 方法会监听 Send 通道,当接收到消息时,将消息通过 WebSocket 连接发送给客户端。
// internal/server/client.go
func (c *Client) Write(
) {
defer
func(
) {
c.Conn.Close(
)
}(
)
for message :=
range c.Send {
c.Conn.WriteMessage(websocket.BinaryMessage, message)
}
}

客户端断开连接

// internal/server/server.go
func (s *Server) Start(
) {
for {
// 处理客户端注销
case conn := <-s.Ungister:
log.Info("loginout"
, log.String("loginout"
, conn.Name)
)
if _
, ok := s.Clients[conn.Name]
; ok {
close(conn.Send)
delete(s.Clients, conn.Name)
}
}
}

客户端和服务端通过 WebSocket 连接进行实时通信,通过 RegisterUngisterBroadcast 通道进行客户端的注册、注销和消息广播,通过客户端的 Send 通道进行消息的发送。整个交互过程基于 Go 语言的协程和通道机制,实现了高效、并发的通信。

代码地址:server.go,client.go

言的协程和通道机制,实现了高效、并发的通信。

代码地址:server.go,client.go

http://www.jsqmd.com/news/8886/

相关文章:

  • 2025 年储罐厂家推荐最新公司权威排行榜榜单发布,深度解析衬四氟储罐 / 硫酸储罐 / 盐酸储罐工厂选购指南
  • 读混元image论文
  • 实用指南:跳动的爱心
  • UnicodeEncodeError: locale codec cant encode character \u5e74 in position 2: encoding error
  • 2025 年生物除臭设备厂家最新推荐排行榜:覆盖污水处理厂 / 垃圾中转站等多场景,助力企业精准挑选优质设备
  • 从理念到沙盘:用悟空博弈模拟器点亮人机共治的曙光
  • 深入解析:Redis事务详解:原理、使用与注意事项
  • phone num
  • Perplexity发布搜索API,驱动下一代AI应用开发
  • PWN手的成长之路-09-SWPUCTF 2023 秋季新生赛Shellcode
  • 20251005 总结
  • OKR1
  • 云数据库选型指南:关系型 vs NoSQL vs NewSQL的企业决策 - 指南
  • 详细介绍:AI觉醒前兆,ChatGPT o3模型存在抗拒关闭行为
  • 当 Python 遇上 Go:Sponge 如何成为替代 Django/Flask 的理想选择 - 指南
  • 2025 年装盒机制造厂 TOP 企业品牌推荐排行榜,自动化 / 喷胶 / 牙膏 / 手机壳 / 3C 数码 / 内外盒 / 面膜 / 电子产品 / 玩具 / 日用品装盒机推荐这十家公司!
  • 英语_阅读_Chinas Spring Festival_待读
  • 2025 年自动包装生产线 TOP 企业品牌推荐排行榜!食品行业 / 日化产品 / 智能化 / 小型 / 多功能集成 / 柔性 / 后道 / 高速自动包装生产线推荐!
  • api调用钉钉群机器人发信息 - 规格严格
  • AI 自我理解边界
  • 2025 年氢氧化铝生产厂家 TOP 品牌榜单来袭,阻燃,高白,酸融,导热,超细,微粉级,低粘度,灌封胶用,覆铜板用氢氧化铝公司推荐!
  • 飞算 JavaAI 赋能老工程重构:破旧立新的高效利器
  • 2025钢球厂家最新企业品牌推荐排行榜,轴承钢球,不锈钢球,碳钢球,精密钢球,440C不锈钢球推荐这十家公司!
  • 2025 年工业提升门厂家最新企业品牌推荐排行榜,汇峰节能科技彰显行业影响力!
  • 什么是偏微分方程?
  • 2025 权威推荐!电梯源头品牌 TOP5 排行榜:实力厂家精选,品质之选不容错过
  • 钉钉红包性能优化之路 - 实践
  • SQLite详细解读 - 实践
  • IIS反向代理tomcat
  • 2025混合机厂家最新企业品牌推荐排行榜,高效盘条式混合机,无重力混合机,犁刀式混合机,锥形混合机,卧式螺带混合机推荐这十家公司!