對於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