Real time Apps #6 - SignalR over WebSocket
이 포스트에 있는 내용이 언제나 확실한 정답은 아닙니다. 진실이라고 생각해 왔던 전제가 시간의 지남에 따라 들어나지 않았던 다른 이면 때문에 좋은 방향으로 이끌어 낼 수 있는 역할로 변환 되는게 역사적으로도 많은 증명 있었습니다. 그렇지만 저는 현재 상황에서 최선의 답을 찾고자 노력하였으며 이 글을 읽는 다른 분들에게 다음 길을 갈 수 있도록 도와주는 디딤돌이 되고자 노력하고자 포스팅을 통해 공유하고자 하는 것입니다. 그리고 프로그래머라는 타이틀을 달고 살아야 한다면 "왜"라는 의문을 항상 가지고 다니면서 자신의 위치에 안주하지 않고 항상 노력하는 모습으로 살아 가고자 합니다. 언제든 지적이나 오류가 있으면 피드백 부탁 드리겠습니다. ing™ |
ASP.NET SignalR 소개
'http://signalr.net/' 에서는 SignalR을 아래와 같이 소개하고 있다.
ASP.NET SignalR is a new library for ASP.NET developers that makes it incredibly simple to add real-time web functionality to your applications. What is "real-time web" functionality? It's the ability to have your server-side code push content to the connected clients as it happens, in real-time. |
말하자면 ASP.NET SignalR은 어플리케이션에 매우 간단하게 실시간 웹 기능을 만들 수 있도록 해주는 ASP.NET 개발자를 위한 라이브러리이다. 실시간 웹 기능이란? 서버 사이드에서 실시간으로 일어난 일을 연결된 클라이언트에게 내용을 능동적으로 전달하는 것이다. 즉 SignalR은 즉각적인 사용자와의 상호작용과 실시간 데이터 갱신이 필요한 웹 응용 프로그램 개발을 지원하기 위한 라이브러리이다. 예로 대시보드에서 다른 시스템을 모니터링을 할 때 즉각적으로 변하는 값을 브라우저의 그래프에 즉시 반영하는 시나리오에 적합하다.
SignalR은 실시간 응용 프로그램 개발 과정을 WebSocket를 이용한 개발보다 더 단순화시켜 줍니다. ASP.NET의 서버 라이브러리와 SignalR에서 같이 제공되는 자바스크립트 클라이언트 라이브러리를 통해서 WebSocket을 직접 사용하는 것보다 더 추상화 시킨 라이브러리이다. '그림8'과 같이 추상화된 라이브러리로 API를 사용하면 WebSocket을 지원하는 클라이언트 브라우저에서는 WebSocket를 통해 서버와 통신하고, 그렇지 않을 경우에는 대체되는 통신 기법으로 바뀌어 서버와의 통신을 유지하도록 해준다.
[그림11] SignalR 통신
본격적으로 SignalR을 살펴 보기 전에 시스템적인 요구 사항을 점검해 보도록 하자 서버 시스템 요구 사항 지원되는 서버 리스트
지원되는 IIS (웹 컨테이너)
클라이언트 요구 사항 브라우저 버전
브라우저에서 jQuery version 1.6.4, 1.7.2, 1.8.2, or 1.9.1 자신의 브라우저가 지원이 되는지 알아 볼 수 있는 사이트가 있으니 자세한 정보는 이곳에서 알아 보기 바란다. http://testswarm.signalr.net/user/signalr |
[그림12] Nuget Package Manager에서 SignalR을 검색한 결과 화면
이제 개발에 필요한 라이브러리를 추가 하자. Nuget을 통해 SignalR로 검색하면 '그림12'와 같은 화면을 확인할 수 있을 것이다. 이 중에서 'Microsoft ASP.NET SignalR'을 선택하고 설치하면 자동으로 Visual Studio에 필요한 DLL들이 추가가 될 것이다. 그런다음 Global.asax.cs 파일을 열어서 '코드12'와 같이 'RouteTable.Routes.MapHubs();'를 Application_Start에 추가 하고 저장 후 닫아 버리자
protected void Application_Start() { // SignalR 세팅 RouteTable.Routes.MapHubs(); ... (기존 코드)
}
[코드12] Global.asax.cs 에 추가된 초기화 코드
위 코드는 SignalR이 ASP.NET에서 초기화가 되도록 세팅하는 것이며 Global.asax.cx의 Application_Start 메소드는 웹 서버가 처음 기동될 때 단 한번만 실행이 된다. 그러므로 SignalR 관련 초기화는 한번만 이뤄지게 된다.
<!-- SignalR로 통신하여 받은 데이터를 반영할 수 있는 DOM --> <ul id="messages"></ul> @using (Ajax.BeginForm("PostMessage", new AjaxOptions())) { <p> Say : @Html.TextBox("messageText") <input type="submit" /> </p> } @section scripts { <script src="~/Scripts/jquery.signalR-1.0.1.js" type="text/javascript"></script> <script src="~/signalr/hubs" type="text/javascript"></script> <script type="text/javascript"> $(function () { // Form의 Submit 이벤트 통제 $("form").submit(function () { var text = $('#messageText').val(); // Hub를 통해 SignalR 통신으로 서버에 보낸다. messagesHub.server.send(text); $('#messageText').val('').focus(); return false; }); // SiglalR/Hubs에서 Generated된 javascript 코드를 할당 var messagesHub = $.connection.messages; // SignalR에서 Hub를 통해 메세지를 받는다. messagesHub.client.addMessage = function (messageFromServer) { $('<li>').text(messageFromServer).appendTo("#messages"); } // SignalR 시작 $.connection.hub.start(); }); </script> }
[코드13] SignalR이 브라우저에서 실행될 클라이언트 사이드 코드
1. <script src="~/Scripts/jquery.signalR-1.0.1.js" type="text/javascript"></script> : SignalR 관련 라이브러리를 추가하면 jQuery를 확장한 자바스크립트 라이브러리가 추가되어 있을 것이다. 웹 페이지에서 사용할 수 있도록 추가하는 것이다.
2. <script src="~/signalr/hubs" type="text/javascript"></script> : 서버 코드상에서 Hub를 상속받은 Messages 클래스에 대해서 Generated하여 자바스크립트 코드를 만든었으며 서버에서 추가한 메소드가 자바스크립트에서 실행이 되도록 하고 있다. 자세한 사항은 밑에서 한번더 다루도록 하겠다.
3. var messagesHub = $.connection.messages : SignalR의 자바스크립트 라이브러리가 연결할 Hub 객체를 할당한다.
4. messagesHub.server.send(text) : text 메시지를 서버에 보내준다.
5. messagesHub.client.addMessage : 서버에서 보내준 메시지를 처리하는 이벤트를 설정한다. 여기서는 화면에 보여주는 로직만 코딩되어 있다.
서버측 코드에 대해서 작성할 차례인데 생각보다 간단한 코드로 이뤄진다.
/// <summary> /// 컨트롤러 클래스 /// </summary> public class SignalRTestController : Controller { // // GET: /SignalR/ public ActionResult Index() { @ViewBag.Message = "SignalR Test"; return View(); } } /// <summary> /// SignalR의 기능을 담당할 Messages, 클라이언트에서 올려준 메세지를 모든 클라이언트에 뿌려주는 역할을 한다. /// </summary> public class Messages : Hub { public void Send(string message) { Clients.All.addMessage(message); } }
[코드14] SignalR의 서버 사이드 코드
1. SignalRTestController : 단순히 웹 페이지를 보여주기 위한 코드 밖에 없다.
2. public class Messages : Hub : 이 코드가 SignalR의 핵심이다. 여기에서 추가로 코드가 자바스크립트로 Generated로 되어 브라우저에서도 사용할 수 있게 변환이 된다.
3. Clients.All.addMessage(message) : 받은 메시지를 연결된 모든 클라이언트에게 보내주는 코드다.
이제 코드 설명은 다 끝났지만 한간지 의문점이 남게 될 것이다. Generated되어 자동으로 실행이 되도록 한다고 하였지만 무엇이 어떻게 생성이 되고 실행이 되는지는 모른다. 일반적으로는 몰라도 SignalR에서 자동으로 뒷단에서 많은 일들을 하고 있기 때문에 편리하게 브라우저의 HTML5에 제한을 생각하지 않고 편리하게 사용만 하면 된다. 그렇지만 SignalR을 더 많이 이해하기 위해 자바스크립트 소스를 분석하게 되었다. 아래 '코드14'가 브라우저에서 Generated된 자바스크립트 코드다. 너무 길어 일괄적인 코드는 생략하고 중요한 코드만 남겨 두었다.
[코드15] /signaR/Hubs에서 만들어진 자바스크립트 코드
자동으로 생성된 코드는 서버에서 Hub를 상속 받은 Messages의 분석하여 Javascript를 만든 것이다. 서버의 'Send' 메소드가 자바스크립트의 send: function (message) { }로 변환된 것을 확인 할 수 있다. 이런 방식으로 서버의 코드를 자바스크립트에서 직접 사용할 수 있도록 Proxy를 만들어서 브라우저에 보내주는 것이다. 이제 모든 코드에 대해서 살펴 보았으니 결과를 확인해 보도록 하자.
[그림13] SingalR 실행 결과 화면 ( 위쪽이 Chrome, 아래쪽이 IE10 )
1. IE에서 메시지를 'IE10에서 보내는 SignalR 메시지' 입력하고 서버에 전송한다. - 실시간으로 크롬에서 확인된다.
2. 크롬에서 메시지를 'Chrome에서 보내는 SignalR 메시지' 입력하고 서버에 전송한다. - 실시간으로 IE에서 확인된다.
위와 같이 실시간으로 보내지는 메시지를 브라우저에서 받아 처리하도록 한다. 여기까지는 WebSocket와 별 다를게 없어 보인다. HTML5의 WebSocket를 지원하지 않는 브라우저를 재현하기 위해 IE의 '관리자 도구'를 이용하여 모드를 하위 버전으로 수정하여 테스트를 진행하여 서버와이 통신이 어떻게 변경이 되는지 확인해 보도록 하겠다.
IE에서 F12로 관리자 모드를 활성화 한다. 이곳에서 네트워크 탭으로 가서 캡춰 시작 버튼을 눌러 네트워크 트래픽이 잡아 내도록 한다. 그리고 브라우저 모드를 IE10에서 IE9으로 변경하면 아래와 같은 결과를 확인 할 수 있다.
[그림14] IE의 관리자 도구 화면
이제부터 브라우저는 IE10이지만 내부적으로는 IE9과 같은 방식으로 동작하게 된다. IE9은 WebSocket를 지원하지 않아 웹 소켓 통신을 하지 못하는데 어떻게 실시간으로 값을 받아 올 수 있을까? 이건 네트워크 트래픽에 잡힌 '/signalr/connect?transport=foreverFrame ...' Url 주소를 보면 해답을 찾을 수 있다. ForeverFrame으로 서버에 계속 연결되어 있는 상태가 되어 서버에서 Flush된 데이터를 브라우저에서 받는 것이다. 그래서 네트워크 결과에 보면 계속 '보류중' 이라고 나오는 것이다. 이렇게 SignalR을 사용하면 WebSocket만을 사용하여 개발하는 것 보다 브라우저의 제약에 좀더 자유로울 수 있게 되고 추상화된 API를 제공하므로 개발의 일관성을 유지할 수 있게 된다.
지금까지 브라우저에서 서버와 통신하는 여러가지 방법중에 대표적인 기술과 최신에 나온 WebSocket 그리고 통신 기술들을 아우르는 추상화 시킨 라이브러리인 SignalR이나 Socket.IO에 대해서 간략하게 나마 알아 보았다. 어떤 기술을 선택하여 개발할지는 각각의 개발 환경이나 제약 사항에 따라 취사 선택을 해야 할 것이다. 이제 부터는 각자 자신의 몫이다. 자신의 것으로 만들고 적용하여 보다 발전된 방향으로 가야하는 짐을 여러분에게 맡기는 것이다.
소스 코드 자체에 주석과 직관적인 코딩으로 충분히 파악이 가능할 것으로 예상하므로 별도의 설명을 생략하도록 하겠습니다. 포스트의 내용이 장황한 설명 보다는 주석과 소스코드 자체 만으로도 이해할 수 있도록 하기 위해 노력하였습니다. 실 개발에서도 적용할 수 있도록 간단하면서도 현실적인 예제 프로그램을 통해 각 소스를 만들고 이해 시키고자 하였으며 실무에 필요한 개발요구 사항들을 해결 하는데 도움이 되고자 노력하였습니다. 그리고 소스와 같이 있는 주석을 이용해 nDoc이나 별도의 자동 Document 제작 유틸로 API 문서를 만드는 데에도 도움이 되었으면 한다. ing™ |
'ASP.NET MVC' 카테고리의 다른 글
Web에서 HttpResponseException을 이용한 에러 노출 (0) | 2014.04.17 |
---|---|
HostingEnvironment를 이용한 호스팅 정보 활용 (0) | 2014.04.17 |
Real time Apps #5 - WebSocket (0) | 2013.09.10 |
Real time Apps #4 - SSE ( Serve Sent Events ) (0) | 2013.08.24 |
Real time Apps #3 - LongPolling (0) | 2013.08.23 |