Tìm hiểu về websocket với rails

Tìm hiểu về websocket với rails

1.Websocket là gì?

WebSoket là công nghệ hỗ trợ giao tiếp hai chiều giữa client và server bằng cách sử dụng một TCP socket để tạo một kết nối hiệu quả và ít tốn kém.

Thông thường dữ liệu được truyền qua phương thức http sẽ chứa các dữ liệu không cần thiết trong headers của một message. Vì vậy khi truyền dữ liệu sẽ rất chậm. Ví dụ 1 header của một http request thường là hơn 800kb trong khi 1 message của websocket chỉ là 2kb.

Mục đích của giao thức WebSocket là cung cấp thông tin liên lạc hai chiều giữa một khách hàng và một máy chủ mà không cần mở nhiều kết nối vì thế nên truyền gửi message rất nhanh chóng.

Tuy nhiên nó cũng có những nhược điểm như không có phạm vi yêu cầu nào, do không sử dụng header nên nó không có session nào cả. Khi một connect bị ngắt kết nối thỳ các transaction và contest của nó cũng bị hủy bỏ theo.

2. Giao thức bắt tay của websocket

websocket_events.jpg

Chúng ta sử dụng 3 events sau:

onopen: Khi websocket đã được mở onmessage: Khi nhận được một message onclose: Khi websocket được đóng lại

Giao thức WebSocket như đã nêu ở trên là giao thứchai chiều qua kết nối TCP duy nhất. Các giao thức bao gồm một cái bắt tay mở mà được giải thích bởi HTTP như là một yêu cầu nâng cấp tiếp theo là khung thông điệp cơ bản, lớp trên TCP. Các giao thức sử dụng mô hình bảo mật dựa trên nguồn gốc. Mục đích của giao thức WebSocket là cung cấp thông tin liên lạc hai chiều giữa một khách hàng và một máy chủ mà không cần mở nhiều kết nối. Một WebSocket hỗ trợ cả hai chuỗi UTF-8 và khung hình nhị phân

3. Gem websocket-rails

Bắt đầu từ rails 4 trở đi đã hỗ trợ websocket. Ta tìm hiểu gem websocket-rails với 3 phần:

1. Subscribe Events to Actions

Khi install gem websocket-rails và chạy sẽ tạo ra một file event.rb vào trong thư mục config để trỏ các event đến chính xác action trong controller. Ta dùng hàm subscribe để định nghĩa như sau:

subscribe :event_name, :to => EventController, :with_method => :action_method

or

subscribe :event_name, 'event#action_method'

Nó sẽ điều hướng đến event.trigged từ javascript client như sau:

dispatcher.trigger('event_name', object_to_send);

2. WebsocketRails Controllers

Ta có thể khơi tạo 1 session trong suốt quá trình connection được mở cho đến khi đóng:

def initialize_session
    # perform application setup here
    controller_store[:message_count] = 0
end

Trong controller dùng hàm send_message để trigger event đến 1 kênh nào đó Ví dụ:

new_message = {:message => 'this is a message'}
send_message :event_name, new_message

Muốn gửi đến một user cụ thể ta có thể dùng:

WebsocketRails.users[myUser.id].send_message('new_notification', {:message => 'you\'ve got an upvote '})

Hoặc dùng hàm broadcast để gửi message đến toàn bộ client đang subscribe kênh:

broadcast_message :new_comment, new_comment

3. Websocket client với javascript

Dưới client để tạo 1 connection ta dùng hàm ví dụ như sau: var dispatcher = new WebSocketRails('localhost:3000/websocket'); function on_open() sẽ được chạy ngay sau khi một connection được khởi tạo Để trigger một event từ server ta dùng như sau:

var comment = {
  title: 'This post was awful',
  body: 'really awful',
  post_id: 9
}

dispatcher.trigger('comments.create', comment);

Dữ liệu sẽ được gửi lên server theo event comment.create. Nhận message tử server trả lại bằng hàm bind. ví dụ:

dispatcher.bind('comments.new', addCommentToDom);

4. Standalone Server Mode

Websocket có thể chạy được với eventmachine như thin, puma nhưng để chạy được với non-eventmachine như unicorn hoặc phusion ta cần bật standalone mode. Việc này rất có ý nghĩa khi deploy trên server.

Để bật standalone mode ta config:

config.standalone = true

Mặc định standalone mode sẽ chạy cổng 3001 nên tao có thể config chính xác cổng chạy websocket như sau:

 config.standalone_port = 3245

Có thể tham khảo thêm tại https://github.com/websocket-rails/websocket-rails/wiki/Standalone-Server-Mode

4. Demo một ứng dụng chat group dùng websocket

ý tưởng chat room đơn giản sử dụng gem websocket-rails. Bỏ qua phần signup, signin .. sử dụng devise. Ta vào luôn phần chính. Ở file event.rb ta subscribe 3 event sau:

  subscribe :client_connected, :to => ChatController, :with_method => :user_connected
  subscribe :new_message, :to => ChatController, :with_method => :incoming_message

Với client_connected sẽ khởi tạo 1 socket connection. new_message sẽ target đến incoming_message có chức năng gửi toàn bộ message đến 1 kênh nào đó

Vì vậy code controller sẽ như sau:

def user_connected
    p 'user connected'
    send_message :user_info, {:user => current_user.screen_name}
end

def incoming_message
     broadcast_message :new_message, {:user =>     current_user.screen_name, :text => message[:text]}
end

Screenshot from 2016-03-28 22:58:39.png

5. Kết luận

Tài liệu tham khảo: https://github.com/websocket-rails/websocket-rails http://blog.rikkeisoft.com/seminar-gioi-thieu-ve-websocket-va-node-js/

source: https://github.com/asvenus/websocket-demo