這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
這個應用示範如何使用 Google Go 語言和 HTML5 的 WebSocket 來實現一個簡單的基於 Web 的聊天程式。
是聊天應用的:
你可輸入 email 來加入聊天室,我們將從 Gravatar 上擷取對應的使用者名稱和頭像,當你正在聊天時,你能在介面右側看到聊天室其他人的姓名和頭像。你可以輸入資訊來跟他們聊天。
現在,讓我們來看看如何?這麼一個程式。
伺服器端
首先我們需要一個名為 ActiveRoom 聊天室引擎作為整個應用的核心。該引擎將在下面的代碼中定義,當程式主函數啟動時將會初始化一個聊天室引擎執行個體並作為一個全域變數。
正在啟動並執行執行個體用於維護所有 websocket 串連並處理收到的訊息。一旦通過廣播渠道接收到一個新的訊息,它會將該訊息發送到所有串連發送渠道。
Message 是伺服器和用戶端資料互動的基礎資料型別 (Elementary Data Type),在這裡我們定義了兩個訊息類型,一個是簡訊,另外一個是即時的使用者線上狀態。
type ActiveRoom struct { OnlineUsers map[string]*OnlineUser Broadcast chan Message CloseSign chan bool}type Message struct { MType string TextMessage TextMessage UserStatus UserStatus}func (this *ActiveRoom) run() { for { select { case b := <-this.Broadcast: for _, online := range this.OnlineUsers { online.Send <- b } case c := <-this.CloseSign: if c == true { close(this.Broadcast) close(this.CloseSign) return } } }}
OnlineUser 類代表一個成功串連到聊天室的使用者,它維護著 ActiveRoom 執行個體的指標、伺服器和用戶端之間的 websocket 串連,同時包括正在聊天的使用者和 Go 的通訊渠道。
OnlineUser 定義了兩個指標方法
PushToClient:
從發送渠道讀取訊息然後將這些訊息通過 websocket 推送給用戶端。
PullFromClient:
從用戶端讀取訊息並發送到正在啟動並執行 ActiveRoom 執行個體。
這兩個方法使用 "for" 語句來等待新的訊息,除非 websocket 串連中斷。
type OnlineUser struct { InRoom *ActiveRoom Connection *websocket.Conn UserInfo *User Send chan Message}func (this *OnlineUser) PullFromClient() { for { var content string err := websocket.Message.Receive(this.Connection, &content) if err != nil { return } m := Message{ MType: TEXT_MTYPE, TextMessage: TextMessage{ UserInfo: this.UserInfo, Time: humanCreatedAt(), Content: content, }, } this.InRoom.Broadcast <- m }}func (this *OnlineUser) PushToClient() { for b := range this.Send { err := websocket.JSON.Send(this.Connection, b) if err != nil { break } }}
下面我們來看看程式流程,BuildConnection
函數在 main 函數中被註冊為 websocket 串連的處理器:
http.Handle("/chat", websocket.Handler(wscon.BuildConnection))
當有一個 websocket 串連請求,該函數將做一些初始化工作用於處理新的串連:
func BuildConnection(ws *websocket.Conn) { email := ws.Request().URL.Query().Get("email") onlineUser := &OnlineUser{ InRoom: runningActiveRoom, Connection: ws, Send: make(chan Message, 256), UserInfo: &User{ Email: email, Name: strings.Split(email, "@")[0], Gravatar: libs.UrlSize(email, 20), }, } runningActiveRoom.OnlineUsers[email] = onlineUser m := Message{ MType: STATUS_MTYPE, UserStatus: UserStatus{ Users: runningActiveRoom.GetOnlineUsers(), }, } runningActiveRoom.Broadcast <- m go onlineUser.PushToClient() onlineUser.PullFromClient() onlineUser.killUserResource()}
用戶端
最後一部分是用戶端的實現,這是採用 JavaScript 實現的。它開啟了一個新的 websocket 串連到聊天伺服器,並註冊回呼函數用於處理來自伺服器端的訊息。你會發現當串連收到新的訊息時,conn.onmessage 將被調用。現在你只需將接收到的訊息交給對應的 JavaScript 函數去處理:
if (window["WebSocket"]) { conn = new WebSocket("ws://{{.WebSocketHost}}/chat?email={{.Email}}"); conn.onopen = function() {}; conn.onmessage = function(evt) { var data = JSON.parse(evt.data); switch(data.MType) { case "text_mtype": addMessage(data.TextMessage) break; case "status_mtype": updateUsers(data.UserStatus) break; default: } }; conn.onerror = function() { errorMessage("<strong> An error just occured.<strong>") }; conn.onclose = function() { errorMessage("<strong>Connection closed.<strong>") };} else { errorMessage("Your browser does not support WebSockets.");}
如果你對這個應用高度興趣,你可以從這裡擷取整個應用的源碼:gochatting.
英文原文,OSCHINA原創翻譯
轉自:http://www.oschina.net/question/12_63247?from=20120805