<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # 5. 用 tubesock 在 Rails 實現聊天室 #### 1. 介紹 前篇文章介紹了如何實現一個簡易的聊天室,有時候,我們在rails應用中也是需要使用websocket的功能,比如,消息的通知,一些數據狀態的通知等,所以這篇來介紹下如何簡單地實現這個功能。 #### 2. rack hijack 這篇文章主要介紹的是一個比較重要的概念,它是rack hijack。hijack是rack在1.5.0之后才支持,它出現的目的是為了能在rack層次對socket連接進行操作。能對底層的socket進行操作,也就能使用websocket。puma,unicorn等服務器都有它的實現。 新建一個文件叫hijack.ru,內容如下: ``` use Rack::Lint use Rack::ContentLength use Rack::ContentType, "text/plain" class DieIfUsed def each abort "body.each called after response hijack\n" end def close abort "body.close called after response hijack\n" end end run lambda { |env| case env["PATH_INFO"] when "/hijack_req" if env["rack.hijack?"] io = env["rack.hijack"].call if io.respond_to?(:read_nonblock) && env["rack.hijack_io"].respond_to?(:read_nonblock) # exercise both, since we Rack::Lint may use different objects env["rack.hijack_io"].write("HTTP/1.0 200 OK\r\n\r\n") io.write("request.hijacked") io.close return [ 500, {}, DieIfUsed.new ] end end [ 500, {}, [ "hijack BAD\n" ] ] when "/hijack_res" r = "response.hijacked" [ 200, { "Content-Length" => r.bytesize.to_s, "rack.hijack" => proc do |io| io.write(r) io.close end }, DieIfUsed.new ] end } ``` 其中`env['rack.hijack'].call`就是返回socket的文件描述符的對象,之后可以對這個對象進行像socket那樣的操作,比如`io.write("request.hijacked")`,就是返回“request.hijacked”。 使用下面的指令運行這段代碼: ``` $ unicorn hijack I, [2016-04-12T15:44:53.197379 #18197] INFO -- : listening on addr=0.0.0.0:8080 fd=9 I, [2016-04-12T15:44:53.197564 #18197] INFO -- : worker=0 spawning... I, [2016-04-12T15:44:53.201453 #18197] INFO -- : master process ready I, [2016-04-12T15:44:53.203755 #18226] INFO -- : worker=0 spawned pid=18226 I, [2016-04-12T15:44:53.204682 #18226] INFO -- : Refreshing Gem list I, [2016-04-12T15:44:53.315295 #18226] INFO -- : worker=0 ready ``` 監聽在8080端口,可以用瀏覽器訪問。 ![](https://box.kancloud.cn/dd02efb4fcc4ce82ae9bdff00e762824_394x129.png) puma,unicorn等服務器對hijack的實現是很簡單的,本來他們就是對socket的操作,現在只不過是提供了一個接口,把它放到請求的全局變量中罷了,還增加了一些狀態判斷。主要是這三個變量`env['rack.hijack']`,`env['rack.hijack?']`,`env['rack.hijack_io']`。 #### 3. Tubesock [tubesock](https://github.com/ngauthier/tubesock)是一個gem,它就是對上面的`rack hijack`進行封裝,從而能實現websocket功能,它不僅能在rack中實現,也能在rails中的controller使用。 現在我們來在rails中結合redis的pub/sub功能實現一個聊天室功能。 首先安裝,我們使用puma作為服務器。 在Gemfile中添加下面幾行。 ``` gem 'puma' gem 'redis-rails' gem 'tubesock' ``` 添加`app/controllers/chat_controller.rb`文件,內容如下: ``` class ChatController < ApplicationController include Tubesock::Hijack def chat hijack do |tubesock| redis_thread = Thread.new do Redis.new.subscribe "chat" do |on| on.message do |channel, message| tubesock.send_data message end end end tubesock.onmessage do |m| Redis.new.publish "chat", m end tubesock.onclose do redis_thread.kill end end end end ``` 在`config/routes.rb`中添加路由。 ``` Rails.application.routes.draw do get "/chat", to: "chat#chat" end ``` 分別添加view和js。 ``` <h1>Tubesock Chat</h1> <form class="chat"> <input placeholder="hello world" autofocus> </form> ``` ``` $ -> socket = new WebSocket "ws://#{window.location.host}/chat" socket.onmessage = (event) -> if event.data.length $("#output").append "#{event.data}<br>" $("body").on "submit", "form.chat", (event) -> event.preventDefault() $input = $(this).find("input") socket.send $input.val() $input.val(null) ``` 對上面的代碼進行解析: 假如有一個瀏覽器客戶端打開了,就會運行`new WebSocket "ws://#{window.location.host}/chat"`。 這樣就到了`ChatController`中的`chat`方法。 執行了下面的語句: ``` redis_thread = Thread.new do Redis.new.subscribe "chat" do |on| on.message do |channel, message| tubesock.send_data message end end end ``` 將會開啟一個新的線程,并會用Redis去訂閱一個新的頻道`chat`,進入到`subscribe`方法中,`tubesock.send_data message`表示一旦有消息過來就立即用tubesock這個socket把數據返回給客戶端瀏覽器。 ``` tubesock.onmessage do |m| Redis.new.publish "chat", m end ``` 上面的代碼表示一旦服務器接收到客戶端瀏覽器的消息之后的動作,比如說,在聊天界面輸入消息內容。接收到消息之后就立即發送到上面所說的`chat`通道,上面Redis中的`subscribe`動作就會被觸發。因為所有的客戶端一連上服務器就會執行Redis的`subscribe`功能,也就是說所有瀏覽器客戶端都會觸發`subscribe`里的動作,就會接收到服務器端的推送消息,這也正是聊天界面的效果。 效果如下: ![](https://box.kancloud.cn/1443db8d973f9b06d1d78f061c361814_801x420.png) 本篇完結。 下一篇:[websocket之message\_bus(六)](http://www.rails365.net/articles/websocket-message-bus-liu)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看