Real time Apps #3 - LongPolling


참조 URL
  1. http://techoctave.com/c7/posts/60-simple-long-polling-example-with-javascript-and-jquery
  2. http://tkjeon.tistory.com/entry/Jquery-Jquery-폴링Polling-기법
  3. http://msdn.microsoft.com/ko-kr/library/dd449174.aspx - TaskCompletionSource<TResult>


목차
  1. Polling - 있어?
    [ASP.NET MVC] - Real time Apps - Polling
  2. LongPolling - 있으면 보내줘!
    [ASP.NET MVC] - Real time Apps - LongPolling
  3. SSE ( Server Send Events ) - 있으면 보내줘 기다릴께~ 
    [ASP.NET MVC] - Real time Apps - SSE ( Serve Sent Events )
  4. WebSocket - 어! 왔네~
    [ASP.NET MVC] - Real time Apps - WebSocket
  5. SignalR - over WebSocket ( MS Platform )
    [ASP.NET MVC] - Real time Apps - SignalR over WebSocket


 이 포스트에 있는 내용이 언제나 확실한 정답은 아닙니다. 진실이라고 생각해 왔던 전제가 시간의 지남에 따라 들어나지 않았던 다른 이면 때문에 좋은 방향으로 이끌어 낼 수 있는 역할로 변환 되는게 역사적으로도 많은 증명 있었습니다. 그렇지만 저는 현재 상황에서 최선의 답을 찾고자 노력하였으며 이 글을 읽는 다른 분들에게 다음 길을 갈 수 있도록 도와주는 디딤돌이 되고자 노력하고자 포스팅을 통해 공유하고자 하는 것입니다. 그리고 프로그래머라는 타이틀을 달고 살아야 한다면 "왜"라는 의문을 항상 가지고 다니면서 자신의 위치에 안주하지 않고 항상 노력하는 모습으로 살아 가고자 합니다. 언제든 지적이나 오류가 있으면 피드백 부탁 드리겠습니다.

ing™       


 이번에는 LongPolling에 대해서 알아 보자. 좀전에 Polling에 대해서 알게 되었다면 별로 어렵지 않게 이해를 할 수 있을 것으로 예상한다. 그냥 Polling은 주기적으로 서버에 요청하는 방식이지만 LongPolling 방식은 한번 요청하고 서버에 데이터가 있을때만 반환받는 방식이다. 아래 '그림3'으로 보면 좀더 쉽게 이해할 수 있을 것이다.


[그림3] LongPolling 방식


 1. Request1로 서버에 요청하고 서버에서 Event( or Data )가 발생되면 해당 형식( 여기서는 Message라고 정의 )을 브라우저에 보내주고 브라우저 커넥션은 끊어진다.

 2. 받은 데이터를 처리하고 곧바로 서버에 Request2를 요청하고 데이터가 발생할 때까지 대기한다.

 3. 1단계를 다시 시작한다. 


 이와 같은 단계로 LongPolling 방식이 구동이 된다. Polling와 LongPolling 방식은 전체적으로 비슷한 방식을 개발할 수 있으나 다른점은 'LongPolling'이라는 이름처럼 길게 대기하여 서버에 응답요청을 한다는데 있다. 길게 기다리다가 "있으면 보내줘!"와 같은 컨셉이다. 이제 실제 코드로 알아가 보자.


<!-- Polling 하여 받은 데이터를 반영할 수 있는 DOM -->
<ol id="messages"></ol>
 
@using (Ajax.BeginForm("PostMessage"new AjaxOptions())) { 
    <p>
        Say : @Html.TextBox("messageText")
        <input type="submit" /> 
    </p>
}

<!-- 위 코드는 아래의 HTML Tag로 변환된다. <form action="/LongPolling/PostMessage" data-ajax="true" id="form0" method="post">    <p>         Say : <input id="messageText" name="messageText" type="text" value="" />         <input type="submit" />      </p> </form> -->

