3

Ruby1.9.3とThin1.3.1を使用して、同じポートを使用して通常のHTTPトラフィックと、Cramp(EventMachine上に構築されている)を介したHTML5WebSocketを提供しようとしています。最小限の自己完結型の例を次に示します。

require 'thin'
require 'cramp'
require 'http_router'

Cramp::Websocket.backend = :thin

class SocketApp < Cramp::Action
  self.transport = :websocket

  on_start = :connected
  on_finish = :disconnected
  on_data = :message

  def connected
    puts 'Client connected'
  end
  def disconnected
    puts 'Client disconnected'
  end
  def message(msg)
    puts "Got message: #{msg}"
    render 'Here is your reply'
  end
end

class WebApp
  def call(env)
    [ 200, { 'Content-Type' => 'text/html' }, <<EOF
<html><head>
<script>
  function init() {
    function log(msg) { document.getElementById('log').innerHTML += msg + '<br>'; }
    var socketUri = 'ws://' + document.location.host + '/socket';
    log('Socket URI: ' + socketUri);
    var socket = new WebSocket(socketUri);
    socket.onopen = function(e) {
      log('onopen');
      socket.send('Is there anybody out there?');
      log('sent message');
    };
    socket.onclose = function(e) {
      log('onclose; code = ' + e.code + ', reason = ' + e.reason);
    };
    socket.onerror = function(e) {
      log('onerror');
    };
    socket.onmessage = function(e) {
      log('onmessage; data = ' + e.data);
    };
  }
</script>
</head><body onload='init();'>
  <h1>Serving Cramp::Websocket and normal Rack app on the same port</h1>
  <p id='log'></p>
</body></html>
EOF
    ]
  end
end

app = HttpRouter.new do
  add('/socket').to SocketApp
  add('/').to WebApp.new
end

run app

これを自分で試してみたい場合は、このコードをという名前のファイルに貼り付けconfig.ruて実行しますthin start。宝石が必要で、thinインストールcrampする必要がありhttp_routerます。

JavaScriptコードがにWebSocket接続を確立しws://localhost:3000/socket、送信されたメッセージをエコーするという考え方ですが、これは意図したとおりには機能しません。イベントが発生し、メッセージのopen送信時にエラーは発生しませんが、応答はありません。

サーバーの観点からは、Client connectedメッセージが出力されないため、接続は確立されていません。

を使用するthin start -Dと、HTTP 101が発生し、一部のバイナリデータが交換されていることがわかります。

私は何が間違っているのですか?

更新:ファイルを2つの部分に分割し、を取り除いて、異なるポートでHttpRouter2つのインスタンスを実行thinしても、それでも機能しません。したがって、問題は、HttpRouterまたはではなく、ソケットコードにありますWebApp

4

1 に答える 1

3

これは不正行為ですが、別のライブラリに切り替えることで最終的に解決しました: websocket-rack。興味深いことに、修正されたコードは次のとおりです。

require 'thin'
require 'http_router'
require 'rack/websocket'

class SocketApp < Rack::WebSocket::Application
  def on_open(env)
    puts 'Client connected'
  end
  def on_close(env)
    puts 'Client disconnected'
  end
  def on_message(env, message)
    puts "Got message: #{message}"
    send_data 'Here is your reply'
  end
end

class WebApp
  def call(env)
    [200, { 'Content-Type' => 'text/html' }, <<EOF
<html><head>
<script>
  function init() {
    function log(msg) { document.getElementById('log').innerHTML += msg + '<br>'; }
    var socketUri = 'ws://' + document.location.host + '/socket';
    log('Socket URI: ' + socketUri);
    var socket = new WebSocket(socketUri);
    socket.onopen = function(e) {
      log('onopen');
      socket.send('Is there anybody out there?');
      log('sent message');
    };
    socket.onclose = function(e) {
      log('onclose; code = ' + e.code + ', reason = ' + e.reason);
    };
    socket.onerror = function(e) {
      log('onerror');
    };
    socket.onmessage = function(e) {
      log('onmessage; data = ' + e.data);
    };
  }
</script>
</head><body onload='init();'>
  <h1>Serving WebSocket and normal Rack app on the same port</h1>
  <p id='log'></p>
</body></html>
EOF
    ]
  end
end

app = HttpRouter.new do
  add('/socket').to(SocketApp.new)
  add('/').to(WebApp.new)
end

run app
于 2012-05-05T21:32:48.713 に答える