1

我尝试构建一个广告牌,用于在服务器使用 sinatra 启动的浏览器中显示消息。在服务器代码中最明显的事情是这样的:

服务器:

require 'em-websocket'
require 'yajl'
require 'haml'
require 'sinatra/base'
require 'thin'

$channel = EM::Channel.new

EventMachine.run do
  class App < Sinatra::Base
    get '/' do
      haml :index
    end
  end

  EventMachine::WebSocket.start(:host => '0.0.0.0', :port => 8080) do |ws|
    ws.onopen {
      sid = $channel.subscribe { |msg| ws.send msg }
      ws.onmessage { |msg| $channel.push msg}
# the text I periodically send to the server and want to be visible in the connected webbrowsers
      1.upto(5) {|i| sleep 3; ws.send "Hello #{i}"} #had to remove this
    }
  end
  App.run!({:port => 3000})
end

索引.haml

!!!
%html{:lang => "en"}
  %head
    %link{:href => "/css/bootstrap.css", :rel => "stylesheet"}
  %body
    %div#show
    %script{:src => "http://code.jquery.com/jquery-1.7.2.min.js"}
    %script{:src => "/js/bootstrap.js"}
    %script{:src => "/js/app.js"}

应用程序.js

$(function(){
  ws = new WebSocket("ws://localhost:8080");
  ws.onmessage = function(evt) {
    if (evt.data!='done'){
      document.getElementById("show").innerHTML = evt.data; 
    }
  };
});

但是文本在最后一次睡眠后立即显示在浏览器中,因此只有最后一行可见。建立连接后,我似乎无法从服务器端发送内容,只能作为对传入消息的反应。

因此,我使用如下所示的 Ruby 客户端进行了尝试,但每次发送文本时都必须建立新连接,将循环放在 .callback 或 .stream 方法中不起作用。

require 'em-websocket-client'

def send text
  EM.run do
    conn = EventMachine::WebSocketClient.connect("ws://localhost:8080")

    conn.callback do
      conn.send_msg text
      conn.send_msg "done"
    end

    conn.stream do |msg|
      puts "<#{msg}>"
      if msg.data == "done"
        conn.close_connection
      end
    end

    conn.disconnect do
      EM::stop_event_loop
    end
  end
end

1.upto(5) do |i|
  sleep 3
  send "Hello #{i}"
end

我相信必须有更好的方法来实现这一点,请问哪种方式?

4

0 回答 0