4-2 什么是WebSocket; Action Cable的使用。Rails guide-6.3视频教学,没有看!

WebSocket

WebSocket是一种在单个TCP连接上进行全双工通讯的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

背景:

现在,很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

优点:

  • 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小
  • 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少
  • 保持连接状态。于HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。

 https://zh.wikipedia.org/wiki/WebSocket

 


 

Action Cable

1. a thick strong metal rope used on ships, to support bridges etc

通过提供Client Javascript框架和Server端Ruby框架把 WebSocket协议和Rails应用集成起来。

 

2. Publish-Subscribe功能

指定好发布者和订阅者,之后发布者自动发送新数据给订阅者。比传统方式高效。 

3 Server-Side Components

3.1 Connections 第一步连接设置。

 

Connections are instances of ApplicationCable::Connection.对连接的授权就是在这个类中完成的,对能够识别的用户会建立 consumer-connection pair.

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    # 声明连接标志索引,用于之后查找指定连接
    identified_by :current_user
 
    def connect
      # 尝试连接,把cookie发送给连接实例self。
      # 设置current_user,之后就能检索指定用户打开的所有连接。
      self.current_user = find_verified_user
      logger.add_tags 'ActionCable', current_user.name
    end
 
    protected
      def find_verified_user
        if verified_user = User.find_by(id: cookies.signed[:user_id])
          verified_user
        else
          #模块自带方法, 如果找不到,就关闭连接,返回404提示,就是下面2句话。
          # logger.error "An unauthorized connection attempt was rejected"
          # raise UnauthorizedError
          reject_unauthorized_connection
        end
      end
  end
end

identified_by(*identifiers)中的核心语法是:attr_accessor identifier, 就是建立一个存取宏, 产生一个实例名字和存取它的方法。然后把它放入这个数组集合中。

def identified_by(*identifiers)
  Array(identifiers).each { |identifier| attr_accessor identifier }
  self.identifiers += identifiers
end
 

 

3.2 Channels

类似controller做的标准MVC步骤。 

http://api.rubyonrails.org/classes/ActionCable/Channel/Base.html  (api)

Rails creates ApplicationCable::Channel class 封装共享的逻辑在你的各channels.

3.21 Parent Channel Setup 

你自己创建自己的channel类,继承它。 命令:rails generate channel products。

pasting

在类中定义订阅subscribed

 

,取消订阅,拒绝订阅reject(资质审核)等10多个方法。

# app/channels/chat_channel.rb

class ChatChannel < ApplicationCable::Channel # 当用户成为此频道的订阅者时调用
  def subscribed

    。 

  end

end 

 

4 Client-Side Components 

4.1 Connections

Consumers require an instance of the connection on their side. This can be established using the folling JavaScript, which is generated by default by Rails :

4.11 Connect Consumer

identical  app/assets/javascripts/cable.js 

// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `rails generate channel` command.
//
//= require action_cable
//= require_self
//= require_tree ./channels
 
(function() {
  this.App || (this.App = {});
 
  App.cable = ActionCable.createConsumer();
 
}).call(this);

4.12 Subscriber

A consumer becomes a subscriber by creating a subscription to a given channel:

 create  app/assets/javascripts/channels/products.coffee

App.products = App.cable.subscriptions.create "ProductsChannel",

 

  connected: ->
    # Called when the subscription is ready for use on the server
  disconnected: ->
    # Called when the subscription has been terminated by the server
  received: (data) ->
    # Called when there's incoming data on the websocket for this channel

 

 

5. Client-Server Interactions 交互

 

 create  app/channels/products_channel.rb

5.1 Streams

Streams provide the mechanism by which channels route published content (broadcasts) to their subscribers. 

 

如果和模型关联的流,用stream_for
class CommentsChannel < ApplicationCable::Channel       
  def subscribed 
    post = Post.find(params[:id]) 
stream_for post 

   end

end 

向评论频道发送广播的方式如下:

