首页 > 其他分享 >Go语言Revel框架 聊天室三种通讯方式分析

Go语言Revel框架 聊天室三种通讯方式分析

时间:2023-07-18 21:04:00浏览次数:37  
标签:聊天室 websocket room Refresh Revel user Go return message

三种机制的切换

首页相关的网页请求路由如下:

# Login

GET     /

GET     /demo                                   Application.EnterDemo

首页显示输入昵称和三种聊天技术选择入口,选择后form提交到Application.EnterDemo页面。跳转到三种具体的聊天技术页面是通过Get参数增加user的方式进行的。

func (c Application) EnterDemo(user, demo string) revel.Result {
    c.Validation.Required(user)
    c.Validation.Required(demo)
 
if
        c.Flash.Error("Please choose a nick name and the demonstration type.")
return
    }
 
switch
case "refresh":
return c.Redirect("/refresh?user=%s", user)
    case"longpolling":
return c.Redirect("/longpolling/room?user=%s", user)
    case"websocket":
return c.Redirect("/websocket/room?user=%s", user)
    }
    returnnil
}

定时刷新机制

从功能角度,定时刷新页面永远会带用户名。http://localhost:9000/refresh?user=ghj1976

在routes表中我们可以看到定时刷新涉及到下面几个页面请求:

# Refresh demo

GET     /refresh                                Refresh.Index

GET     /refresh/room                           Refresh.Room

POST    /refresh/room                           Refresh.Say

GET     /refresh/room/leave                     Refresh.Leave

进入页面,或者整理浏览器刷新页面,都会触发用户进入chatroom。

func (c Refresh) Index(user string) revel.Result {
    chatroom.Join(user)
return
}
每隔5秒钟,重新请求一下Refresh.Room页面。
<script type="text/javascript"charset="utf-8">
 
  // Scroll the messages panel to the end
var scrollDown = function() {
'#thread').scrollTo('max')
  }
 
  // Reload the whole messages panel
var refresh = function() {
    $('#thread').load('/refresh/room?user={{.user}} #thread .message', function() {
      scrollDown()
    })
  }
 
  // Call refresh every 5 seconds
5000)
 
  scrollDown()
 
</script>

Refresh.Room 的处理逻辑:

使用一个订阅者把目前聊天室的所有信息都显示出来。离开这个处理过程就把订阅者注销。

func (c Refresh) Room(user string) revel.Result {
:=
defer
:=
for i, _ := range
if events[i].User ==
"you"
        }
    }
return
}
对 /refresh/room 发出P

ost请求是,则记录发出的消息,同时刷新页面。

func (c Refresh) Say(user, message string) revel.Result {
    chatroom.Say(user, message)
return
}

离开聊天室时,标示离开,同时跳转页面。

func (c Refresh) Leave(user string) revel.Result {
    chatroom.Leave(user)
return
}

长连接 comet

长连接的路由请求如下:

# Long polling demo

GET     /longpolling/room                       LongPolling.Room

GET     /longpolling/room/messages              LongPolling.WaitMessages

POST    /longpolling/room/messages              LongPolling.Say

GET     /longpolling/room/leave                 LongPolling.Leave

当请求长连接的页面时,http://localhost:9000/longpolling/room?user=ghj1976  把用户加入聊天室。

func (c LongPolling) Room(user string) revel.Result {
    chatroom.Join(user)
return
}

长连接的浏览器端核心逻辑如下,删除了一些跟核心逻辑无关的代码:
向服务器请求有没有新的消息,如果没有新的消息,则会一直等待服务器。如果有则请求完成消息,然后再次发出一个请求getMessages();
 

<script type="text/javascript">
 
var lastReceived = 0
  var waitMessages ='/longpolling/room/messages?lastReceived='
 
  // Retrieve new messages
var getMessages = function() {
    $.ajax({
: waitMessages +
: function(events) {
function() {
this)
= this.Timestamp
        })
        getMessages()
      },
: 'json'
    });
  }
  getMessages();
 
  // Display a message
var display = function(event) {
'#thread').append(tmpl('message_tmpl', {event:
'#thread').scrollTo('max')
  }
 
</script>

服务器端处理逻辑则是借用了channel无法读出新的内容时,会一直等下去的技巧,代码如下:

func (c LongPolling) WaitMessages(lastReceived int) revel.Result {
:=
defer
 
    // See if anything is new in the archive.
var
for _, event := range
if
append(events, event)
        }
    }
 
    // If we found one, grand.
if len(events) > 0
return
    }
 
    // Else, wait for something new.
:= <-subscription.New
return
}

离开和发送消息的逻辑跟定时刷新的机制基本类似,就不再表述。

WebSocket机制

请求路由信息:

# WebSocket demo

GET     /websocket/room                         WebSocket.Room

WS      /websocket/room/socket                  WebSocket.RoomSocket

WebSocket.Room 处理请求这套机制的进入页面。

WebSocket是Chrome支持的一套通讯机制,javascript中只需要简单的 socket.onmessage 、socket.send 两个方法就可以完成相关工作。

 

<script type="text/javascript">
 
  // Create a socket
var socket = new WebSocket('ws://'+window.location.host+'/websocket/room/socket?user={{.user}}')
 
  // Display a message
var display = function(event) {
'#thread').append(tmpl('message_tmpl', {event:
'#thread').scrollTo('max')
  }
 
  // Message received on the socket
= function(event) {
    display(JSON.parse(event.data))
  }
 
'#send').click(function(e) {
var message = $('#message').val()
'#message').val('')
    socket.send(message)
  });
 