@section scripts{ <script type="text/javascript">     $(function () {         // Begin the LongPolling loop         getNextMessage();         // Form의 Submit 이벤트  통제         $("form").submit(function () {             var form = $(this);

            // messageText의 Html tag에 입력된 값을 가져온다.              var txtMessageText = $(form.find('#messageText'));

            // Ajax로 서버에 입력한 값을 넘겨준다.             $.post('@Url.Action("PostMessage")', { 'messageText': txtMessageText.val() }, function () {                 txtMessageText.val('');                 txtMessageText.focus();             });                              // HTML의 Submit가 일어나지 않도록 한다.             return false;         });     });     // 서버에 메시지가 있는지 문의 요청     function getNextMessage() {         $.post("@Url.Action("GetNextMessage")", function (message) {             $("<li>").text(message).appendTo("#messages");             // 응답받은 즉시 다시 요청             getNextMessage();         });     } </script> }

[코드3] LongPolling - Browser의 javascript 코드


 위 코드에서는 '그림3'과 같이 사용자의 입력을 받는 부분이 있다.


[그림4] LongPolling 테스트 대기 화면


 위 '코드3'의 전체적인 흐름을 파악해 보자

- HTML이 완성되면 getNextMessage()를 호출하여 서버에 요청을 한다.

- Html의 form에서 submit 버튼을 눌렀을 때 페이지 이동이 일어나지 않도록 처리한다.

- getNextMessage() 함수는 서버에 GetNextMessage()를 호출하고 반환 받을 때까지 대기한다.

- 사용자에게 데이터 입력을 받고 제출 버튼을 누르면 ajax의 Post 방식으로 PostMessage 함수를 호출하여 넘겨준다.


  이제 서버측 '코드4'에 대해서 알아 보자


/// <summary>
/// 요청이 오면 임의의 시간 대기 후 응답
/// </summary>
/// <returns></returns>
public async Task<string> GetNextMessage()
{
    return await _nextMessage.Task;
}
 
/// <summary>
/// Lock object
/// </summary>
static object _nextMessageLock = new object();

/// <summary>
/// for LongPolling object
/// </summary>
static TaskCompletionSource<string> _nextMessage = new TaskCompletionSource<string>();
 
public void PostMessage(string messageText)
{
    lock (_nextMessageLock)
    {
        // Concurrent 해결 하기 위해 임시 변수에 옮긴다.
        var oldNextMessage = _nextMessage;
        _nextMessage = new TaskCompletionSource<string>();
        oldNextMessage.SetResult(messageText);
    }
}

[코드4] LongPolling - Server side 코드


 1. GetNextMessage 함수가 호출이 되면 return await _nextMessage.Task 구문에서 리턴값이 있을 때까지 비 동기로 대기 한다.

 2. PostMessage 함수가 호출 될 때 위에서 대기하고 있던 객체인 _nextMessage 객체에 SetResult(msg)에 값을 넘겨주면 1에서 대기하던 객체는 해당 값을 반환하도록 해주며 다시 대기하도록 한다. 이때 Lock를 통해 쓰레드 안정성을 확보하도록 하였다.

 3. TaskCompletionSource<string> 객체는 입력값이 string이고 출력 값이 string인 객체로 선언되었으며 비 동기로 동작할 수 있도록 .Net Framework 4에서 부터 제공하는 클래스다.

 4. public async Task<string> GetMessage()는 비 동기로 수행된다고 알려주는 C# 5.0 예약어다. 이 함수 안에는 반드시 await 예약어를 사용하여 비 동기로 사용하는 구문이 있어야 한다. - 이 부분은 node.js의 특징인 비 동기 방식을 .Net에서 지원하는 것이라 이해해도 되겠다.


 이제 LongPolling에 대해 전체적인 흐름을 이해했으리라 생각이 든다. 지금까지 살펴보았다면 꼭 실습으로 한 번씩 테스트를 해 보기를 바라며 정 여건이 되지 않는다면 마지막 편에 제공되는 전체 소스파일을 다운바다 실행해 보기 바란다.


 마지막으로 결과 화면으로 확인해 보자 아래 '그림5'를 통해 확인 할 수 있다.




[그림5] LongPolling 결과 화면


위 화면에서 제출을 누르면 “5.Step #5" 밑에 "6. Step #6"이 추가 됨을 확인 할 수 있을 것이다.


소스 코드 자체에 주석과 직관적인 코딩으로 충분히 파악이 가능할 것으로 예상하므로 별도의 설명을 생략하도록 하겠습니다. 포스트의 내용이 장황한 설명 보다는 주석과 소스코드 자체 만으로도 이해할 수 있도록 하기 위해 노력하였습니다. 실 개발에서도 적용할 수 있도록 간단하면서도 현실적인 예제 프로그램을 통해 각 소스를 만들고 이해 시키고자 하였으며 실무에 필요한 개발요구 사항들을 해결 하는데 도움이 되고자 노력하였습니다. 그리고 소스와 같이 있는 주석을 이용해 nDoc이나 별도의 자동 Document 제작 유틸로 API 문서를 만드는 데에도 도움이 되었으면 한다. 
※ DOC에 대한 프로그램 정보 Util link

ing™       




Real time Apps #2 - Polling


참조 URL
  1. http://reallifejs.com/brainchunks/repeated-events-timeout-or-interval/ - setTimeout vs setInterval
  2. http://en.wikipedia.org/wiki/Comet_(programming) - COMET programming
  3. http://blog.falafel.com/blogs/basem-emara/2012/06/06/polling-ajax-requests-in-javascript

  

목차
  1. Polling - 있어?
    [ASP.NET MVC] - Real time Apps - Polling
  2. LongPolling - 있으면 보내줘!
    [ASP.NET MVC] - Real time Apps - LongPolling
  3. SSE ( Server Send Events ) - 있으면 보내줘 기다릴께~ 
    [ASP.NET MVC] - Real time Apps - SSE ( Serve Sent Events )
  4. WebSocket - 어! 왔네~
    [ASP.NET MVC] - Real time Apps - WebSocket
  5. SignalR - over WebSocket ( MS Platform )
    [ASP.NET MVC] - Real time Apps - SignalR over WebSocket


 이 포스트에 있는 내용이 언제나 확실한 정답은 아닙니다. 진실이라고 생각해 왔던 전제가 시간의 지남에 따라 들어나지 않았던 다른 이면 때문에 좋은 방향으로 이끌어 낼 수 있는 역할로 변환 되는게 역사적으로도 많은 증명 있었습니다. 그렇지만 저는 현재 상황에서 최선의 답을 찾고자 노력하였으며 이 글을 읽는 다른 분들에게 다음 길을 갈 수 있도록 도와주는 디딤돌이 되고자 노력하고자 포스팅을 통해 공유하고자 하는 것입니다. 그리고 프로그래머라는 타이틀을 달고 살아야 한다면 "왜"라는 의문을 항상 가지고 다니면서 자신의 위치에 안주하지 않고 항상 노력하는 모습으로 살아 가고자 합니다. 언제든 지적이나 오류가 있으면 피드백 부탁 드리겠습니다.

ing™       


 Polling에 대해서 알아보기 전에 우선은 Ajax와 인터랙티브 웹 페이지에 대해 간략히 알아 보자. Ajax 통신은 브라우저에서 제공해주는 특별한 객체를 통해(IE - new ActiveXObject("Microsoft.XMLHTTP"), Other - new XMLHttpRequest()) 사용자의 행위에 따라 페이지의 새로 고침 없이 Background에서 서버에서 원하는 데이터를 가져와  페이지의 일부분만을 수정할 수 있는 메커니즘을 말한다. 이런 개발 방식으로 개발된 웹 페이지를 접한 사용자들은 기존의 페이지에서는 느낄 수 없었던 사용자 경험을 얻을 수 있었다.  이 후 수많은 사이트에서 이 개발 방식으로 웹 페이지를 제공하게 되었다. 이런 개발 방식이 조금 더 응용되어 Polling 기법으로 사용자의 행위 없이도 서버에서 변경된 정보를 실시간 - 사용자의 입장에서는 실시간이나 개발자 입장에서는 실시간 지향적 이라 하겠다 - 적으로 업데이트를 할 수 있게 되었다. 간단하게 예를 들면 브라우저에서 서버에게 주기적으로 "데이터가 있어?"라고 물어 보고 서버에서 데이터의 여부에 따라 다르게 대답 하는 것이라 하겠다. 브라우저에서는 받은 데이터로 웹 페이지의 일부분만을 업데이트하여 사용자에게 보여주므로 빠른 응답을 사용자에게 경험하게 할 수 있다. 대표적인 애플리케이션은 웹 채팅이다. 상대방에서 보낸 메시지 여부를 주기적인 Polling으로 알아내어 사용자에게 보여주는 것이다.


Polling의 사전적인 의미를 알아보자. N사이트의 국어사전의 뜻을 보면 다음 표와 같이 풀이하고 있다.


<컴퓨터> 컴퓨터 또는 단말 제어 장치 따위에서 여러 개의 단말 장치에 대하여 순차적으로 송신 요구의 유무를 문의하고요구가 있을 경우에는  단말 장치에 송신을 시작하도록 지령하며없을 에는 다음 단말 장치에 대하여 문의하는 전송 제어 방식. 

[표3] 폴링에 대한 국어사전 풀이


 이 뜻풀이처럼 데이터가 필요한 곳에서 제공자에게 송신을 요구하는 패턴을 Polling 방식이라고 할 수 있겠다. 즉 원하는 곳에서 당겨가는 방식이다. 그렇다면 웹 페이지와 서버 간에는 어떻게 Poll이 이루어지고 있는지를 아래 '그림1'을 통해서 전체적인 흐름을 알아 가 보자.

[그림1] Polling 방식


 웹 페이지에서 Polling을 구현하는 방식은 setTimeout() 함수를 이용해 주기적인 시간 간격으로 서버에 요청하여 원하는 정보를 얻어오도록 하고 있다. 

  1. '그림1'에서와 같이 첫번째 요청처럼 브라우저에서 Ajax로 'Request1'을 요청하면 서버에서는 유효한 데이터가 있는지 조회하고 없으면 개발자가 정의한 형식(여기서는 Empty라고 정의)으로 리턴받고 브라우저 커넥션은 끊어진다.

  2. setTimeOut()함수로 'Request2'요청이 발생할 당시 서버에서 이벤트가 발생하여 유효한 데이타가 있으면 Empty와 대신 개발자가 정의한 형식(여기서는 Message라고 정의)으로 리턴받고 브라우저 커넥션은 끊어진다.

  3. 1단계를 다시 시작하여 서버에서 반영된 유효한 값을 브라우저에 업데이트 한다.

 위와 같은 방식으로 서버의 변경된 데이터를 브라우저에 지속적으로 반영하여 실시간 반응을 지향하는 웹 페이지를 만들었다. 


 이제 예제를 통해서 실제적인 코드로 살펴 볼 것이다. ( 실행해 볼 수 있는 소스코드를 마지막 포스트에서 첨부할 것 이니 다운받아 확인할 수 있습니다. ) 

<!-- Polling 하여 받은 데이터를 반영할 수 있는 DOM -->
<ol id="messages"></ol>

@section scripts{ <script type="text/javascript">     $(function () {         // Begin the Polling loop         getNextMessage();     });     function getNextMessage() {         // Http post method request

//@Url.Action("GetNextMessage") -> /현재 페이지/GetNextMessage로 치환된다         $.post("@Url.Action("GetNextMessage")", function (message) {             $("<li>").text(message).appendTo("#messages");         });         // Http get method request         //$.get("@Url.Action("GetNextMessage")", function (message) {         //    $("<li>").text(message).appendTo("#messagees");         //});         setTimeout(getNextMessage, 1000);     } </script> }

[코드1] Polling - Browser의 HTML과 javascript 코드

( ASP.NET MVC4의 Razor 문법으로 작성된 코드다. )


 위 코드는 페이지가 로딩이 되면 getNextMessage() 함수를 호출하여 서버에 데이터를 요청하고 <ol> 노드에 <li> 노드를 추가하는 코드다. ( 서버 요청을 HttpPost 또는 HttpGet으로 할 수 있다 ) 그리고 setTimeout를 통해 1초후에 다시 getNextMessage()를 호출하도록 되어 있다. 별도의 문제나 행위가 발생하지 않는 한 무한 호출이 되는 단순한 구조로 구성 되어 있다. 이제 아래 코드를 통해 서버쪽의 코드를 알아 보자.

 

/// <summary>
/// 요청이 오면 즉시 응답
/// </summary>
/// <returns></returns>
public string GetNextMessage()
{
    int waitingCount = 0;
    var now = DateTime.Now;
    return "Response at " + now.ToString() + "." + now.Millisecond + " 서버 대기 시간 : " + waitingCount + "ms";
}

[코드2] Polling - Server side 코드

( 서버 사이트 코드는 ASP.NET MVC4 기반에서 작성이 되었다. )


 위 코드는 따로 설명을 할 필요도 없을 정도로 간단하여 짧게 설명을 하도록 하겠다. GetNextMessage()함수는 호출이 되면 현재 시간을 알아내 string으로 반환하도록 되었다. 이제 위 결과 화면을 아래 그림을 통해 확인해 보자.


[그림2] Realtime Apps - Polling 실행 결과 화면

( 위 화면은 Visual studio에서 ASP.NET MVC4 템플릿에서 기본 제공되었다.)



  '그림2'의 결과 화면을 보면 1초마다 호출된 결과를 화면에 뿌려주는 것을 확인할 수 있다. 이제 코드와 결과 화면까지 확인을 하였다. 이제 Polling이 어떤 방식으로 구성되고 개발되는지 대략적으로 알 수 있을 것이라고 기대한다. 위 예제는 MS 진영에서 개발 및 테스트를 할 수 있지만 Java나 PHP, 기타 Ruby와 같은 곳에서도 비슷한 방식으로 구현이 될 것이므로 이해 하는 데에 크게 무리가 없을 것이라 생각한다.


Tip!

 Request가 지속적으로 일어 날 때마다 서버에서는 유효한 사용자의 요청인지를 알아내기 위해 내부적으로 HTTP Handshanking이 지속적으로 일어나기 때문에 오버헤드가 발생한다. 그래서 예측할 수 없는 웹 서비스를 제공하는 서버에서는 성능에 대한 고려를 충분히 해야 한다.


소스 코드 자체에 주석과 직관적인 코딩으로 충분히 파악이 가능할 것으로 예상하므로 별도의 설명을 생략하도록 하겠습니다. 포스트의 내용이 장황한 설명 보다는 주석과 소스코드 자체 만으로도 이해할 수 있도록 하기 위해 노력하였습니다. 실 개발에서도 적용할 수 있도록 간단하면서도 현실적인 예제 프로그램을 통해 각 소스를 만들고 이해 시키고자 하였으며 실무에 필요한 개발요구 사항들을 해결 하는데 도움이 되고자 노력하였습니다. 그리고 소스와 같이 있는 주석을 이용해 nDoc이나 별도의 자동 Document 제작 유틸로 API 문서를 만드는 데에도 도움이 되었으면 한다. 
※ DOC에 대한 프로그램 정보 Util link

ing™       



+ Recent posts