ASP.NET SignalR 2.0: SignalR 소개

등록일시: 2014-01-06 08:00,  수정일시: 2015-07-25 16:02
조회수: 8,286
이 문서는 ASP.NET SignalR 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

본문에서는 SignalR이 무엇인지, 그리고 SignalR을 만들기 위해서 설계된 몇 가지 처리 방식들을 살펴봅니다.

SignalR이란?

ASP.NET SignalR은 ASP.NET 개발자들을 위한 라이브러리로, 응용 프로그램에 실시간 웹 기능을 구현하기 위해 필요한 과정들을 단순하게 만들어줍니다. 여기에서 말하는 실시간 웹 기능이란 클라이언트가 새로운 데이터를 요청할 때까지 서버가 마냥 기다리기만 하는 것이 아니라, 데이터가 준비되는 즉시 서버 코드에서 현재 연결되어 있는 클라이언트들에게 콘텐트를 전달(Push)할 수 있는 능력을 의미합니다.

SignalR은 ASP.NET 응용 프로그램에 구현하는 모든 유형의 실시간 웹 기능에 적용할 수 있습니다. 대부분 예제로 챗 응용 프로그램이 많이 사용되는 편이지만, SignalR이 실제로 처리할 수 있는 작업은 그보다 훨씬 광범위합니다. 사용자가 새로운 데이터를 조회하기 위해서 자주 갱신하는 웹 페이지나, 신규 데이터 조회를 목적으로 롱 폴링(Long Polling)을 구현한 페이지라면, 언제라도 SignalR의 적용을 고려해볼만 합니다. 가령, 대시보드나 모니터링 응용 프로그램, 협업 응용 프로그램 (동시에 문서를 편집하는), 작업 진행 현황 갱신 프로그램, 그리고 실시간 양식 등이 그 좋은 예입니다.

그 뿐만 아니라 실시간 게임처럼 높은 빈도로 서버의 정보가 갱신돼야 하는 새로운 형태의 웹 응용 프로그램에도 SignalR을 완벽하게 적용할 수 있습니다. 그 실제 사례를 살펴보려면 멋진 ShootR 게임을 즐겨보시기 바랍니다.

SignalR은 서버 측 .NET 코드에서 클라이언트 브라우저의 (또는 다른 클라이언트 플랫폼의) 자바스크립트 함수를 호출하기 위한, 서버-to-클라이언트 윈격 프로시저 호출(RPC, Remote Procedure Calls)을 생성할 수 있는 간결한 API를 제공해줍니다. 또한, 연결 관리(연결 및 연결 해제 이벤트 등)나 연결 그룹핑을 위한 API도 포함하고 있습니다.

Invoking methods with SignalR

SignalR은 자동으로 연결을 관리해주고, 연결되어 있는 모든 클라이언트들에게 마치 챗 룸처럼 동시에 메시지를 브로드케스팅 할 수 있게 해줍니다. 물론, 특정 클라이언트들에게만 메시지를 전송할 수도 있습니다. 매번 통신이 이루어질 때마다 다시 연결되는 클래식 HTTP 연결과는 달리, SignalR의 클라이언트와 서버 간 연결은 지속적입니다.

SignalR은 보편적인 오늘날 웹의 요청-응답 모델 대신, 서버 코드가 원격 프로시저 호출(RPC, Remote Procedure Calls)을 통해서 브라우저의 클라이언트 코드를 호출할 수 있는 "서버 푸시" 기능을 지원해줍니다.

SignalR 응용 프로그램은 서비스 버스(Service Bus)나 SQL 서버, 또는 Redis를 이용해서 수 천의 클라이언트들을 대상으로 확장할 수 있습니다.

마지막으로, SignalR은 GitHub를 통해서 접근할 수 있는 오픈-소스입니다.

SignalR과 WebSocket

