歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

使用 Go 語言和 HTML5 WebSocket 構建一個 Web 聊天室

這個應用演示如何使用 Google Go 語言和 HTML5 的 WebSocket 來實現一個簡單的基於 Web 的聊天程序。

下圖是聊天應用的截圖:

你可輸入 email 來加入聊天室,我們將從 Gravatar 上獲取對應的用戶名和頭像,當你正在聊天時,你能在界面右側看到聊天室其他人的姓名和頭像。你可以輸入信息來跟他們聊天。

現在,讓我們來看看如何實現這麼一個程序。

服務器端

首先我們需要一個名為 ActiveRoom 聊天室引擎作為整個應用的核心。該引擎將在下面的代碼中定義,當程序主函數啟動時將會初始化一個聊天室引擎實例並作為一個全局變量。

正在運行的實例用於維護所有 websocket 連接並處理收到的消息。一旦通過廣播渠道接收到一個新的消息,它會將該消息發送到所有連接發送渠道。

Message 是服務器和客戶端數據交互的基本數據類型,在這裡我們定義了兩個消息類型,一個是文本消息,另外一個是實時的用戶在線狀態。

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原創翻譯

Copyright © Linux教程網 All Rights Reserved