2013
마이크로소프트웨어

글: 라천호 rchcomm@naver.com, www.feelanet.com / 2012년 8월호


<실전강의실>

SW 개발자라면 ‘인터랙티브(Interactive)’란 단어를 익히 들어봤을 것이다. 인터(Inter)와 액티브(Active)의 합성어인 인터랙티브의 사전적 의미는 ‘상호적인’, ‘상호작용을 하는’으로, 사용자의 요청에 반응해 마치 대화하듯 데이터를 입출력할 수 있는 일종의 프로그램이다. 최근 인터랙티브 웹이 대두되면서 이와 관련한 다양한 논의가 이뤄지고 있는데, 이 글에서는 웹서버의 데이터 통신 기법상에서 인터랙티브 웹의 동작 원리를 살펴본다.

라천호 rchcomm@naver.com, www.feelanet.com|디자인패턴과 프레임워크에 관심이 많아 관련 기술을 검토하고 정리하는 것을 즐기는 평범한 개발자다. 필라넷의 애플리케이션 파트에서 Fx-Platform의 Core Framework 기반으로 각각의 도메인 영역에 알맞은 애플리케이션 프레임워크를 개발하면서 관련된 컨설팅도 병행하고 있다.



Ajax 방법론이 등장함에 따라 고수준의 인터랙티브 웹 개발이 가능해지면서 인터랙티브에 대한 사용자의 눈높이도 높아지고 있다. 게다가 기존 레거시 시스템을 웹에서 지원하는 형태로 기술이 발전하면서 C/S 프로그램의 기능을 HTML, CSS, 자바스크립트로 대체해야 한다는 공감대도 형성되고 있다. 시대적 흐름이 된 스마트폰과 태블릿 등의 모바일 디바이스가 확산되면서 각각의 브라우저와의 호환도 고려해야 할 중요한 사안이 되고 있다. 이러한 다양한 제약들과 트렌드를 인터랙티브 웹 개발에 반영하기란 쉽지 않다.


그럼에도 이를 가능케 하기 위한 개발자의 노력이 계속되면서 Polling과 LongPolling 등의 새로운 방식의 시도가 탄생했지만 HTTP 프로토콜과 HTML의 구조적 한계를 극복하지는 못한 것으로 평가되고 있다. 이런 이유로 HTML5와 표준화된 스크립트 프로그래밍 언어인 ECMAScript 5가 주목받고 있을 뿐 아니라 윈도우와 리눅스 같은 개발 플랫폼으로서 HTML이 빠르게 진화하고 있다.

그렇다면 인터랙티브 웹을 가능케 하는 다양한 기법에는 어떤 것들이 있을까? 이러한 기법 중 서버와의 통신을 통해 데이터를 얻는 Polling은 어떻게 동작하는 것일까?

1. Polling - 있어?
2. LongPolling - 있으면 보내줘!
3. SSE(Server Sent Events) - 있으면 보내줘 기다릴게~
4. WebSocket - 어! 왔네!(Socket.IO)
5. SignalR - over WebSocket(MS Platform)

Polling 기법을 살펴보기에 앞서 데이터 통신 기술을 정리한 <표 2>를 간단히 살펴보자. 여기서 hybrid라고 표기된 SignalR과 Socket.IO는 하위 브라우저와도 호환되는 하이브리드 방식인데, 이를 이용하면 WebSocket을 지원하지 않는 브라우저에서도 하위 통신 방법으로 데이터를 요청할 수 있다.

Polling - 있어?
Polling을 이해하기 위해서는 Ajax와 인터랙티브 웹에 대한 이해가 선행돼야 한다. Ajax는 브라우저에서 제공하는 특별한 객체(인터넷 익스플로러)인 new ActiveXObject(“Microsoft. XMLHTTP”)와 타 브라우저들의 new XMLHttpRequest()를 활용해 페이지를 ‘새로고침’하지 않아도 사용자의 요청에 따라 서버에서 원하는 데이터를 얻고 페이지의 일부를 수정 가능한 메커니즘을 뜻한다. 이러한 방식을 따르는 웹은 기존의 정적인 웹에서 불가능했던 새로운 경험을 제공하기 때문에 점차 많은 웹사이트에서 이러한 개발 방식을 채택하고 있다.

이러한 기술을 응용한 대표적인 기법이 Polling이다. Polling은 사용자가 요청하지 않아도 서버에서 변경된 정보를 실시간 업데이트하는데, 이를 동작 방식으로 볼 경우 실시간보단 실시간을 지향한다는 표현에 더 적합하다. 예컨대 브라우저가 서버에게 “새로운 데이터가 있어?”라고 주기적으로 묻는 것이 바로 Polling이며, 이때 서버는 데이터의 여부에 따라 다르게 답한다. 이 기법은 새로운 데이터를 수신하면 웹페이지의 일부분만 업데이트하기 때문에 응답속도가 빠른 것이 특징으로, 대표적인 애플리케이션으로는 웹 채팅이 있다.