SignalR은 최대한 새로운 WebSocket 전송방식을 사용하려고 시도하지만, 불가능한 경우에는 그 대안으로 기존 전송방식들 중 하나를 사용하도록 구현되어 있습니다. 물론 여러분이 원한다면 직접 WebSocket을 사용하는 응용 프로그램을 작성할 수도 있겠지만, SignalR에는 직접 구현해야 될 다양한 부가 기능들이 이미 구현되어 있습니다. 더 중요한 사실은 구형 클라이언트들을 위한 코드를 별도로 작성해야하는 부담 없이도 WebSocket의 이점을 활용하는 응용 프로그램 코드를 작성할 수 있다는 점입니다. 또한, SignalR은 기반 전송방식들에 대한 변경 사항들을 지원하기 위해서 지속적으로 업데이트 될 예정이므로, WebSocket의 버전과 무관하게 응용 프로그램에 일관된 인터페이스를 제공해줄 수 있으므로 WebSocket의 업데이트에 대한 고민으로부터 자유롭습니다.

물론, 직접 WebSocket을 사용한 솔루션을 작성할 수도 있겠지만 SignalR은 다른 전송방식에 대한 대안이나 WebSocket의 구현 변경에 따른 응용 프로그램의 보완 같은 여러분이 직접 처리해야 할 모든 기능들을 자체적으로 제공해줍니다.

전송방식들(Transports)과 그 대안(Fallbacks)

SignalR은 클라이언트와 서버 간의 실시간 작업을 수행하기 위해 필요한 몇 가지 전송방식을 추상화시킨 것입니다. 즉, SignalR의 연결은 먼저 HTTP 형태로 시작된 다음, 만약 가능하다면 WebSocket 연결로 승격됩니다. SignalR에 가장 이상적인 전송방식은 WebSocket 방식으로, 서버의 메모리를 가장 효율적으로 사용하고, 대기 시간(Latency)이 짧으며, 가장 근본적인(Underlying) 기능들을 (클라이언트와 서버 간의 전이중 통신 같은) 제공해주기 때문입니다. 그 반면 가장 엄격한 요구 조건을 갖고 있기도 합니다. 즉, WebSocket은 서버가 Windows Server 2012나 Windows 8이어야 하고 .NET 프레임워크 4.5를 사용해야 합니다. 만약, 이런 조건들을 만족하지 못하면 SignalR은 연결 시 다른 전송방식을 사용하려고 시도하게 됩니다.

HTML 5 전송방식

이 유형의 전송방식들은 HTML 5에 대한 지원 정도에 따라 영향을 받습니다. 만약, 클라이언트 브라우저가 HTML 5 표준을 지원하지 않는다면 오래된 전송방식이 사용될 것입니다.

  • WebSocket (서버와 브라우저 양쪽 모두 Websocket을 지원하는 경우에 선택됩니다). WebSocket은 클라이언트와 서버 간에 지속적인 진정한 양방향 연결을 설정할 수 있는 유일한 전송방식입니다. 반면, WebSocket은 엄격한 요구 사항을 갖고 있기 때문, 이를 만족하는 브라우저들은 오직 최신 버전의 마이크로소프트 인터넷 익스플로러, 구글 크롬, 그리고 모질라 파이어폭스뿐이며, 오페라나 사파리 같은 다른 브라우저들은 일부분만 구현되어 있습니다.
  • Server Sent Events, EventSource라고 부르기도 합니다. (브라우저가 Server Sent Events를 지원하는 경우에 선택되며, 인터넷 익스플로러를 제외한 모든 브라우저가 기본적으로 지원합니다.)

코멧(Comet) 전송방식

다음 전송방식들은 코멧 웹 응용 프로그램 모델을 그 기반으로 하고 있습니다. 이 모델에서 브라우저를 비롯한 기타 클라이언트들은, 클라이언트가 명시적으로 요청하지 않더라도 서버가 자체적으로 클라이언트로 데이터를 푸시하는데 사용하기 위한 용도의 장기 HTTP 요청을 유지합니다.

  • 영구 프레임(Forever Frame) (인터넷 익스플로러 전용). 영구 프레임 전송방식은 완료되지 않는 요청을 서버의 종점으로 보내는 숨겨진 IFrame을 생성합니다. 그러면, 서버는 즉시 실행되는 스크립트를 지속적으로 클라이언트로 전송하는 방식으로 서버에서 클라이언트로 향하는 단방향 실시간 연결을 제공해줍니다. 반면, 클라이언트에서 서버로 향하는 연결은 서버에서 클라이언트로 향하는 연결과는 별개의 연결을 사용하되, 표준 HTML 요청과 유사하게 전송이 필요한 각각의 데이터 조각마다 새로운 연결이 생성됩니다.
  • Ajax 롱 폴링(Long Polling). 롱 폴링은 지속적인 연결을 생성하는 대신, 서버가 응답할 때까지만 열려 있는 요청을 서버에 보내고, 서버가 응답한 시점에 연결을 닫습니다. 그리고, 그 즉시 새로운 연결이 요청됩니다. 이 방식은 연결이 재설정될 때 다소 지연이 존재할 수도 있습니다.

