gorilla/websocket
是一个非常流行的 Go 语言库,用于实现 WebSocket 协议的客户端和服务器端功能。它非常简洁且高效,支持多种高级功能,适合构建实时通信应用。下面我将详细讲解如何使用 gorilla/websocket
库,包含客户端和服务器端的使用方法、常见的差异,并提供基础和进阶教程。
基础使用
1. 安装 gorilla/websocket
首先需要安装 gorilla/websocket
库,可以使用 go get
命令来安装:
go get github.com/gorilla/websocket
2. 创建 WebSocket 服务器
WebSocket 服务器通常使用 http
包来处理客户端连接,gorilla/websocket
库提供了一个 Upgrader
类型来将 HTTP 请求升级为 WebSocket 连接。
WebSocket 服务器端示例
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
// 定义 WebSocket 升级器,用于将 HTTP 请求升级为 WebSocket 连接
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
// 允许任何来源的连接
return true
},
}
func handler(w http.ResponseWriter, r *http.Request) {
// 升级 HTTP 请求为 WebSocket 连接
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("升级失败:", err)
return
}
defer conn.Close()
// 处理客户端发送的消息
for {
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println("读取消息失败:", err)
break
}
// 打印收到的消息
fmt.Printf("收到消息: %s\n", p)
// 回应客户端的消息
err = conn.WriteMessage(messageType, p)
if err != nil {
log.Println("写入消息失败:", err)
break
}
}
}
func main() {
http.HandleFunc("/ws", handler) // 定义 WebSocket 路由
log.Println("服务器启动,监听端口 8080...")
log.Fatal(http.ListenAndServe(":8080", nil)) // 启动 HTTP 服务器
}
代码解析:
- 我们使用
http.HandleFunc
来定义一个处理/ws
路径的 WebSocket 请求。 upgrader.Upgrade
将 HTTP 请求升级为 WebSocket 连接。conn.ReadMessage
用于读取客户端发送的消息,conn.WriteMessage
用于发送消息给客户端。- 我们允许所有来源的连接,通过设置
CheckOrigin
为true
。
3. 创建 WebSocket 客户端
WebSocket 客户端通过 websocket.Dial
函数连接到服务器,并与服务器进行双向通信。
WebSocket 客户端示例
package main
import (
"fmt"
"log"
"github.com/gorilla/websocket"
)
func main() {
// 连接到 WebSocket 服务器
conn, _, err := websocket.DefaultDialer.Dial("ws://localhost:8080/ws", nil)
if err != nil {
log.Fatal("连接失败:", err)
}
defer conn.Close()
// 向服务器发送消息
message := []byte("Hello, WebSocket!")
err = conn.WriteMessage(websocket.TextMessage, message)
if err != nil {
log.Fatal("发送消息失败:", err)
}
// 接收服务器的消息
_, p, err := conn.ReadMessage()
if err != nil {
log.Fatal("读取消息失败:", err)
}
fmt.Printf("收到服务器的消息: %s\n", p)
}
代码解析:
- 使用
websocket.DefaultDialer.Dial
连接到 WebSocket 服务器。 - 发送消息通过
conn.WriteMessage
,类型为websocket.TextMessage
。 - 使用
conn.ReadMessage
来接收服务器的响应。
基础使用总结
- WebSocket 客户端通过
Dial
方法连接到服务器。 - 服务器端使用
Upgrader
升级 HTTP 请求为 WebSocket 连接。 - 客户端和服务器端都可以使用
ReadMessage
和WriteMessage
进行双向通信。
进阶使用
1. 异常处理与连接管理
在 WebSocket 应用中,我们通常需要处理连接中断和异常情况。例如,客户端或服务器端可能会断开连接,我们需要相应地清理资源和重新连接。
进阶 WebSocket 服务器端示例
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
"time"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func handler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("升级失败:", err)
return
}
defer conn.Close()
// 设置一个超时时间,连接 30 秒后关闭
conn.SetReadDeadline(time.Now().Add(30 * time.Second))
// 处理消息
for {
messageType, p, err := conn.ReadMessage()
if err != nil {
log.Println("连接错误或超时:", err)
break
}
fmt.Printf("收到消息: %s\n", p)
err = conn.WriteMessage(messageType, p)
if err != nil {
log.Println("写入消息失败:", err)
break
}
}
}
func main() {
http.HandleFunc("/ws", handler)
log.Println("服务器启动,监听端口 8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}
进阶部分:
conn.SetReadDeadline
设置一个读取超时时间,如果在 30 秒内没有读取到消息,连接将被关闭。- 当发生错误或连接断开时,我们会立即停止处理并释放连接资源。
2. 广播消息(群聊场景)
WebSocket 服务器可以通过广播将消息发送给所有连接的客户端。我们使用一个全局的连接池来管理每个连接。
广播服务器端示例
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
var clients = make(map[*websocket.Conn]bool) // 连接池
func handler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("升级失败:", err)
return
}
defer conn.Close()
clients[conn] = true
defer delete(clients, conn)
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("读取消息失败:", err)
break
}
// 广播消息
for client := range clients {
if err := client.WriteMessage(websocket.TextMessage, message); err != nil {
log.Println("发送广播消息失败:", err)
client.Close()
delete(clients, client)
}
}
}
}
func main() {
http.HandleFunc("/ws", handler)
log.Println("服务器启动,监听端口 8080...")
log.Fatal(http.ListenAndServe(":8080", nil))
}
代码解析:
clients
用来存储所有的 WebSocket 连接。- 当收到消息时,服务器会广播给所有已连接的客户端。
总结
- 客户端和服务器端的差异: 客户端通过
Dial
连接到 WebSocket 服务器,服务器端通过http
升级 HTTP 请求为 WebSocket 连接。 - 异常处理: WebSocket 连接可能会断开,需要及时处理。
- 进阶功能: 例如广播功能,可以让服务器向所有连接的客户端发送消息。
通过这些基础和进阶示例,你可以使用 gorilla/websocket
来构建可靠的实时 WebSocket 应用。