Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby의 푸시 및 Pub/Sub

Action Cable과 같은 라이브러리를 사용하면 Rails에서 실시간 기능을 구축하는 것이 훨씬 쉬워졌습니다. AppSignal Academy의 이번 에피소드에서는 실시간 업데이트에 대해 알아보고 내부에서 어떻게 작동하는지 살펴보기 위해 최소한의 WebSocket 서버를 구축하는 방법을 살펴보겠습니다.

우리는 푸시하는 애플리케이션을 구축할 것입니다. 데이터 및 Pub/Sub 사용 WebSocket을 통해 . 코드를 시작하기 전에 먼저 이 세 가지 개념이 의미하는 바를 잠시 살펴보겠습니다.

  • 푸시 수신기가 해당 데이터에 대해 폴링하도록 하는 대신 수신기에 데이터를 푸시하는 것을 말합니다. 주가, 채팅 애플리케이션 또는 운영 콘솔과 같은 실시간 업데이트가 있어야 합니다.

  • 게시/구독 또는 게시 및 구독은 1990년대 월스트리트에서 TIBCO에서 인기를 끌었던 데이터를 푸시하기 위한 상호 작용 모델입니다. 수신자는 주제를 구독하고 게시자가 해당 주제에 데이터를 푸시할 때까지 기다립니다. 일부 간단한 구현에서는 제목에 와일드카드 대신 명명된 채널만 사용하지만 게시된 메시지를 수신기와 일치시키기 위해 와일드카드 패턴 일치를 포함하는 것이 일반적입니다. 저는 초기에 TIBCO에서 일을 시작했기 때문에 와일드카드 패턴 매칭의 유연성이 마음에 듭니다.

  • 웹소켓 일반적으로 웹 브라우저와 응용 프로그램 간에 데이터를 교환하기 위한 프로토콜입니다. HTTP 연결이 WebSocket 연결로 업그레이드되면 두 끝점 간에 양방향으로 데이터를 보낼 수 있습니다. WebSocket은 애플리케이션에서 브라우저로 데이터를 푸시할 수 있습니다. 또한 브라우저의 JavaScript 코드에서 애플리케이션으로 데이터를 다시 보내기 위한 POST 또는 PUT 이외의 다른 메커니즘을 제공합니다. 꽤 멋지죠?

언더 후드

WebSocket 서버의 예가 어떻게 작동하는지 살펴보겠습니다. 브라우저에서 클라이언트는 JavaScript 코드를 사용하여 서버에 WebSocket 연결을 시도합니다.

var sock = new WebSocket("ws://" + document.URL.split("/")[2] + "/upgrade");

서버는 업그레이드가 요청되었다는 표시가 있는 HTTP 요청을 수신합니다. 일반적으로 서버는 응용 프로그램이 업그레이드 여부를 결정할 수 있도록 합니다. 어떻게 하는지는 앱에 제공되는 API에 따라 다릅니다. Rack을 지원하는 서버는 소켓을 하이재킹하고 개발자가 모든 프로토콜 세부 사항을 처리하도록 하거나 제안된 PR에 따라 업그레이드에 대한 응답으로 충분하도록 하는 옵션을 제공합니다.

업그레이드는 서버와 클라이언트 간의 일련의 교환입니다. 모든 브라우저와 일부 서버 젬은 이러한 세부 정보를 숨깁니다. 연결이 설정되면 WebSocket 프로토콜에 따라 메시지를 교환할 수 있습니다.

내부의 마법은 인코딩, 디코딩 및 메시지 교환 프로토콜을 처리합니다. 메시지는 SHA1을 사용하여 암호화된 후행 페이로드가 있는 고정 너비 이진 구조입니다. WebSocket 프로토콜에는 ping/pong 하트비트 및 메시지 교환 열기 및 닫기와 같은 여러 메시지 유형 및 교환이 포함됩니다. 이것이 서버가 연결 하이재킹 방식을 사용하지 않음으로써 수행하는 마법입니다.

다이빙 인

모든 수신 클라이언트에 현재 시간을 게시하기 위해 시작된 시계 스레드의 예를 사용합니다. 속도가 빠르고 복잡성을 최소화하기 때문에 Agoo를 사용하여 서버를 구축합니다.