어떤 환경에서 어떤 전송방식이 지원되는지에 대한 더 자세한 정보는 지원되는 플랫폼 문서를 참고하시기 바랍니다.

전송방식 선택 절차

다음 목록은 SignalR이 사용할 전송방식을 결정하는데 사용되는 과정을 보여줍니다.

  1. 브라우저가 인터넷 익스플로러 8이나 그 이하 버전이라면 롱 폴링이 사용됩니다.

  2. JSONP가 구성되어 있다면 (연결이 시작될 때, jsonp 매개변수가 true로 설정된 경우), 롱 폴링이 사용됩니다.

  3. 크로스-도메인 연결이 만들어졌고 (SignalR의 종점이 호스팅 페이지와 다른 경우), 다음 조건들을 모두 만족하면 WebSocket이 사용됩니다:

    • 클라이언트가 CORS(Cross-Origin Resource Sharing)를 지원합니다. 클라이언트들의 CORS 지원 정보는 caniuse.com의 CORS를 참고하시기 바랍니다.

    • 클라이언트가 WebSocket을 지원합니다.

    • 서버가 WebSocket을 지원합니다.

    이 조건들 중 한 가지라도 만족하지 않으면 롱 폴링이 사용됩니다. 크로스 도메인 연결에 관한 더 자세한 정보는 How to establish a cross-domain connection 문서를 참고하시기 바랍니다.

  4. JSONP가 구성되지 않았고, 크로스-도메인 연결도 아니며, 클라이언트와 서버가 모두 WebSocket을 지원하면 WebSocket이 사용됩니다.

  5. 클라이언트나 서버 중 하나라도 WebSocket을 지원하지 않으면, 가능한 경우 Server Sent Events가 사용됩니다.

  6. 그러나, Server Sent Events을 사용할 수 없다면 영구 프레임이 시도됩니다.

  7. 영구 프레임이 실패하면 롱 폴링이 사용됩니다.

전송방식 모니터링

허브의 로깅을 활성화시키면 브라우저의 콘솔 윈도우를 통해서 응용 프로그램에서 어떤 전송방식이 사용되는지 확인할 수 있습니다.

브라우저에서 허브 이벤트들에 대한 로깅을 활성화시키려면 다음 명령을 클라이언트 응용 프로그램에 추가합니다.

$.connection.hub.logging = true;
  • 인터넷 익스플로러에서 F12를 눌러서 개발자 도구를 열고 콘솔(Console) 탭을 엽니다.

    Console in Microsoft Internet Explorer

  • 크롬에서는 Ctrl+Shift+J를 눌러서 콘솔을 엽니다.

    Console in Google Chrome

로깅이 활성화된 상태에서 콘솔을 열면, SignalR이 어떤 전송방식을 사용하고 있는지 확인할 수 있습니다.

Console in Internet Explorer showing WebSocket transport

전송방식 지정하기

전송방식이 협상되는 과정 역시 클라이언트 및 서버의 자원과 시간을 일정 부분 잡아먹기 마련입니다. 만약, 클라이언트의 기능을 미리 알고 있다면 클라이언트 연결이 시작될 때 아예 전송방식을 지정할 수도 있습니다. 다음 코드 조각은 해당 클라이언트가 다른 프로토콜들을 지원하지 않는 것을 알고 있는 경우, Ajax 롱 폴링 전송방식을 사용해서 연결을 시작하는 방법을 보여줍니다.

connection.start({ transport: 'longPolling' });

만약, 클라이언트가 특정 전송방식을 지정한 순서대로 시도해보기를 바란다면 대안 방식들의 순서를 지정할 수도 있습니다. 다음 코드 조각은 WebSocket을 먼저 시도해보고, 만약 실패하면 바로 롱 폴링 방식을 사용하도록 지정합니다.

