昨天將前端的部分寫好了,今天就讓我們將 Server 的部分處理好,建立一個公開的匿名聊天室吧!
今天的範例主要是要修改昨天所寫的 main.go
,這邊我先將昨天的範例寫出來。
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("template/html/*")
r.Static("/assets", "./template/assets")
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
r.Run(":5000")
}
本次的範例 WebSocket
Server 的部分主要透過 melody
來處理。
melody 是基於由 gorilla
推出的 websocket package 所封裝,透過封裝好的簡易方法就可以體驗到 WebSocket 的強大功能。
使用 go get
的指令進行安裝。
go get gopkg.in/olahol/melody.v1
本次也會利用 gin
來實作 server,因此也需要進行安裝。
go get github.com/gin-gonic/gin
使用 melody
前首先要先建立好相關的物件。
m := melody.New()
接著我們使用 gin
來處理 routing,透過 melody
來處理連線的 request
。
r.GET("/ws", func(c *gin.Context) {
m.HandleRequest(c.Writer, c.Request)
})
這樣就可以完成握手協定
拉,是的,使用 melody
就是可以這麼簡單的完成 websocket
的連線!
因為連線與離線訊息我們都要透過傳送 message
的方式通知 client
端,因此我們要先設定訊息物件與相關方法
訊息物件會有三個屬性
NewMessage
方法建立 Message
物件type Message struct {
Event string `json:"event"`
Name string `json:"name"`
Content string `json:"content"`
}
func NewMessage(event, name, content string) *Message {
return &Message{
Event: event,
Name: name,
Content: content,
}
}
由於透過 WebSocket 傳送訊息要使用 []byte
格式,因此這邊我們也將轉換的方法進行封裝
func (m *Message) GetByteMessage() []byte {
result, _ := json.Marshal(m)
return result
}
melody 有提供 HandleConnect
方法讓我們處理連線的 session
,我們這邊設定連線進來就發送一個 xxx 加入聊天室
的訊息給全部人
m.HandleConnect(func(session *melody.Session) {
id := session.Request.URL.Query().Get("id")
m.Broadcast(NewMessage("other", id, "加入聊天室").GetByteMessage())
})
melody 有提供 HandleClose
方法讓我們處理離線的 session
,我們這邊設定離線就發送一個 xxx 離開聊天室
的訊息給全部人
m.HandleClose(func(session *melody.Session, i int, s string) error {
id := session.Request.URL.Query().Get("id")
m.Broadcast(NewMessage("other", id, "離開聊天室").GetByteMessage())
return nil
})
完成連線與離線處理後,我們接著要處理由 client
傳送上來的 message
,這邊也透過由 melody
提供的 HandleMessage
來處理傳入的訊息,因為我們是公開的聊天室,所以透過 Broadcast
將所有連線的 client
發送傳入的訊息。
m.HandleMessage(func(s *melody.Session, msg []byte) {
m.Broadcast(msg)
})
目前 main.go
的整體程式如下
package main
import (
"encoding/json"
"github.com/gin-gonic/gin"
"gopkg.in/olahol/melody.v1"
"net/http"
)
type Message struct {
Event string `json:"event"`
Name string `json:"name"`
Content string `json:"content"`
}
func NewMessage(event, name, content string) *Message {
return &Message{
Event: event,
Name: name,
Content: content,
}
}
func (m *Message) GetByteMessage() []byte {
result, _ := json.Marshal(m)
return result
}
func main() {
r := gin.Default()
r.LoadHTMLGlob("template/html/*")
r.Static("/assets", "./template/assets")
r.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", nil)
})
m := melody.New()
r.GET("/ws", func(c *gin.Context) {
m.HandleRequest(c.Writer, c.Request)
})
m.HandleMessage(func(s *melody.Session, msg []byte) {
m.Broadcast(msg)
})
m.HandleConnect(func(session *melody.Session) {
id := session.Request.URL.Query().Get("id")
m.Broadcast(NewMessage("other", id, "加入聊天室").GetByteMessage())
})
m.HandleClose(func(session *melody.Session, i int, s string) error {
id := session.Request.URL.Query().Get("id")
m.Broadcast(NewMessage("other", id, "離開聊天室").GetByteMessage())
return nil
})
r.Run(":5000")
}
我們透過瀏覽器開啟兩個分頁,分別都連上 http://127.0.0.1:5000
這個網址,第二個分頁要可以看到
第一個分頁要可以看到
如果可以看到以上畫面就代表已經完成了連線測試!
連線測試完成後,我們接著測試訊息傳送的功能,分別在分頁1與分頁2 輸入訊息 按下 Enter
後,應該可以看到以下畫面
切換至分頁2 應該可以看到以下畫面
這邊可以交互測試,就可以體驗到 WebSocket 即時通訊的強大之處了!
最後我們來測試看看離線會有什麼效果,先將分頁2關閉,如果分頁1的畫面如下就代表離線測試通過拉!
[備註]一開始沒有存到圖,所以重開一次來測試QQ
通過這兩天簡單的實作後,發現要做一個基本的聊天室不難,但是要了解 WebSocket 的機制已經整體的生命週期,希望這次的分享有幫助到大家,謝謝!
專案範例我放在這裡