Polling의 사전적 의미는 데이터가 필요한 곳이 제공자에게 송신을 요구하는 것이다. 그렇다면 좀더 구체적으로 웹페이지와 서버가 어떤 방식으로 Poll을 처리할까?


<그림 1> Polling의 동작 방식

기본적으로 setTimeout() 함수로 일정 시간 간격으로 서버에 요청을 보내 원하는 정보를 얻는 간단한 구조만으로 웹페이지에서 Polling을 구현할 수 있다.

① <그림 1>에서 브라우저가 Ajax를 통해 ‘Request 1’을 요청하면 서버는 유효한 데이터가 있는지 조회하고 없는 경우 개발자가 정의한 형식(Empty)을 반환한다. 이후 커넥션이 종료된다.
② setTimeOut() 함수에 의해 ‘Request 2’ 요청이 서버로 전달되기에 앞서 서버에서 유효한 이벤트가 발생해 유효한 데이터가 발생한 경우 클라이언트가 보낸 Request2에 따라 개발자가 정의한 형식(Message)을 클라이언트로 반환하고 커넥션이 종료된다.
③ ①단계가 반복 수행되면서 서버의 유효한 값을 받고 브라우저에 업데이트한다.

동작 메커니즘이 간단한 만큼 Polling의 동작 방식을 이해하는 데에 별다른 어려움이 없을 것이다. 이처럼 일정 시간을 주기로 서버에서 업데이트된 정보를 조회하고 갱신하는 Polling 기법을 실제로 구현해보자. 클라이언트에 해당하는 브라우저와 서버 측의 코드는 각각 <리스트 1>, <리스트 2>와 같다.

 

<리스트 1>은 ASP.NET MVC의 Razor 문법으로 작성됐음에 주의하자. 이 문법을 모르더라도 문법이 간단하고 주석을 통해 주요 포인트를 설명한 만큼 전체적인 동작 방식을 이해하는 데 큰 어려움은 없다. 따라서 자세한 설명을 생략하고 전체적인 흐름 위주로 설명하겠다.

HTML에는 ‘message’란 ID로 태그를 선언해 DOM을 노드에 추가했다. 자바스크립트에서의 경우 check point 1에서 호출되는 getNextMessage() function으로 Polling이 수행되며, getNextMessage()는 HTTP Post 방식으로 서버에 데이터를 요청한다. 이때 서버에 데이터가 있으면 check point 2와 같이 messages 노드를 찾아 ‘li’와 해당 값을 추가하고, 요청이 완료되면 check point 3처럼 setTimeout을 통해 1초 후에 다시 getNextMessage()가 실행된다.

참고로 getNextMessage()에서 주석 처리된 $.get(…) 부분을 제거하고 실행할 경우 HTTP Get 요청 방식으로 서버에 데이터를 요청할 수 있다.

서버는 클라이언트의 요청을 어떻게 처리하는 것일까? 서버 측 Polling 소스 코드인 <리스트 2>에서 그 답을 찾아보자. <리스트 2>의 GetNextMessage()는 ‘/GetNextMessage’를 통해 브라우저에 주소를 입력하면 ASP.NET MVC가 routing engine을 매치시켜 실행한다. 그런데 여기서 Thread.Sleep(waiting Count)가 주석 처리돼 있기 때문에 서버는 대기 없이 결과를 반환한다.

참고로 <리스트 2>에 선언된 ‘var’은 닷넷 프레임워크 4.0에 추가된 키워드로, 선언을 컴파일러가 대신 처리해준다. 예컨대 var str=“”의 경우 컴파일러가 자동적으로 string str=“”로 변환하기 때문에 이를 활용하면 프로그래밍이 한결 쉬워진다.

이 Polling 코드를 실행한 결과는 <그림 2>와 같으며, 여기에는 ASP.NET MVC4 프로젝트 생성 시 기본 제공되는 템플릿이 적용돼 있음을 참고하길 바란다.


<그림 2> Polling 실행 결과

<그림 2>가 독자들이 예상한 결과와 같은가? <그림 2>의 경우 8번까지만 출력돼 있지만 만약 이 프로그램을 계속 실행했다면 테스트 결과가 화면을 가득 채웠을 것이다. 물론 이 예제는 윈도우 OS에서만 테스트할 수 있지만 Polling의 원리만 이해했다면 자바, PHP, 루비 등으로도 쉽게 구현해볼 수 있을 것이다.

Polling 기법을 활용하기에 앞서 반드시 고려해야 할 것은 다름아닌 ‘시스템 부하’다. Polling의 동작 원리상 Request가 반복되며, 매 요청 때마다 서버는 유효한 요청인지 여부를 매번 확인해야 한다. 이러한 요청 하나하나마다 HTTP 핸드쉐이킹(Hand shanking)이 일어나기에 오버헤드가 발생하기 쉽다. 그러므로 예측하기 어려운 웹서비스를 제공하는 서버라면 성능에 대해 충분히 고려할 필요가 있다.