connection.start({ transport: ['webSockets','longPolling'] });

전송방식을 지정하기 위한 문자열 상수들은 다음과 같습니다:

  • webSockets

  • forverFrame

  • serverSentEvents

  • longPolling

연결 및 허브

SignalR의 API에는 클라이언트와 서버 간의 통신을 위한 두 가지 모델이 존재하는데, 지속적인 연결(Persistent Connections)과 허브(Hubs)가 바로 그것입니다.

연결은 단일 수신자, 그룹화된 수신자, 또는 브로드캐스트 메시지 전송을 위한 단순한 종점을 나타냅니다. 지속적인 연결 API들은 (.NET 코드 상에서는 PersistentConnection 클래스로 대표됩니다) 개발자가 SignalR이 노출하는 저-수준 통신 프로토콜에 직접 접근할 수 있게 해줍니다. 연결 통신 모델을 사용하는 작업은 WCF(Windows Communication Foundation) 같은 연결 기반 API들을 사용해온 개발자들에게는 매우 익숙한 작업일 것입니다.

허브는 연결 API의 상위에 자리한, 보다 고-수준의 파이프라인으로 클라이언트나 서버가 서로 상대방의 메서드들을 직접 호출할 수 있게 만들어줍니다. SignalR이 머신 간의 경계를 넘나드는 호출의 분배를 마치 마법처럼 처리해주기 때문에, 클라이언트에서 서버의 메서드를 로컬 메서드처럼 손쉽게 호출할 수 있으며, 그 반대의 경우도 역시 마찬가지 입니다. 허브 통신 모델을 사용하는 작업은 .NET 리모팅 같은 원격 호출 API들을 사용해온 개발자들에게는 매우 익숙한 작업일 것입니다. 허브를 사용하면 메서드에 강력한 형식의 매개변수를 전달할 수 있으므로, 모델 바인딩이 가능해집니다.

아키텍처 다이어그램

다음 다이어그램은 허브, 지속적인 연결, 그리고 전송방식들과 관련된 기반 기술들의 관계를 보여줍니다.

SignalR Architecture Diagram showing APIs, transports, and clients

허브의 동작 방식

서버 측 코드에서 클라이언트의 메서드를 호출하면, 활성화된 전송방식을 통해서 호출된 메서드의 이름과 매개변수들이 포함된 패킷이 전송됩니다 (개체가 메서드 매개변수로 전송되면, 이는 JSON으로 직렬화됩니다). 그러면, 클라이언트가 클라이언트 측의 코드에 정의된 메서드들 중에서 이름이 일치하는 메서드를 찾습니다. 만약 일치하는 메서드가 존재하면 해당 클라이언트 메서드가 역직렬화된 매개변수 데이터를 사용해서 실행됩니다.

피들러 등의 이용하면 메서드 호출을 모니터할 수 있습니다. 다음 이미지는 SignalR 서버에서 웹 브라우저 클라이언트로 전송된 메서드 호출을 피들러의 Logs 패인을 통해서 살펴본 모습입니다. 이 메서드 호출은 MoveShapeHub라는 허브에서 전송되었으며, updateShape라는 메서드가 실행되고 있는 것을 알 수 있습니다.

View of Fiddler log showing SignalR traffic

이 예제에서 허브의 이름은 H 매개변수로 식별할 수 있고, 메서드의 이름은 M 매개변수로 식별할 수 있으며, 메서드로 전송된 데이터는 A 매개변수로 식별할 수 있습니다. 이 메시지를 만들어낸 응용 프로그램은 ASP.NET SignalR 2.0: 자습서: SignalR 2.0을 이용한 고속 실시간 기능 자습서를 통해서 살펴볼 수 있습니다.

통신 모델 선택하기

대부분의 응용 프로그램들은 허브 API를 사용하게 될 것입니다. 반면, 연결 API는 다음과 같은 상황에서 사용될 수 있습니다:

  • 전송된 실제 메시지의 형식이 지정돼야 하는 경우.
  • 개발자가 원격 호출 모델보다 메시징 및 분배 모델 작업을 선호하는 경우.
  • 메시징 모델을 사용하는 기존 응용 프로그램을 SignalR을 사용해서 포팅하는 경우.