WebSocket handshake with Ruby and EM::WebSocket::Server
I think that once the connection is open the request and response have already occurred, so sending headers at that point is too late. In addition, headers have to end with a blank line, which you omitted.
According to the demos, you don't even have to set headers in the client or the server--the ruby module automatically takes care of the headers on the server side, and html5 automatically takes care of the headers on the client side. I think this should work:
require "em-websocket-server"
class EchoServer < EM::WebSocket::Server
def on_connect
EM::WebSocket::Log.debug "Connected"
puts "I felt a connection."
enddef on_receive msg
puts "RECEIVED: #{msg}"
send_message msg
endend
EM.run do
myhost = "0.0.0.0"
myport = 8000
puts "Starting WebSocket server. Listening on port #{myport}..."
EM.start_server myhost, myport, EchoServer
end
html file:
<!DOCTYPE html> <html> <head><title>Test</title>
<script type="text/javascript">
var myWebSocket = new WebSocket("ws://localhost:8000");
myWebSocket.onopen = function(evt) {
console.log("Connection open. Sending message...");
myWebSocket.send("Hello WebSockets!"); };
myWebSocket.onmessage = function(evt) {
console.log(evt.data);
myWebSocket.close(); };
myWebSocket.onclose = function(evt) {
console.log("Connection closed."); };
myWebSocket.onerror = function(err) {
alert(err.name + " => " + err.message); } </script>
</head> <body> <div>Hello</div> </body> </html>
And it does work in Safari 5.1.9 (which is an older browser): I see the expected output on both the server and the client. However, the code does not work in Firefox 21: I get the error message...
Firefox can't establish a connection to the server at ws://localhost:8000/.
var myWebSocket = new WebSocket("ws://localhost:8000");
I notice that in both Firebug and Safari Developer Tools, the server does not send a Sec-WebSocket-Accept header:
Response Headers
Connection Upgrade
Upgrade WebSocket
WebSocket-Location ws://localhost:8000/
WebSocket-Origin null
Request Headers
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cache-Control no-cache
Connection keep-alive, Upgrade
DNT 1
Host localhost:8000
Origin null
Pragma no-cache
Sec-WebSocket-Key r9xT+ywe533EHF09wxelkg==
Sec-WebSocket-Version 13
Upgrade websocket
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:21.0) Gecko/20100101 Firefox/21.0
Nothing I tried would make the code work in Firefox 21.0. To check whether Firefox 21.0 even supports websockets, I went to:
http://www.websocket.org/echo.html
and it said my browser does support websockets.
Is there any reason you have to use the em-websocket-server module? The last modification for that module on github was three years ago. And whenever you see
require rubygems
in ruby code, that should alert you that the code is old. I tried the newer em-websocket module, and I was able to successfully transfer data back and forth using websockets on both Firefox 21.0 and Safari 5.1.9:require 'em-websocket'
myhost = "0.0.0.0"
myport = 8000EM.run {
puts "Listening on port #{myport}..."EM::WebSocket.run(:host => myhost, :port => myport, :debug => false) do |ws|
ws.onopen do |handshake|
path = handshake.path
query_str = handshake.query
origin = handshake.origin
puts "WebSocket opened:"
puts "\t path \t\t -> #{path}"
puts "\t query_str \t -> #{query_str}"
puts "\t origin \t -> #{origin}"
end
ws.onmessage { |msg|
ws.send "Pong: #{msg}"
}
ws.onclose {
puts "WebSocket closed"
}
ws.onerror { |e|
puts "Error: #{e.message}"
}end
}
Same client side code. Now the response headers include Sec-WebSocket-Accept:
Response Headers
Connection Upgrade
Sec-WebSocket-Accept LyIm6d+kAAqkcTR744tVK9HMepY=
Upgrade websocket
Request Headers
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Cache-Control no-cache
Connection keep-alive, Upgrade
DNT 1
Host localhost:8000
Origin null
Pragma no-cache
Sec-WebSocket-Key pbK8lFHQAF+arl9tFvHn/Q==
Sec-WebSocket-Version 13
Upgrade websocket
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:21.0) Gecko/20100101 Firefox/21.0
In your code, I don't think you are setting any headers. Instead, you are just sending messages back and forth that happen to contain characters that look like headers. Apparently, your browser requires the Sec-WebSocket-Accept header in the response before it will allow the connection, and when the em-websocket-server module fails to set that header in the response, your browser refuses the connection.
The relevant source code for em-websockets-server looks like this:
module EM
module WebSocket
module Protocol
module Version76
# generate protocol 76 compatible response headers
def response
response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
response << "Upgrade: WebSocket\r\n"
response << "Connection: Upgrade\r\n"
response << "Sec-WebSocket-Origin: #{origin}\r\n"
response << "Sec-WebSocket-Location: #{scheme}://#{host}#{path}\r\n"
if protocol
response << "Sec-WebSocket-Protocol: #{protocol}\r\n"
end
response << "\r\n"
response << Digest::MD5.digest(keyset)
response
end
As you can see, it doesn't set the Sec-WebSocket-Accept header. That code is in a module called Version76, and searching google for websockets version 76 yields an obsolete protocol(which contains an example of a request and response):
https://datatracker.ietf.org/doc/html/draft-hixie-thewebsocketprotocol-76
Here is the current websockets protocol(which also contains an example of a request and response):
https://www.rfc-editor.org/rfc/rfc6455
Conclusion: em-websockets-server is obsolete.
websocket-rails, websocket handshake error
Thanks to the members of the Websocket Rails IRC, I found out that in my route, I was appending the locale before every path, so it coudln't find it.
Check your routes.rb
if someone hit that issue too !
Websockets with Rails(Puma) - Error during WebSocket handshake: Unexpected response code: 200
Try this in your console:
window.dispatcher = new WebSocketRails window.document.location.host + '/websocket'
You configure the rest of what you want to do in the config/events.rb file and whatever controllers you use to handle the events
Any success with Sinatra working together with EventMachine WebSockets?
Did not try it, but should not be too hard:
require 'em-websocket'
require 'sinatra/base'
require 'thin'
EM.run do
class App < Sinatra::Base
# Sinatra code here
end
EM::WebSocket.start(:host => '0.0.0.0', :port => 3001) do
# Websocket code here
end
# You could also use Rainbows! instead of Thin.
# Any EM based Rack handler should do.
Thin::Server.start App, '0.0.0.0', 3000
end
Also, Cramp has a websocket implementation that works directly with Thin/Rainbows! you might be able to extract, so you won't even need to run the server on another port.
Using em-websocket gem can't change connection to 'ws://' RUBY
EventMachine is listening on port 8000:EventMachine::WebSocket.start(:host => "0.0.0.0", :port => 8000)
but you are trying to connect to port 3000: ws = new WebSocket("ws://localhost:3000/home/webSocket");
Change it to connect to port 8000:
ws = new WebSocket("ws://localhost:8000/home/webSocket");
Although the additional path is not needed unless you specifically want to pass /home/webSocket
to EventMachine.
broadcasting data with event machine websocket
You asking for a basic chat server?
Just store the connections in a list (or hash).
People tend to include in a hash to make it easier to remove them
If this is in a class, use @connections
instead of $connections
GL
$connections = {}
EventMachine::WebSocket.run(:host => "0.0.0.0", :port => 8080) do |ws|
ws.onopen
$connections[ws] = true
end
ws.onclose do
$connections.delete(ws)
end
ws.onmessage do |msg|
$connections.each { |c, b| c.send msg }
end
end
Related Topics
Youtube Iframe Player API - Onstatechange Not Firing
How to Get an Ajax Get-Request to Wait for the Page to Be Rendered Before Returning a Response
Why Is It Frowned Upon to Modify JavaScript Object's Prototypes
Console.Log() After Setstate() Doesn't Return the Updated State
React - User-Defined Jsx Components Not Rendering
How to Set Bootstrap Navbar Active Class with Angular Js
How to Enable Touch on Multiple Buttons Simultaneously in React Native
How to Print Part of a Rendered HTML Page in JavaScript
Calculating Page Load Time in JavaScript
Parsing JSON Giving "Unexpected Token O" Error
Ruby on Rails 4 JavaScript Not Executed
JavaScript with Embedded Ruby: How to Safely Assign a Ruby Value to a JavaScript Variable
How to Pre-Populate a Jquery Datepicker Textbox with Today's Date
How to Format a Utc Date as a 'Yyyy-Mm-Dd Hh:Mm:Ss' String Using Nodejs
Using Socket.Io in Express 4 and Express-Generator's /Bin/Www