HTML 페이지에 현재 시간을 표시하여 클라이언트로서 일부 JavaScript로 시작하겠습니다. 새 WebSocket 생성 후 onopen 상태 HTML 요소를 변경하는 콜백이 설정됩니다. onmessage 콜백 업데이트 onmessage HTML 요소. 콜백은 발행 및 구독 교환과 같은 비동기 호출로 작업할 때 일반적인 디자인 패턴입니다.

<!-- websocket.html -->
<html>
  <body>
    <p id="status">...</p>
    <p id="message">... waiting ...</p>
 
    <script type="text/javascript">
      var sock = new WebSocket(
        "ws://" + document.URL.split("/")[2] + "/upgrade"
      );
      sock.onopen = function () {
        document.getElementById("status").textContent = "connected";
      };
      sock.onmessage = function (msg) {
        document.getElementById("message").textContent = msg.data;
      };
    </script>
  </body>
</html>

클라이언트가 완료되면 Rack API를 사용하여 Ruby 애플리케이션인 서버를 구현해 보겠습니다. Clock 클래스 자체는 /upgrade의 모든 HTTP 요청에 대한 핸들러가 됩니다. 길. 업그레이드 요청인 경우 HTTP 상태 코드 200과 함께 Success를 반환하고, 그렇지 않으면 Page Not Found에 대해 404를 반환합니다. #call의 유일한 다른 단계 메소드는 WebSocket 핸들러의 할당입니다.

class Clock
  def self.call(env)
    unless env['rack.upgrade?'].nil?
      env['rack.upgrade'] = Clock
      [ 200, { }, [ ] ]
    else
      [ 404, { }, [ ] ]
    end
  end
end

API는 콜백을 기반으로 합니다. 서버에 대해 신경을 쓰는 유일한 콜백은 #on_open입니다. "시간" 주제에 대한 구독을 생성할 수 있는 콜백. 메시지는 주제 또는 주제별로 식별된 채널을 통해 교환됩니다. #on_open 웹 소켓 연결이 설정되면 호출됩니다.

class Clock
  # ...
 
  def self.on_open(client)
    client.subscribe('time')
  end
end

이제 매초마다 시간을 게시하는 스레드로 게시를 시작하겠습니다. Agoo.publish 호출 "시간" 제목에 메시지를 보내면 모든 구독자가 메시지를 받습니다. 서버는 구독 및 연결을 추적하고 HTML 요소를 업데이트하는 JavaScript 클라이언트에 메시지를 전달합니다.

require 'agoo'
 
Thread.new {
  loop do
    now = Time.now
    Agoo.publish('time', "%02d:%02d:%02d" % [now.hour, now.min, now.sec])
    sleep(1)
  end
}

필요한 유일한 다른 코드는 서버를 초기화하고 시작하는 코드입니다. Agoo::Server.handle(:GET, '/upgrade', Clock) 호출 /upgrade에서 HTTP GET 요청을 수신하도록 서버에 지시합니다. URL 경로 및 해당 요청을 Clock에 전달 수업. 이를 통해 성능과 유연성을 향상시키기 위해 Ruby 외부에서 라우팅을 수행할 수 있습니다.

Agoo::Server.init(6464, '.', thread_count: 0)
Agoo::Server.handle(:GET, '/upgrade', Clock)
Agoo::Server.start

거의 다 왔습니다. 이 명령어로 서버를 실행하세요.

$ ruby pubsub.rb

서버가 실행 중이고 포트 6464에서 수신 대기 중임을 나타내는 다음과 같은 로그 항목이 나타나야 합니다.

I 2018/08/14 19:49:45.170618000 INFO: Agoo 2.5.0 with pid 40366 is listening on https://:6464.

작동 여부 확인 시간

https://localhost:6464/websocket.html을 열어보자. 연결이 설정되면 초기 깜박임 후 연결 상태와 시간이 표시되어야 합니다. 시계가 똑딱 거리면서 시간이 1초마다 증가합니다.

connected

19:50:12

게시 및 구독 웹 애플리케이션을 만드신 것을 축하합니다;-)

오늘 에피소드에서는 WebSocket을 사용하는 방법을 살펴보았습니다. SSE(서버 측 이벤트)는 동일한 작업을 수행하는 또 다른 옵션을 제공하며 전체 소스 코드 예제에 SSE를 포함했습니다. 더 자세히 알고 싶다면 우리가 사용한 Agoo 서버나 Iodine WebSocket 서버를 살펴보세요.

질문이나 의견이 있으시면 주저하지 말고 @AppSignal로 연락해 주십시오.