zoukankan      html  css  js  c++  java
  • Go语言Revel框架 的聊天室示例解读

    安装Revel框架请参看下面这篇文章:《Go语言Revel框架 准备工作》 http://www.cnblogs.com/ghj1976/archive/2013/03/24/2979709.html

    运行聊天室例子

    运行聊天室例子只需执行下面命令:

    $ revel run github.com/robfig/revel/samples/chat

    $ revel run github.com/robfig/revel/samples/chat
    ~
    ~ revel! http://robfig.github.com/revel
    ~
    2013/03/25 11:54:42 revel.go:240: Loaded module static
    2013/03/25 11:54:42 run.go:57: Running chat (github.com/robfig/revel/samples/chat) in dev mode
    2013/03/25 11:54:42 harness.go:143: Listening on :9000
    2013/03/25 11:54:55 revel.go:240: Loaded module static
    2013/03/25 11:54:55 main.go:26: Running revel server
    2013/03/25 11:54:55 i18n.go:93: Error reading messages files: lstat /Users/cybercare/go/src/github.com/robfig/revel/samples/chat/messages: no such file or directory
    Listening on port 52482...

    这时候访问 http://localhost:9000/ 就可以让你选择昵称和连接方式进入聊天的界面。

    NewImage

    代码解读

    目录组织结构

    这个演示程序的目录组织结构:

    Here are the contents of the app:

    chat/app/
    chatroom # Chat room routines 聊天室协程
    chatroom.go
    controllers
    app.go # The welcome screen, allowing user to pick a technology 欢迎页面,允许客户选择一个数据
    refresh.go # Handlers for the "Active Refresh" chat demo 定时刷新的聊天室Demo
    longpolling.go # Handlers for the "Long polling" ("Comet") chat demo 长连接 Comet技术的聊天室
    websocket.go # Handlers for the "Websocket" chat demo Websocket 技术的聊天室
    views
    ... # HTML and Javascript

    解读 chatroom.go 

    一个聊天室开一个协程来单独处理,chatroom() 函数无限循环运行,处理每次聊天的请求。

    func init() {

         go chatroom()

    }

    chatroom() 函数 在三个 channels 之间 select, 并执行相应的请求操作。

    type Event struct {

        Type      string // "join", "leave", or "message" 演示Demo只有这三种类型

        User      string // 发出事件的用户名

        Timestamp int    // Unix timestmap (secs) 发出事件的系统时间

        Text      string // What the user said (if Type == "message")  用户说的内容,只有 Type=message时,才会有这个信息。

    }

     

    type Subscription struct {

        Archive []Event      // All the events from the archive.  归档的所有事件

        New     <-chan Event // New events coming in.  新到来的事件

    }


    var (

        // Send a channel here to get room events back.  It will send the entire

        // archive initially, and then new messages as they come in.

        // 当有新用户加入时,初始化的一些订阅信息。

        subscribe = make(chan (chan<- Subscription), 10)


        // Send a channel here to unsubscribe.

        // 在信道channel中发送退订。

        unsubscribe = make(chan (<-chan Event), 10)


        // Send events here to publish them.

        // 在这里发送事件

        publish = make(chan Event, 10)

    )

     

    // This function loops forever, handling the chat room pubsub

    func chatroom() {

        archive := list.New()      // 最近的几条聊天记录

        subscribers := list.New()  // 订阅者列表

     

        for {

            select {

            case ch := <-subscribe:

                // Add subscriber to list and send back subscriber channel + chat log.

                // 当有新用户加入聊天时,添加到用户列表并给该用户发送 channel 和聊天记录。

            case event := <-publish:

                // Send event to all subscribers and add to chat log.

                // 发送 Event 给所有订阅者,并且增加到聊天记录中。

            case unsub :=<-unsubscribe:

                // Remove subscriber from subscriber list.

                // 订阅者离开后,从用户列表中删除离开者。

            }

        }

    }

    当一个新的用户加入时,处理下面事情:

    1. 把最新的聊天记录Copy出来,以便提供给新来的用户。
    2. 把用户订阅channel加入到聊天者channel清单中。
    3. 聊天订阅者获得新信息的 channel 

           case ch := <-subscribe:

     

                var events []Event

                for e := archive.Front(); e != nil; e = e.Next() {

                    events = append(events, e.Value.(Event))

                }

                subscriber := make(chan Event, 10)

                subscribers.PushBack(subscriber)

                ch <- Subscription{events, subscriber}

     

    当用户发布新聊天内容时,发布的event一个一个发送给订阅者的channel,然后event被添加到archive,archive里面的数量大于10,前面的会被移出。

     

           case event := <-publish:

     

                for ch := subscribers.Front(); ch != nil; ch = ch.Next() {

                    ch.Value.(chan Event) <- event

                }

                if archive.Len() >= archiveSize {

                    archive.Remove(archive.Front())

                }

                archive.PushBack(event)

     

    当有用户离开聊天室时,订阅者channel在list中被移除。

           case unsub := <-unsubscribe:

     

                for ch := subscribers.Front(); ch != nil; ch = ch.Next() {

                    if ch.Value.(chan Event) == unsub {

                        subscribers.Remove(ch)

                        break

                    }

                }

            }

    对聊天室框架代码解读可以看下面这个思维导图:

    NewImage

    参考资料:

    http://robfig.github.com/revel/index.html

    http://robfig.github.com/revel/samples/chat.html 

    http://robfig.github.com/revel/samples/index.html

    Revel示例 - 聊天室
    http://www.cnblogs.com/ztiandan/archive/2013/01/23/2864872.html

    http://bbs.studygolang.com/thread-291-1-1.html 

  • 相关阅读:
    Pandas加载含有嵌套(nested)文档的mongodb数据
    [Spark笔记]Spark Streaming连接Kafka的入门代码
    [Spark笔记]Apache Spark — Overview
    [Hive笔记]Hive常用命令整理
    Mac上安装MongoDB后没有默认用户或密码,需要创建用户
    游戏服务器架构系列
    游戏服务器架构系列
    giantbranch的专栏——只更新一些简单的东西,工具什么的,更多更新只在新博客:www.giantbranch.cn
    SpringBoot Admin 2.1.5监控微服务的基本配置
    一张图看清国内程序员的分布数量
  • 原文地址:https://www.cnblogs.com/ghj1976/p/2997231.html
Copyright © 2011-2022 走看看