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

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

  1. 实时更新数据,无需刷新:a,如何使用Turbolinks clearCache(), b Action Cable

    视频: https://gorails.com/episodes/how-to-use-turbolinks-clearCache?autoplay=1 用途: 更方便的实时从服务器更新局部网页,在这 ...

  2. 使用WebSocket实现服务端和客户端的通信

    开发中经常会有这样的使用场景.如某个用户在一个数据上做了xx操作, 与该数据相关的用户在线上的话,需要实时接收到一条信息. 这种可以使用WebSocket来实现. 另外,对于消息,可以定义一个类进行固 ...

  3. 刨根问底 HTTP 和 WebSocket 协议(上)

    HTTP vs WebSocket 那天和boss聊天,不经意间提到了Meteor,然后聊到了WebSocket,然后就有了以下对话,不得不说,看问题的方式不同,看到的东西也会大不相同. A:Mete ...

  4. websocket可以做什么

    本篇介绍的是websocket,但是并不介绍它的协议格式,一般能看明白http头也能明白websocket在协议切换前的协商,能看明白IP报头也就对websocket在协议切换后通讯格式不陌生.web ...

  5. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...

  6. Web APi之控制器选择Action方法过程(九)

    前言 前面我们叙述了关于控制器创建的详细过程,在前面完成了对控制器的激活之后,就是根据控制器信息来查找匹配的Action方法,这就是本节要讲的内容.当请求过来时首先经过宿主处理管道然后进入Web AP ...

  7. 借助node实战WebSocket

    一.WebSocket概述 WebSocket协议,是建立在TCP协议上的,而非HTTP协议. 如下: ws://127.0.0.1或wss://127.0.0.1就是WebSocket请求. 注:w ...

  8. Struts2 源码分析——Action代理类的工作

    章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...

  9. Struts2 源码分析——调结者(Dispatcher)之执行action

    章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...

随机推荐

  1. python3.4学习笔记(十一) 列表、数组实例

    python3.4学习笔记(十一) 列表.数组实例 #python列表,数组类型要相同,python不需要指定数据类型,可以把各种类型打包进去#python列表可以包含整数,浮点数,字符串,对象#创建 ...

  2. vue v-for 和 v-if 、v-else一起使用造成的bug

    现象:导致v-else 执行v-for的length次数, 从现象看应该v-for先解析,然后将v-if和v-else包在其中 解决方案:很简单,tempalte 将v-if v-else 隔离到最外 ...

  3. Python Web学习笔记之TCP/IP、Http、Socket的区别

    经常在笔试.面试或者工作的时候听到这些协议,虽然以前没怎么涉及过,但至少知道这些是和网络编程密不可分的知识,作为一个客户端开发程序员,如果可以懂得网络编程的话,他的作用和能力肯定会提升一个档次.原因很 ...

  4. 20165310 java_blog_week4

    2165310 <Java程序设计>第4周学习总结 教材学习内容总结 继承(extends) 同一个包内:继承除了private修饰的变量与方法 不同包内:不继承private和友好,继承 ...

  5. 关于STM32外接4—16MHz晶振主频处理方法

    由于STM32F10x库官方采用的是默认的外接8MHz晶振,因此造成很多用户也采用了8MHz的晶振,但是,8MHz的晶振不是必须的,其他频点的晶振也是可行的,只需要在库中做相应的修改就行.    在论 ...

  6. devicePixelRatio手机图片模糊的原因

    一.移动设备图片模糊问题 手机上图片模糊问题原因就是一个像素在电脑上和手机上代表的实际像素的不同. 我们在样式表中使用的px(独立像素)单位其实并不一定代表着实际的一个像素(物理像素),这还要看硬件的 ...

  7. 【运行错误】Uncaught DOMException: Blocked a frame with origin "null" from accessing a cross-origin frame.

    代码如下: <html> <head> <script> /*window.frames[]可以通过下标或名称访问单独的frame*/ window.onload= ...

  8. Python3基础 file for+list 读取txt文本 并 一行一行的输出(低效率)

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  9. linux内核启动参数解析及添加

    1.环境: ubuntu16.04 Linux jello 4.4.0-89-generic #112-Ubuntu SMP Mon Jul 31 19:38:41 UTC 2017 x86_64 x ...

  10. linux指定某用户某组挂载外接硬盘以便操作硬盘

    一.环境:发行版本:ubuntu 14.04 64bit 二.获取要指定的用户及组id 使用id命令 (笔者获取的uid和gid都为1000) 三.获取识别的硬盘路径 sudo fdisk -l  ( ...