LongPolling - 있으면 보내줘!
Polling보다 기술적으로 좀더 진화한 형태의 기법이 바로 LongPolling이다. Polling의 경우 주기적으로 서버에 요청하지만 LongPolling은 한 번만 요청하면 서버에 데이터가 있을 때 데이터를 반환받을 수 있기 때문에 Polling보다 상대적으로 오버헤드의 위험성이 적은 것이 특징이다.

 


<그림 3> LongPolling의 동작 방식

LongPolling도 서버로 Request를 전송하며 시작된다는 점은 Polling과 같지만 브라우저에 구현된 setTimeout() 함수가 없다는 것이 동작 방식에 있어서 가장 큰 차이점이다. 지금부터는 <그림 3>을 통해 LongPolling 기법의 동작 방식을 살펴보자.

① 브라우저가 Ajax를 통해 서버에 Request1 요청을 보내면 서버는 유효한 데이터가 있을 때까지 대기한다.
② 만약 서버에서 이벤트가 발생해 데이터가 유효해지면 앞서 연결돼 있던 Request1에 대한 요청(Message)을 반환한다.
③ 서버에게서 요청에 대한 데이터를 받은 브라우저는 서버와의 커넥션을 끊는 즉시, 다시 서버에게 Request2를 요청해 ①단계 작업을 반복한다.

이처럼 Polling과 LongPolling의 동작 방식은 전체적으로 매우 유사하다. 큰 차이점은 LongPolling이란 이름에서 유추할 수 있듯 클라이언트가 서버의 응답을 기다리는 시간이 더 길다는 점이다. 서버에 데이터가 있을 때까지 무작정 기다리게 되는 것으로 “데이터가 있으면 보내줘”라고 이해하면 쉽다.



<그림 4> LongPolling의 사용자 입력

LongPolling 예제는 Polling과 달리 웹페이지에서 사용자 입력을 받는다. 서버 측의 LongPolling 예제인 <리스트 3>을 통해 전체적인 동작 흐름을 이해해보자.

<리스트 3>에서 HTML이 완성되면 클라이언트는 getNext Message()를 호출해 서버에 요청을 보내는데, 이 함수는 서버에 GetNextMessage()를 호출하고 결과값을 반환받을 때까지 대기한다. 이 웹페이지에 사용자가 데이터를 입력하고 제출 버튼을 클릭하면 Ajax의 Post 방식으로 PostMessage 함수가 호출되고 이 데이터가 브라우저로 전달된다. HTML의 form에는 submit 버튼을 클릭해도 페이지가 이동되지 않게 처리됐음을 참고하자.

그렇다면 <리스트 4>는 어떻게 동작할까?

① GetNextMessage 함수가 호출되면 ‘return await _nextMessage. Task’ 구문이 반환값이 있을 때까지 비동기로 대기한다.
② PostMessage 함수가 호출되면 앞서 대기하고 있던 ‘_nextMess age’ 객체에 SetResult(msg)의 값을 넘겨주며, 이때 ①에서 대기 중인 객체는 해당 값을 반환하고 다시 대기한다. 이때 Lock이 사용됐기 때문에 비동기 처리임에도 스레드의 안전성이 보장된다.
③ TaskCompletionSource<string> 객체는 입력값이 string이고 출력값이 string인 객체로 선언돼 있는데 비동기로 동작함에 주의하자. 참고로 이 객체는 닷넷 프레임워크 4.0부터 제공돼온 클래스다.
④ public async Task<string> GetMessage()는 비동기로 수행됨을 의미하는 C# 5.0의 예약어다. 이 함수에는 반드시 await 예약어로 비동기로 처리돼야 하는데, 이는 node.js의 특징인 비동기 방식을 닷넷에서 지원하기 위함이다.

지금까지 핵심 위주로 LongPolling의 동작 원리를 살펴봤다. 단순히 이론적인 이해에 그치는 것보다는 실제로 앞선 예제들을 실습해보길 바란다. 만약 여건상 어렵다면 이 글에서 소개한 전체 소스 코드를 공개할 예정이니 참고하길 바란다.


<그림 6> LongPolling 실행 결과

앞선 LongPolling 예제를 실행한 결과는 <그림 6>과 같으며, 여기에 있는 제출 버튼을 클릭해보면 ‘5.Step #5’의 아래에 ‘6.Step #6’이 추가됨을 확인할 수 있다.

참고자료
1. http://reallifejs.com/brainchunks/repeated-events-timeout-or-interval/
2. http://en.wikipedia.org/wiki/Comet_(programming)
3. http://blog.falafel.com/blogs/basem-emara/2012/06/06/polling-ajax-requests-in-javascript
4. http://techoctave.com/c7/posts/60-simple-long-polling-example-with-javascript-and-jquery
5. http://tkjeon.tistory.com/entry/Jquery-폴링Polling-기법
6. http://msdn.microsoft.com/ko-kr/library/dd449174.aspx

맨 위로
맨 위로