客戶端連接中斷通過監(jiān)聽r.context().done()實(shí)現(xiàn),當(dāng)通道關(guān)閉時(shí)停止發(fā)送數(shù)據(jù)并釋放資源。代碼中使用goroutine監(jiān)聽該通道,一旦客戶端斷開連接,即輸出日志并退出循環(huán),從而避免無效的數(shù)據(jù)發(fā)送和資源浪費(fèi)。
使用go語言構(gòu)建服務(wù)器發(fā)送事件(SSE)服務(wù)器,關(guān)鍵在于利用Go的并發(fā)特性和標(biāo)準(zhǔn)庫中的net/http包,實(shí)現(xiàn)高效、實(shí)時(shí)的事件推送。這不僅能讓你快速構(gòu)建原型,還能深入理解SSE協(xié)議的底層運(yùn)作機(jī)制。
package main import ( "fmt" "log" "net/http" "time" ) func sseHandler(w http.ResponseWriter, r *http.Request) { // 設(shè)置響應(yīng)頭,關(guān)鍵在于Content-Type w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") // 創(chuàng)建一個(gè)通道,用于發(fā)送數(shù)據(jù) messageChan := make(chan string) // 啟動(dòng)一個(gè)goroutine,模擬數(shù)據(jù)源 go func() { defer close(messageChan) ticker := time.NewTicker(2 * time.Second) defer ticker.Stop() for range ticker.C { messageChan <- fmt.Sprintf("當(dāng)前時(shí)間:%s", time.Now().Format(time.RFC3339)) } }() // 監(jiān)聽客戶端斷開連接 notify := r.Context().Done() go func() { <-notify log.Println("客戶端已斷開連接") return }() // 循環(huán)發(fā)送數(shù)據(jù) for msg := range messageChan { fmt.Fprintf(w, "data: %snn", msg) // 強(qiáng)制刷新緩沖區(qū),確保數(shù)據(jù)立即發(fā)送 flusher, ok := w.(http.Flusher) if ok { flusher.Flush() } } log.Println("SSE 完成") } func main() { http.HandleFunc("/events", sseHandler) log.Println("SSE服務(wù)器已啟動(dòng),監(jiān)聽端口:8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
如何處理客戶端連接中斷?
服務(wù)器端需要監(jiān)聽客戶端的連接狀態(tài),一旦檢測(cè)到連接中斷,就應(yīng)該停止發(fā)送數(shù)據(jù),釋放資源。上面的代碼示例中,r.Context().Done() 就是用來監(jiān)聽客戶端連接中斷的。當(dāng)客戶端斷開連接時(shí),該通道會(huì)被關(guān)閉,goroutine 就會(huì)退出。如果沒有這個(gè)機(jī)制,服務(wù)器可能會(huì)持續(xù)嘗試向已經(jīng)斷開的連接發(fā)送數(shù)據(jù),導(dǎo)致資源浪費(fèi)甚至錯(cuò)誤。
立即學(xué)習(xí)“go語言免費(fèi)學(xué)習(xí)筆記(深入)”;
SSE與websocket相比,有哪些優(yōu)缺點(diǎn)?
SSE是單向通信協(xié)議,服務(wù)器向客戶端推送數(shù)據(jù)。WebSocket是雙向通信協(xié)議,客戶端和服務(wù)器可以互相發(fā)送數(shù)據(jù)。
- SSE優(yōu)點(diǎn): 簡(jiǎn)單易用,基于HTTP協(xié)議,無需額外的握手協(xié)議,服務(wù)器實(shí)現(xiàn)起來更簡(jiǎn)單。對(duì)只需要服務(wù)器向客戶端推送數(shù)據(jù)的場(chǎng)景,效率更高。
- SSE缺點(diǎn): 只能服務(wù)器向客戶端推送數(shù)據(jù),不支持客戶端向服務(wù)器發(fā)送數(shù)據(jù)。瀏覽器支持度不如WebSocket。
- WebSocket優(yōu)點(diǎn): 雙向通信,實(shí)時(shí)性更好,瀏覽器支持度高。
- WebSocket缺點(diǎn): 實(shí)現(xiàn)相對(duì)復(fù)雜,需要處理連接的建立、維護(hù)和關(guān)閉。
選擇哪種協(xié)議取決于具體的應(yīng)用場(chǎng)景。如果只需要服務(wù)器向客戶端推送數(shù)據(jù),SSE是一個(gè)不錯(cuò)的選擇。如果需要雙向通信,WebSocket更合適。
如何優(yōu)化SSE服務(wù)器的性能?
- 使用連接池: 避免頻繁創(chuàng)建和銷毀連接,使用連接池可以提高性能。
- 使用緩沖區(qū): 將多個(gè)事件合并成一個(gè)消息發(fā)送,減少網(wǎng)絡(luò)傳輸?shù)拇螖?shù)。
- 啟用Gzip壓縮: 減少數(shù)據(jù)傳輸量,提高傳輸速度。
- 使用CDN: 將SSE服務(wù)器部署到CDN上,可以提高訪問速度,降低服務(wù)器負(fù)載。
- 監(jiān)控服務(wù)器性能: 定期監(jiān)控服務(wù)器的CPU、內(nèi)存、網(wǎng)絡(luò)等指標(biāo),及時(shí)發(fā)現(xiàn)和解決性能問題。
SSE在哪些場(chǎng)景下比較適用?
- 實(shí)時(shí)更新: 股票行情、體育賽事直播、新聞推送等。
- 服務(wù)器監(jiān)控: 實(shí)時(shí)顯示服務(wù)器的CPU、內(nèi)存、網(wǎng)絡(luò)等指標(biāo)。
- 消息通知: 向客戶端推送消息通知,例如:郵件提醒、訂單狀態(tài)更新等。
- 日志流: 將服務(wù)器的日志實(shí)時(shí)推送到客戶端,方便開發(fā)人員調(diào)試和監(jiān)控。
- 在線游戲: 實(shí)時(shí)更新游戲狀態(tài),例如:玩家位置、血量等。