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

news/2025/10/5 20:33:43/文章来源:https://www.cnblogs.com/yxysuanfa/p/19127025

客户端和服务端的交互

客户端与服务端建立连接

// 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.mzph.cn/news/928706.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站开发持续更新wordpress广告设置

大数据开发&#xff08;Hadoop面试真题&#xff09; 1、Hive count(distinct)有几个reduce&#xff0c;海量数据会有什么问题&#xff1f;2、既然HBase底层数据是存储在HDFS上&#xff0c;为什么不直接使用HDFS&#xff0c;而还要用HBase?3、Spark map join的实现原理&#xf…

2025 年储罐厂家推荐最新公司权威排行榜榜单发布,深度解析衬四氟储罐 / 硫酸储罐 / 盐酸储罐工厂选购指南

引言在当今工业领域,储罐作为储存各类液体、气体等物质的关键设备,其重要性不言而喻。从化工行业储存具有强腐蚀性的原料,到食品行业对卫生安全要求极高的产品储存,再到环保领域对污水、废气处理过程中的暂存需求等…

读混元image论文

读混元image论文https://www.yiyibooks.cn/arxiv/2509.23951v1/index.html

实用指南:跳动的爱心

实用指南:跳动的爱心2025-10-05 20:24 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-…

UnicodeEncodeError: locale codec cant encode character \u5e74 in position 2: encoding error

s= datetime.now().strftime(u"%Y年%m月%d日 %H:%M:%S" )UnicodeEncodeError: locale codec cant encode character \u5e74 in position 2: encoding error可行方案: import localefrom datetime import da…

2025 年生物除臭设备厂家最新推荐排行榜:覆盖污水处理厂 / 垃圾中转站等多场景,助力企业精准挑选优质设备

当前,恶臭污染在工业生产与城市生活中愈发凸显,污水处理厂、垃圾中转站、餐厨垃圾处理场等场所产生的恶臭气体,不仅影响周边居民生活,还危害人体健康,且随着环保标准不断提高,企业对高效环保除臭设备的需求极为迫…

杭州网站设计成功柚v米科技wordpress加载图片的速度

文章目录1. 题目2. 解题1. 题目 亚历克斯和李继续他们的石子游戏。许多堆石子 排成一行&#xff0c;每堆都有正整数颗石子 piles[i]。游戏以谁手中的石子最多来决出胜负。 亚历克斯和李轮流进行&#xff0c;亚历克斯先开始。最初&#xff0c;M 1。 在每个玩家的回合中&…

YOLO模型部署

一、环境搭建 第一步 显卡驱动查看 WIN+R键 进入命令终端 输入 nvidia-smi如果没有CUDA和CUDNN请自行安装,这里不再赘述 第二步 安装Anaconda 网站直接进行下载,这里不再进行安装教程 https://www.anaconda.com/down…

咸阳营销型网站开发北京制作网站主页

发布在linux上的机器,一般我们需要监测各项数据来证实服务器是没问题的, 如果出现问题,我们也可以通过以下指标找到问题的方向 容器指标硬件指标磁盘指标系统指标网络指标 容器指标 线程数 -当前容器内线程总数&#xff08;平均到每个核的线程数&#xff09;进程数 -当前容器…

从理念到沙盘:用悟空博弈模拟器点亮人机共治的曙光

从理念到沙盘:用"悟空博弈模拟器"点亮人机共治的曙光 当"AI元人文"的宏大构想遇上现实的算力壁垒,我们不必等待遥远的硬件革命。一条更智慧的道路已经显现:将其中最精妙的"悟空博弈"…

深入解析:Redis事务详解:原理、使用与注意事项

深入解析:Redis事务详解:原理、使用与注意事项pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", …

phone num

11马金金:15036063732 王梦梦:13949689021 樊兆航:15643637365 齐要夺:13462856861 贺 坤:19939188933 赵 琎:13569184695 王 磊:13839152769 靳斌斌:13673918231 千 军:13569114940 吴庆杰:13603891396…

Perplexity发布搜索API,驱动下一代AI应用开发

Perplexity推出搜索API,开放其公共问答引擎的基础架构,为开发者提供实时可靠的搜索结果,支持构建AI代理、应用程序和检索增强管道,具有实时更新和高效处理能力。Perplexity推出了搜索API,开放了支撑其公共问答引擎…

DNF做钓鱼网站广州网站建设程序员培训

前言 前段时间朋友拿了个网站给我&#xff0c;让我帮忙添加几个小功能&#xff0c;我爽快的答应了,但是当我打开源码&#xff0c;我瞬间就奔溃了&#xff0c;整个项目连最基本的三层框架也没有搭建&#xff0c;仅仅是封装了一个sqlhelp作为数据库的操作接口&#xff0c;项目中的…

毕业设计代做网站推荐重庆模板网站建设

原标题&#xff1a;[原创]简单介绍光缆终端盒知识光缆终端盒又叫光纤终端盒&#xff0c;很多工程商也叫光缆盘纤盒&#xff0c;是在光缆敷设的终端保护光缆和尾纤熔接的盒子&#xff0c;主要用于室内外光缆的直通熔接和分支接续及光缆终端的固定&#xff0c;起到尾纤盘储和保护…

建设商业门户网站的重要企业微信公众号怎么创建

DataGridView的下拉DataGridViewComboBoxColumn的数据绑定问题 需求&#xff1a;左边这列固定x行&#xff0c;右边显示下拉&#xff0c;并且赋上默认值 public void Set(){// 添加需要固定显示的行数dataGridView1.Rows.Add("早班";dataGridView1.Rows.Add("中…

PWN手的成长之路-09-SWPUCTF 2023 秋季新生赛Shellcode

远程连接环境。没什么有效信息,只是提示我们这道题会用到 shellcode。file 查看文件。64 位可执行 ELF 文件。checksec 查看文件安全属性。有了栈溢出保护,以及 PIE 保护IDA 打开文件,尝试反编译,但是失败了。直接…

OKR1

P1 学了一些关于计数问题的 DP 状态设计及转移方式,比如连续段 DP,贡献提前计算。 对于排列问题得到两个小点,一是考虑顺序插入,二是 P2 做题第一天模拟赛第二题接触到了连续段 DP。 permutation oddness 和 摩天大…