我正在尝试使用相同的端口来提供正常的HTTP流量以及通过Cramp(构建在EventMachine之上)的HTML5 websocket,使用Ruby 1.9.3和Thin 1.3.1。这是一个最小的,自包含的例子:
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代码与ws://localhost:3000/socket
建立了一个WebSocket连接,它与发送给它的消息相呼应,但这并不像预期的那样工作。 open
事件触发,发送消息时没有错误,但我们从未收到回复。
从服务器的角度来看,由于Client connected
消息未被打印,因此未建立任何连接。
使用thin start -D
,我可以看到HTTP 101正在发生,并且正在交换一些二进制数据。
我做错了什么?
更新:如果我将文件拆分为两部分,请删除HttpRouter
,并在不同的端口上运行两个thin
实例,但它仍然不起作用。所以问题出在套接字代码中,而不是HttpRouter
或WebApp
。
答案 0 :(得分: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