'#message').keypress(function(e) {
if(e.charCode == 13 || e.keyCode == 13) {
'#send').click()
      e.preventDefault()
    }
  })
 
</script>

服务器端WebSocket 请求使用了 code.google.com/p/go.net/websocket 封装包。 

代码实现分了三大块,先把用户加入聊天室,订阅聊天室,websocket.JSON.Send 发送之前已有的聊天信息,

然后使用 websocket.Message.Receive 等待接受来自浏览器的消息内容。

同时用 channel select 方式接受自己发出的和别人发出的消息。

func (c WebSocket) RoomSocket(user string, ws *websocket.Conn) revel.Result {
    // Join the room.
:=
defer
 
    chatroom.Join(user)
defer
 
    // Send down the archive.
for _, event := range
if websocket.JSON.Send(ws, &event) != nil
            // They disconnected
return nil
        }
    }
 
    // In order to select between websocket messages and subscription events, we
    // need to stuff websocket events into a channel.
:= make(chan string)
go func() {
var msg string
for
:= websocket.Message.Receive(ws, &msg)
if err != nil
close(newMessages)
return
            }
<-
        }
    }()
 
    // Now listen for new events from either the websocket or the chatroom.
for
select
case event := <-subscription.New:
if websocket.JSON.Send(ws, &event) != nil
                // They disconnected.
return nil
            }
case msg, ok := <-newMessages:
            // If the channel is closed, they disconnected.
if
return nil
            }
 
            // Otherwise, say something.
            chatroom.Say(user, msg)
        }
    }
    return nil
}

参看资料:


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

HTTP长连接
http://www.blogjava.net/xjacker/articles/334709.html 

Comet:基于 HTTP 长连接的“服务器推”技术
http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

android 客户端怎么实现长连接和短连接?

Android/iOS Notification feature

标签:聊天室,websocket,room,Refresh,Revel,user,Go,return,message
From: https://blog.51cto.com/u_15588078/6768238

相关文章

  • WebSocket搭建一个简单的聊天室
    这个例子比较简单:只有一个聊天室,大家进入的都是同一个聊天室。 没有用户登录,用户登录直接根据id给出匿名用户。程序截图,UI我直接用的 https://github.com/Niessy/websocket-golang-chat这里给的例子的Html代码。                  服务器端Golang代码:package......
  • Golang的跨平台编译程序
    Golang支持交叉编译,也就是说你在32位平台的机器上开发,可以编译生成64位平台上的可执行程序。交叉编译依赖下面几个环境变量:$GOARCH  目标平台(编译后的目标平台)的处理器架构(386、amd64、arm)$GOOS     目标平台(编译后的目标平台)的操作系统(darwin、freebsd、linux、wind......
  • Go语言用WebSocket的简单例子
    Go语言标准包里面没有提供对WebSocket的支持,但是在由官方维护的go.net子包中有对这个的支持,需要独立下载, Gowebsocketpackage下载地址:http://code.google.com/p/go.net/websocket。Goget命令下载:gogetcode.google.com/p/go.net/websocket Go实现的WebSocket的文档:http://......
  • Golang做的验证码(2)
    前面一篇文章介绍了2个用Golang做的验证码 这里再补充几个:1、在GAE上使用的Google的验证码(ReCAPTCHA)封装https://github.com/ThePiachu/GAE-Go-ReCAPTCHA这个的核心代码只在下面这个文件:https://github.com/ThePiachu/GAE-Go-ReCAPTCHA/blob/master/ReCaptcha/ReCaptcha.go 2、一......
  • Golang连接Oracle数据库
    Golang连接Oracle的库有很多,比较常见的如下:不过,oralce只提供了oci8的接口,必须通过它来调用,所以下面方案都逃不过相关设置。1、go-db-oracle地址:https://code.google.com/p/go-db-oracle/官方介绍:OracleDriverusingcgotocallOCIlibrariesfromOracleInstantClient11.......
  • java mongo 插入geometry 多边形 线 点
    importcom.mongodb.client.MongoCollection;importcom.mongodb.client.model.geojson.LineString;importcom.mongodb.client.model.geojson.Point;importcom.mongodb.client.model.geojson.Polygon;importcom.mongodb.client.model.geojson.Position;importcom.tusvn.cc......
  • Go语言读取网上Json格式的天气预报数据例子
    天气预报接口使用的是:http://www.weather.com.cn/data/sk/101010100.html这里的Json数据如下:{"weatherinfo":{"city":"北京","cityid":"101010100","temp":"1......
  • Sublime Text 2下配置Go语言环境
    安装SublimeText2SublimeText2下载地址:http://www.sublimetext.com/2 SublimeText2可免费使用,只是保存次数达到一定数量之后就会提示是否购买,点击取消继续用,和正式注册版本没有任何区别。我下载的是Mac版的,安装只需要简单的把dmg包打开,把应用文件拖动到Application中即可。......
  • Go安装的设置问题:GOROOT,GOPATH
    Mac下使用Google官方的Go语言安装包:https://code.google.com/p/go/downloads/list 安装的Go,会自动把/usr/local/go/bin目录加入PATH中。这样我们直接在控制台就可以执行go语言的一些命令。http://golang.org/cmd/go/#hdr-GOPATH_environment_variable 下面使用export命令看到......
  • centos7 下全局配置最新版的golang语言开发环境
    按照以下步骤进行操作:前往Go官方网站下载页面(https://golang.org/dl/)查找最新版本的Go二进制文件。使用wget命令下载最新版本的Go二进制文件。例如,如果最新版本是1.17,执行以下命令:$wgethttps://golang.org/dl/go1.17.linux-amd64.tar.gz解压缩下载的压缩包:$sudota......