Faye

这是我目前最终采用的方案: nodejs faye! 支持websocket,默认状态下是不走websocket的,基于bayeux协议的subscribe/publish实现。 所以在按照faye例子调试的时候一定要注意:先把不走websocket的调通。目前看来,不走websocket的方案也够用了。 如果要走websocket,一定要注意node服务端用new WebSocket.Client和客户端交互,browser客户端要加上 endpoints: { websocket: ‘http://127.0.0.1:8012/’ }

WebSocket Ruby

EventMachine 是否支持Ruby2.0?应该支持吧,因为我用websocket-rails的时候不报错。

websocket-rails

待解决的问题

1 虽说wiki中指出了支持background jobs中调用websocket-rails的事件,但实践操作起来没有成功。 synchronize = true

2 在尝试rails production模式下运行websocket-rails貌似没法成功建立websocket连接,报错500错误。具体错误信息还需要我 进一步查看一下production.log的日志信息。

3 用Sneakers消费消息的时候websocket-rails的synchronize = true,Sneakers出现了报错信息。但貌似消息本身被正常的消费掉了, 但并没能成功的调用websocket-rails,以至于我只好通过http::get的方式调用websocket-rails,虽然设置了timeout,但这也是性能上的一大缺憾,直接导致程序无法支持高并发!

目前方向

由于以上三个待解决的问题,我已经开始尝试用node.js和faye组合来完成websocket了。

实现

javascript:
  var dispatcher = new WebSocketRails('localhost:3000/websocket');
  dispatcher.on_open = function (data) {
    console.log('-------Connection has been established: ', data);
  }

  dispatcher.trigger('hellowork', {name: 'Start taking advantage of WebSockets'});

  dispatcher.bind('hellowork_success', function (res) {
    console.log('successfully created hellowork_success' + res.name);
  });
class HelloController < WebsocketRails::BaseController
  def hellowork
    puts "---hellowork---- and message is #{message[:name]}"
    sleep(20)
    send_message :hellowork_success, message
  end
end
subscribe :hellowork, :to => HelloController, :with_method => :hellowork
class ConnectController < WebsocketRails::BaseController
  def client_connected
    puts "---client_connected----"
    send_message :connect_success, { message: 'Welcome! We are connected!' }
  end

  def client_disconnected
    puts "---disconnected ----"
    send_message :disconnect_success, { message: 'Yeah! We are disconnected!' }
  end
end

注意事项:

new WebSocketRails(‘localhost:3000/websocket’); 这里的URL一定要通过localhost:3000来访问网站,否则会因为session不能跨域名共享而抱current_user id找不到的错误。

问题:

1、(Resolved.)因为我加了sleep(20),导致整个rails web服务被卡死。成了单线程的了。这是不可忍受的。(补充:这个应该不是问题。因为在rails自己的controller中加sleep也是同样的效果。后来查了一下,sleep是暂停当前线程。但在sinatra代码中写sleep不会影响其他浏览器的响应,据说sinatra通过ruby xxx.rb的方式启动,是多线程的。难道rails却变成了单线程的了?还是感觉奇怪。)

2、(基本解决)每次点击该页面(包含:var dispatcher = new WebSocketRails(‘localhost:3000/websocket’);)都会生成一个connection.如果按ctrl+R,会刷新页面,这时会关闭所有连接,并重新建立一个连接。如果点击了其他页面,并不会关闭原有连接。但ctrl+R会关闭并重新建立一个连接。 如果关闭浏览器,会关闭所有连接。

解决方案:用一个新打开的页面进行WebSocket通讯,其他页面不要和websocket通讯。

3、用puma和unicorn跑,都出现

(Resolved) RuntimeError (eventmachine not initialized: evma_install_oneshot_timer): eventmachine (1.0.3) lib/eventmachine.rb:323:in add_oneshot_timer’`

解决办法见: http://stackoverflow.com/questions/25657405/websockets-not-working-in-my-rails-app-when-i-run-on-unicorn-server-but-works-o

主要是创建config/initializers/eventmachine.rb,并加入: Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?

4 (Resolved.) Unexpected error while processing request: deadlock; recursive locking Add config.middleware.delete Rack::Lock to production.rb