UDN-企业互联网技术人气社区

板块导航

浏览  : 1883
回复  : 6

[HTML5] 使用Go语言和 HTML5 WebSocket 构建一个 Web 聊天室

[复制链接]
genie1003的头像 楼主
发表于 2015-7-22 16:41:20 | 显示全部楼层 |阅读模式
  这个应用演示如何使用 Google Go 语言和 HTML5 的 WebSocket 来实现一个简单的基于 Web 的聊天程序。

  下图是聊天应用的截图:
1344095480_6428.jpg

  你可输入 email 来加入聊天室,我们将从 Gravatar 上获取对应的用户名和头像,当你正在聊天时,你能在界面右侧看到聊天室其他人的姓名和头像。你可以输入信息来跟他们聊天。现在,让我们来看看如何实现这么一个程序。

  服务器端

  首先我们需要一个名为 ActiveRoom 聊天室引擎作为整个应用的核心。该引擎将在下面的代码中定义,当程序主函数启动时将会初始化一个聊天室引擎实例并作为一个全局变量。

  正在运行的实例用于维护所有 websocket 连接并处理收到的消息。一旦通过广播渠道接收到一个新的消息,它会将该消息发送到所有连接发送渠道。

  Message 是服务器和客户端数据交互的基本数据类型,在这里我们定义了两个消息类型,一个是文本消息,另外一个是实时的用户在线状态。
  1. type ActiveRoom struct {
  2.      OnlineUsers map[string]*OnlineUser
  3.      Broadcast   chan Message
  4.      CloseSign   chan bool
  5. }

  6. type Message struct {
  7.      MType       string
  8.      TextMessage TextMessage
  9.      UserStatus  UserStatus
  10. }

  11. func (this *ActiveRoom) run() {
  12.      for {
  13.           select {
  14.           case b := <-this.Broadcast:
  15.                for _, online := range this.OnlineUsers {
  16.                     online.Send <- b
  17.                }
  18.           case c := <-this.CloseSign:
  19.                if c == true {
  20.                     close(this.Broadcast)
  21.                     close(this.CloseSign)
  22.                     return
  23.                }
  24.           }
  25.      }
  26. }
复制代码

  OnlineUser 类代表一个成功连接到聊天室的用户,它维护着 ActiveRoom 实例的指针、服务器和客户端之间的 websocket 连接,同时包括正在聊天的用户和 Go 的通讯渠道。

  OnlineUser 定义了两个指针方法

  PushToClient:
  从发送渠道读取消息然后将这些消息通过 websocket 推送给客户端。

  PullFromClient:
  从客户端读取消息并发送到正在运行的 ActiveRoom 实例。这两个方法使用 "for" 语句来等待新的消息,除非 websocket 连接中断。
  1. type OnlineUser struct {
  2.      InRoom     *ActiveRoom
  3.      Connection *websocket.Conn
  4.      UserInfo   *User
  5.      Send       chan Message
  6. }

  7. func (this *OnlineUser) PullFromClient() {
  8.      for {
  9.           var content string
  10.           err := websocket.Message.Receive(this.Connection, &content)

  11.           if err != nil {
  12.                return
  13.           }

  14.           m := Message{
  15.                MType: TEXT_MTYPE,
  16.                TextMessage: TextMessage{
  17.                     UserInfo: this.UserInfo,
  18.                     Time:     humanCreatedAt(),
  19.                     Content:  content,
  20.                },
  21.           }
  22.           this.InRoom.Broadcast <- m
  23.      }
  24. }

  25. func (this *OnlineUser) PushToClient() {
  26.      for b := range this.Send {
  27.           err := websocket.JSON.Send(this.Connection, b)
  28.           if err != nil {
  29.                break
  30.           }
  31.      }
  32. }
复制代码

  下面我们来看看程序流程,BuildConnection 函数在 main 函数中被注册为 websocket 连接的处理器:
  1. http.Handle("/chat", websocket.Handler(wscon.BuildConnection))
复制代码

  当有一个 websocket 连接请求,该函数将做一些初始化工作用于处理新的连接:
  1. func BuildConnection(ws *websocket.Conn) {
  2.      email := ws.Request().URL.Query().Get("email")
  3.      onlineUser := &OnlineUser{
  4.           InRoom:     runningActiveRoom,
  5.           Connection: ws,
  6.           Send:       make(chan Message, 256),
  7.           UserInfo: &User{
  8.                Email:    email,
  9.                Name:     strings.Split(email, "@")[0],
  10.                Gravatar: libs.UrlSize(email, 20),
  11.           },
  12.      }

  13.      runningActiveRoom.OnlineUsers[email] = onlineUser

  14.      m := Message{
  15.           MType: STATUS_MTYPE,
  16.           UserStatus: UserStatus{
  17.                Users: runningActiveRoom.GetOnlineUsers(),
  18.           },
  19.      }

  20.      runningActiveRoom.Broadcast <- m
  21.      go onlineUser.PushToClient()
  22.      onlineUser.PullFromClient()
  23.      onlineUser.killUserResource()
  24. }
复制代码

  客户端

  最后一部分是客户端的实现,这是采用 JavaScript 实现的。它打开了一个新的 websocket 连接到聊天服务器,并注册回调函数用于处理来自服务器端的消息。你会发现当连接收到新的消息时,conn.onmessage 将被调用。现在你只需将接收到的消息交给对应的 JavaScript 函数去处理:
  1. if (window["WebSocket"]) {
  2.     conn = new WebSocket("ws://{{.WebSocketHost}}/chat?email={{.Email}}");
  3.     conn.onopen = function() {};

  4.     conn.onmessage = function(evt) {
  5.          var data = JSON.parse(evt.data);
  6.          switch(data.MType) {
  7.               case "text_mtype":
  8.                    addMessage(data.TextMessage)
  9.                    break;
  10.               case "status_mtype":
  11.                    updateUsers(data.UserStatus)
  12.                    break;
  13.               default:
  14.          }
  15.     };

  16.     conn.onerror = function() {
  17.            errorMessage("<strong> An error just occured.<strong>")
  18.     };

  19.     conn.onclose = function() {
  20.            errorMessage("<strong>Connection closed.<strong>")
  21.     };
  22. } else {
  23.     errorMessage("Your browser does not support WebSockets.");
  24. }
复制代码
  
发表于 2015-7-23 07:52:43 | 显示全部楼层
好厉害的样子,先收藏了
使用道具 举报

回复

发表于 2015-7-23 07:52:49 | 显示全部楼层
好厉害的样子,先收藏了
使用道具 举报

回复

发表于 2015-7-23 08:49:50 | 显示全部楼层
楼台 发表于 2015-7-23 07:52
好厉害的样子,先收藏了

头像好魔性
使用道具 举报

回复

发表于 2015-8-10 20:26:34 | 显示全部楼层
又见楼主分享帖子
使用道具 举报

回复

发表于 2015-8-15 17:36:49 | 显示全部楼层
总觉得哪里有点问题啊
使用道具 举报

回复

发表于 2015-8-16 20:34:21 | 显示全部楼层
貌似看过类似的文章
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部