CommentsChannel.broadcast_to(@post, @comment

 

发生命名的广播用stream_from ,见api 

流的方法:

 

5.2 Broadcasting

A broadcasting is a pub/sub link 

 CommentsChannel.broadcast_to(@post, @comment)

 

5.3 Subscriptions

This Connection is called a subscription. Incoming messages are then routed to these channel subscriptions based on an identifier sent by the cable consumer.

 

5.4 Passing Parameters to Channels

You can pass para from the client side to the server side when creating a subscriptin. For example:

 def subscribed
    stream_from "chat_#{params[:room]}"
  end

 

5.5 Rebroadcasting a Message

 A common use case is to rebroadcast a message sent by one client to any other connected clients.

   def receive(data)
   ActionCable.server.broadcast("chat_#{params[:room]}", data)
  end

 

The rebroadcast will be received by all connected clients, including the client that sent the message. Note that params are the same as they were when you subscribed to the channel.

 

 


一个基础功能演示的案例(不包含connection.rb)

https://www.cnblogs.com/chentianwei/p/9296887.html 

使用broadcast功能渲染首页部分页面:

3步骤:第一建立频道,第二发送这个频道的信息,第三选择接收信息的位置。

⚠️本案例没有涉及到用户对平淡的订阅和连接。即在assets/channels/XXX_channel.rb 中设置连接。

 


 

 https://github.com/rails/actioncable-examples

 完全的案例:

需要按照redis数据库。简介:Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。菜鸟教程(redis)

  下载的进程截图:
 

 

==> Downloading https://homebrew.bintray.com/bottles/redis-4.0.9.sierra.bottle.tar.gz

 

######################################################################## 100.0%
==> Pouring redis-4.0.9.sierra.bottle.tar.gz
==> Caveats
To have launchd start redis now and restart at login:
  brew services start redis
Or, if you don't want/need a background service you can just run:
  redis-server /usr/local/etc/redis.conf
==> Summary
🍺  /usr/local/Cellar/redis/4.0.9: 13 files, 2.8MB

 

 brew services start redis
==> Successfully started `redis` (label: homebrew.mxcl.redis)

 

启动:

$ redis-server

 查看是否启动 redis-cli ,这个命令打开终端。ping一下,pong就是成功安装了。

 


一个gem 'puma'一直安装不上,提示❌?怎么办?

后来查了很多资料,得到提示安装更高级的版本。

成功了,但是却要求低版本配置。

然后直接在gemfile.lock文件中找到puma修改版本到3.10.然后bundle install成功。

《Rails5敏捷开发》第406页,24.3:

bundle install以Gemfile.lock为准,安装指定的gem版本。哈哈哈哈哈。!!我竟然一直忽略了。 

 


 

看guide上的聊天窗口案例:fork下来后,看不懂:

 

  •  coffee.script不是很懂。javescript也会。
  •  明天再试试,已经看了一半了。对比着中文guide看。
4-9上午学完案例结构,下午学习频道模块的用法。

 

缺陷:不懂coffee.scripte.jiavascripte语法。 

对数据库的部署也不熟悉,看案例的很困难,这个action cable比较难。设计多个模块。 


 

6 案例

7 configuration

rails guide的没有更新需要配合git上的相同内容。

包括3个required configurations:

  1. a subscription adapter
  2. allowed request origins
  3. the cabel server URL(在client side 可选择的设置)

 

7.1 Subscription Adapter

什么是adapter?(9 Dependencies)

Action Cable提供了一个订阅adapter interface来处理它的内部发布和订阅。默认是async adapter(可用于开发和测试)。
adapter可以使用: Async, Redis, PostgreSQL adapter

 

 

默认ActionCable 会寻找配置文件config/cable.yml。这个文件必须指定an adapter为每个Rails环境。

development:
  adapter: redis
  url: redis://localhost:6379/1

test:
  adapter: async

production:
  adapter: redis
  url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>  #指向Redis server
  channel_prefix: Wechat_production    #用于避免频道名字重复,当使用相同的饿Redis server为多个applications时。

 

 

Allowed Request Origins

Action Cable将只接受那些指定源头specific origins的请求 。

具体见ActionCable的部署: https://www.cnblogs.com/chentianwei/p/9900012.html

 

Consumer Configuration

具体见ActionCable的部署: https://www.cnblogs.com/chentianwei/p/9900012.html

https://github.com/rails/rails/tree/master/actioncable

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2018-04-02 09:55  Mr-chen  阅读(613)  评论(0编辑  收藏  举报