wordpress 网站静态,怎样做好网站,最近韩国免费观看视频,常见的网站空间有哪些文章目录 WebSocket 简介时序图核心逻辑Client 结构与功能创建新客户端消息读取逻辑 (ReadPump)发送消息逻辑 (Send)客户端管理器 (ClientManager)WebSocket 处理器处理心跳与长连接 总结 本文将基于 Go 语言#xff0c;通过使用 gorilla/websocket 库来实现一个简单的聊天应用… 文章目录 WebSocket 简介时序图核心逻辑Client 结构与功能创建新客户端消息读取逻辑 (ReadPump)发送消息逻辑 (Send)客户端管理器 (ClientManager)WebSocket 处理器处理心跳与长连接 总结 本文将基于 Go 语言通过使用 gorilla/websocket 库来实现一个简单的聊天应用。该应用具备处理 WebSocket 连接、消息传输、以及用户连接管理等功能。我们将详细展示如何实现这些功能并剖析背后的核心逻辑与原理。
WebSocket 简介
WebSocket 是一种全双工的通信协议允许客户端和服务器之间在一个持久连接上进行双向数据传输。与 HTTP 的短连接不同WebSocket 可以在建立连接后保持连接状态从而实现实时通信。因此WebSocket 非常适合用于聊天应用等需要实时数据传输的场景。
时序图 #mermaid-svg-7FhAQVR5Mkbwx4t6 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .error-icon{fill:#552222;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .marker.cross{stroke:#333333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7FhAQVR5Mkbwx4t6 text.actortspan{fill:black;stroke:none;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .actor-line{stroke:grey;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .sequenceNumber{fill:white;}#mermaid-svg-7FhAQVR5Mkbwx4t6 #sequencenumber{fill:#333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .messageText{fill:#333;stroke:#333;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .labelText,#mermaid-svg-7FhAQVR5Mkbwx4t6 .labelTexttspan{fill:black;stroke:none;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .loopText,#mermaid-svg-7FhAQVR5Mkbwx4t6 .loopTexttspan{fill:black;stroke:none;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-7FhAQVR5Mkbwx4t6 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .noteText,#mermaid-svg-7FhAQVR5Mkbwx4t6 .noteTexttspan{fill:black;stroke:none;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .actorPopupMenu{position:absolute;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-7FhAQVR5Mkbwx4t6 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7FhAQVR5Mkbwx4t6 .actor-man circle,#mermaid-svg-7FhAQVR5Mkbwx4t6 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-7FhAQVR5Mkbwx4t6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端 客户端管理器 WebSocket处理器 请求连接 新客户端加入 确认连接 连接成功 发送消息 消息路由 路由结果 消息送达 loop [消息读取] 发送心跳 响应Pong 客户端 客户端管理器 WebSocket处理器 核心逻辑
在本示例中我们主要实现了以下几个核心模块
Client表示单个 WebSocket 连接的客户端负责处理消息的收发。ClientManager用于管理多个客户端的连接处理客户端的增加、删除以及消息的路由。WebSocket 处理逻辑处理新连接的建立、消息的读取与发送。
Client 结构与功能
type Client struct {conn *websocket.ConnmessageQueue chan []bytemu sync.Mutexuser string
}Client 结构体用于表示一个 WebSocket 客户端连接。每个客户端包含
conn当前的 WebSocket 连接。messageQueue用于存储待发送的消息队列。mu用于保证并发安全的互斥锁。user表示客户端的用户标识。
创建新客户端
func NewClient(user string, conn *websocket.Conn) *Client {return Client{conn: conn,user: user,messageQueue: make(chan []byte, 100),}
}NewClient 函数用于创建新的客户端实例。每个客户端都有一个独立的消息队列用于存储要发送给客户端的消息。
消息读取逻辑 (ReadPump)
func (c *Client) ReadPump() {defer func() {c.conn.Close()}()for {mt, message, err : c.conn.ReadMessage()if err ! nil {log.Println(read:, err)manager.mu.Lock()delete(manager.clients, c.user)_ c.conn.Close()manager.mu.Unlock()break}if mt websocket.TextMessage || mt websocket.PingMessage {c.mu.Lock()c.messageQueue - messagec.mu.Unlock()}}
}ReadPump 方法用于持续从 WebSocket 连接中读取消息并将接收到的消息存储到 messageQueue 队列中。该方法通过一个无限循环不断读取 WebSocket 的消息。当出现错误时例如客户端断开连接便会关闭当前连接并将该客户端从客户端管理器中移除。
其中ReadMessage() 方法用于从 WebSocket 连接中读取消息返回的 mt 表示消息类型。常见的类型包括文本消息TextMessage和 ping 消息PingMessage。对于这些消息类型消息会被推送到 messageQueue 以便后续处理。
发送消息逻辑 (Send)
func Send(user string, returnMessage []byte, logger logx.Logger) {manager.mu.RLock()client, exists : manager.clients[user]manager.mu.RUnlock()if !exists {logger.Infof(client not found for user:%s message:%s, user, string(returnMessage))return}client.mu.Lock()err : client.conn.WriteMessage(websocket.TextMessage, returnMessage)client.mu.Unlock()if err ! nil {logger.Errorf(client.conn.WriteMessage error %s, err.Error())manager.mu.Lock()delete(manager.clients, user)manager.mu.Unlock()_ client.conn.Close()}
}Send 函数负责向指定的用户发送消息。首先它会检查用户是否存在于 ClientManager 中如果不存在则记录日志并返回。如果用户存在则通过 WriteMessage() 方法将消息发送给客户端。若发送消息时发生错误会将该用户从连接管理器中移除并关闭该 WebSocket 连接。
客户端管理器 (ClientManager)
type ClientManager struct {clients map[string]*Clientmu sync.RWMutex
}var manager ClientManager{clients: make(map[string]*Client),
}ClientManager 用于管理多个客户端的连接clients 字段是一个存储所有客户端连接的映射键是用户标识值是客户端对象。通过读写锁 (sync.RWMutex)确保在并发访问时的线程安全。
WebSocket 处理器
ChatWebsocketHandler 是处理 WebSocket 连接的 HTTP 处理函数。
func ChatWebsocketHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {conn, err : upgrader.Upgrade(w, r, nil)logger : logx.WithContext(r.Context())if err ! nil {logger.Errorf(upgrade:%v, err)return}user : r.URL.Query().Get(user)if user {logger.Errorf(user is empty:)_ conn.Close()return}client : NewClient(user, conn)manager.mu.Lock()oldClient, exists : manager.clients[user]if exists {_ oldClient.conn.Close()}manager.clients[user] clientmanager.mu.Unlock()go client.ReadPump()// 省略其他消息处理逻辑...}
}连接升级首先使用 upgrader.Upgrade() 将 HTTP 请求升级为 WebSocket 连接。用户认证通过 URL 查询参数获取用户 ID并创建对应的 Client。旧连接处理如果该用户已经有一个旧的 WebSocket 连接则会关闭旧连接。启动消息读取通过启动 ReadPump() 协程持续读取该用户的 WebSocket 消息。
处理心跳与长连接
在 WebSocket 通信中维持长连接的一个常用做法是使用心跳机制。
if req.Heartbeat {// 处理心跳消息err client.conn.WriteMessage(websocket.PongMessage, []byte())if err ! nil {logger.Errorf(write pong message failed:, err)manager.mu.Lock()delete(manager.clients, user)manager.mu.Unlock()_ client.conn.Close()return}
}每当接收到心跳消息时服务器会返回一个 PongMessage以维持连接的活跃状态。如果发送 PongMessage 失败服务器会关闭该客户端连接。
总结
本文详细展示了如何使用 Go 语言实现一个 WebSocket 聊天应用的核心逻辑。我们讨论了客户端的创建与管理、消息的收发、以及长连接的维持等关键功能。通过这些核心组件我们可以轻松地扩展功能构建复杂的 WebSocket 应用。
WebSocket 实现的关键在于良好的连接管理和消息处理机制这样可以确保在高并发情况下仍然能维持高效且稳定的实时通信。