對於Web開發,Gin是一種非常出色的go語言框架,因為它具有出色的速度和抽象性。GinWebSocket是Gin框架的WebSocket包,允許在Gin中創建WebSocket端點。WebSocket是一種網路協議,它允許在客戶端和伺服器之間進行雙向通信,並且非常適合需要實時通信的應用程序。
一、快速入門
在gin中的WebSocket處理過程中,要引入github.com/gin-gonic/gin、github.com/gin-gonic/gin/binding、github.com/gorilla/websocket這三個包。通過對這些包的導入,我們可以輕鬆地在網站上實現WebSocket。
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/gorilla/websocket"
)
//此處使用默認Engine
var upGrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func Websocket(c *gin.Context) {
conn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
fmt.Println(err)
return
}
}
上述代碼主要用於處理來自客戶端的請求,首先使用 gin.Context 來獲得 http.ResponseWriter 和 *http.Request,這些內容將用於WebSocket握手。
接下來,我們使用 gorilla/websocket 中的Upgrader類型來創建WebSocket連接並從其中獲取來自客戶端的消息和斷開連接請求。
二、創建Websocket客戶端
在Gin中,我們可以通過在瀏覽器中使用Javascript中的WebSocket對象來創建WebSocket客戶端。
function connect() {
var socket = new WebSocket('ws://127.0.0.1:8080/ws');
socket.onmessage = function (msg) {
console.log('Received message from server: ' + msg.data);
};
socket.onerror = function (error) {
console.error('WebSocket error: ' + error);
};
socket.onclose = function () {
console.log('WebSocket connection closed');
};
socket.onopen = function (event) {
// Send an initial message
socket.send('I am the client and I'm listening!');
};
}
connect();
在上面的示例代碼中,我們可以看到如何使用Javascript來連接到WebSocket伺服器。瀏覽器使用WebSocket對象並傳遞要連接的伺服器的地址,然後通過調用onopen、onmessage、onerror和onclose函數進行初始設置。
三、WebSocket中間件
GinWebSocket允許您使用WebSocket中間件針對使用WebSocket的請求提供通用處理程序。在使用WebSocket中間件時,將在WebSocket處理程序中自動注入WebsocketContext。
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello world!",
})
})
r.Use(WebsocketMiddleware())
r.GET("/websocket", WebsocketHandler)
r.Run(":8080")
}
func WebsocketMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
conn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
http.NotFound(c.Writer, c.Request)
return
}
wc := &WebsocketContext{conn}
c.Set("ws", wc)
err = c.Next()
if err != nil {
wc.Close()
}
}
}
在上面的示例代碼中,我們使用WebsocketMiddleware在請求進入WebSocket處理程序之前對其進行處理。然後我們使用Set方法設置一個WebSocket上下文,以便在WebsocketHandler中訪問該上下文。
四、廣播
在許多場景中,您可能希望將消息廣播給多個WebSocket客戶端。使用 ginWebSocket,我們可以輕鬆地實現這一點。
var clients = make(map[*websocket.Conn]bool) // connected clients
var broadcast = make(chan Message) // broadcast channel
type Message struct {
Message string `json:"message"`
}
func main() {
r := gin.Default()
r.Use(WebsocketMiddleware())
r.GET("/ws", WebsocketHandler)
go handleMessages()
r.Run(":8080")
}
func handleMessages() {
for {
// Grab the next message from the broadcast channel
msg := <-broadcast
// Send it out to every client that is currently connected
for client := range clients {
err := client.WriteJSON(msg)
if err != nil {
log.Printf("error: %v", err)
client.Close()
delete(clients, client)
}
}
}
}
func WebsocketHandler(c *gin.Context) {
conn, _ := upGrader.Upgrade(c.Writer, c.Request, nil)
clients[conn] = true
for {
var msg Message
err := conn.ReadJSON(&msg)
if err != nil {
log.Printf("error: %v", err)
delete(clients, conn)
break
}
broadcast <- msg
}
}
在上面的示例代碼中,我們使用一個全局 map 變數 clients 來存儲客戶端連接,並且通過一個廣播通道 broadcast 進行消息廣播。
在WebsocketHandler中,我們使用 ReadJSON 方法從連接中讀取消息,並將該消息發送到廣播通道中;在handleMessages中,我們使用 range 語句循環所有連接並將消息發回給它們所有人。
五、多線程中協同工作
對於更大的應用程序,我們可能希望使用多個goroutine來處理WebSocket鏈接。當多個goroutine同時處理WebSocket請求時,我們需要確保它們之間通信的正確性。在這些情況下,可以使用goroutine-safe通道來確保正常的協同工作。
var clients = make(map[*websocket.Conn]bool) // connected clients
var broadcast = make(chan Message) // broadcast channel
type Message struct {
Message string `json:"message"`
}
func main() {
r := gin.Default()
r.Use(WebsocketMiddleware())
r.GET("/ws", WebsocketHandler)
go handleMessages()
r.Run(":8080")
}
func handleMessages() {
for {
// Grab the next message from the broadcast channel
msg := <-broadcast
// Send it out to every client that is currently connected
for client := range clients {
err := client.WriteJSON(msg)
if err != nil {
log.Printf("error: %v", err)
client.Close()
delete(clients, client)
}
}
}
}
func WebsocketHandler(c *gin.Context) {
conn, _ := upGrader.Upgrade(c.Writer, c.Request, nil)
clients[conn] = true
go func() {
for {
var msg Message
err := conn.ReadJSON(&msg)
if err != nil {
log.Printf("error: %v", err)
broadcast <- Message{Message: "A client has disconnected."}
delete(clients, conn)
return
}
msg.Message = fmt.Sprintf("Message received from %v: %v", conn.RemoteAddr(), msg.Message)
broadcast <- msg
}
}()
}
在上面的示例代碼中,我們使用一個goroutine來處理conn.ReadJSON(),並在goroutine-safe通道中發送讀取的消息。這是為了確保多個線程同時處理WebSocket請求時可以進行正確的協調和通信。
總結
通過這篇文章,您應該已經能夠了解如何在 Gin 中使用 ginWebSocket。您還可以使用 ginWebSocket 提供的一些其他功能,例如在應用程序中使用更高效的二進位消息,以便更快地發送和接收大量數據。同時,在代碼設計過程中一定要注意線程安全問題,保證多個goroutine之間的正確協作。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/151021.html
微信掃一掃
支付寶掃一掃