2011.12.22 14:07

NHN Ajax UI4팀 심상민 

웹 페이지의 한계에서 벗어나 실시간으로 상호작용하는 웹 서비스를 만드는 표준 기술인 WebSocket. 그리고 다양한 방식의 실시간 웹 기술을 손쉽게 사용할 수 있는 Socket.io. 이 두 기술이 무엇인지 설명하고 어떻게 사용하는지 간단한 예제로 알아보겠습니다.

  • 웹 소켓(Web Socket)이 있기까지

    1989년 CERN(http://public.web.cern.ch)에서 웹의 역사가 시작되었을 때에는 사용자와의 상호작용은 웹 개발에서 큰 부분을 차지하지 않았다. 그러나 초창기에 연구기관에서 사용하던 웹은 점점 더 일상생활에 파고들었고, PC용 응용 프로그램(Native Application)을 대체할 수 있는 정도까지 되었다. 지금까지의 PC 환경이 이렇게 변화한 것처럼 모바일 환경에서도 앞으로 마찬가지로 변화할 것으로 보인다.

    전형적인 브라우저 렌더링 방식은 HTTP 요청(HTTP Request)에 대한 HTTP 응답(HTTP Response)을 받아서 브라우저의 화면을 깨끗하게 지우고 받은 내용을 새로 표시하는 방식이다. 내용을 지우고 다시 그리면 브라우저의 깜빡임이 생기게 된다. 이러한 깜빡임 없이 원하는 부분만 다시 그리며 실시간으로 사용자와 상호작용하는 방식이 나타나고 사용자와 상호작용하는 웹 서비스를 선호하는 사용자가 증가하면서 RIA(Rich Internet Application) 기술의 발달이 촉진되었다.

    상호작용하는 웹 서비스를 위해 숨겨진 프레임(Hidden Frame)을 이용한 방법이나 Long Polling, Stream 등 다양한 방법을 사용했다. 그러나 이러한 방식은 브라우저가 HTTP 요청를 보내고 웹 서버가 이 요청에 대한 HTTP 응답를 보내는 단방향 메세지 교환 '규칙'을 변경하지 않고 구현한 방식이다. 그렇기 때문에 상호작용하는 웹 페이지를 복잡하고 어려운 코드로 구현해야 했다.

    보다 쉽게 상호작용하는 웹 페이지를 만들려면 브라우저와 웹 서버 사이에 더 자유로운 양방향 메시지 송수신(bi-directional full-duplex communication)이 필요하다. 그래서 HTML5 표준안의 일부로 WebSocket API(이후 WebSocket)가 등장했다.

    122111_0950_WebSocketSo1.png

    그림 1 WebSocket과 일반적인 Ajax Long Polling 방식 비교(이미지 출처: http://java.sys-con.com/node/1315473)

    WebSocket은 그 이름에서 알 수 있듯이 소켓을 이용하여 자유롭게 데이터를 주고 받을 수 있다. 즉 기존의 요청-응답 관계 방식보다 더 쉽게 데이터를 교환할 수 있다.

  • WebSocket 프로토콜

    표준 WebSocket의 API는 W3C에서 관장하고, 프로토콜은 IETF(Internet Engineering Task Force)에서 관장한다. 그리고 WebSocket은 다른 HTTP 요청과 마찬가지로 80번 포트를 통해 웹 서버에 연결한다. HTTP 프로토콜의 버전은 1.1이지만 다음 헤더의 예에서 볼 수 있듯이, Upgrade 헤더를 사용하여 웹 서버에 요청한다. 당연한 이야기겠지만 클라이언트인 브라우저와 마찬가지로 웹 서버도 WebSocket 기능을 지원해야한다.

    1
    2
    3
    GET /... HTTP/1.1
    Upgrade: WebSocket
    Connection: Upgrade

    브라우저는 "Upgrade: WebSocket" 헤더 등과 함께 랜덤하게 생성한 키를 서버에 보낸다. 웹 서버는 이 키를 바탕으로 토큰을 생성한 후 브라우저에 돌려준다. 이런 과정으로 WebSocket 핸드쉐이킹이 이루어진다.

    그 뒤 Protocol Overhead 방식으로 웹 서버와 브라우저가 데이터를 주고 받는다. Protocol Overhead 방식은 여러 TCP 커넥션을 생성하지 않고 하나의 80번 포트 TCP 커넥션을 이용하고, 별도의 헤더 등으로 논리적인 데이터 흐름 단위를 이용하여 여러 개의 커넥션을 맺는 효과를 내는 방식이다.

    이런 방식을 사용하기 때문에 방화벽이 있는 환경에서도 무리 없이 WebSocket을 사용할 수 있다.

  • WebSocket을 지원하는 브라우저와 웹 서버

    클라이언트인 브라우저 중에서는 Chrome, Safari, Firefox, Opera에서 WebSocket을 사용할 수 있으며, 각종 모바일 브라우저에서도 WebSocket을 사용할 수 있다.

    122111_0950_WebSocketSo2.png

    그림 2 WebSocket 지원 여부(이미지 출처: http://caniuse.com)

    Mozilla 계열 브라우저와 Opera에서는 프록시와 관련된 보안 이슈 때문에 WebSocket의 기본 설정을 'disable'로 설정했다. about:config 페이지에서 설정을 변경할 수 있지만 많은 사용자들이 이 조치에 불만을 제기했다. 프록시와 관련된 문제는 Flash나 Java에서도 동일하게 발생하는데 WebSocket만 기본 설정에서 제외했다는 것에 대한 불만이었다. 이러한 의견을 반영한 것인지 Mozilla 재단에서는 Firefox 6.0부터 네임 스페이스를 붙여 MozWebSocket으로 다시 WebSocket을 지원하기 시작했다. 이 사례는 사용자들이 WebSocket에 거는 기대감이 굉장히 크다는 것을 엿볼 수 있는 사례다.

    그러나 WebSocket 프로토콜은 아직 확정된 상태가 아니다. 현재 Draft75, Draft76 등의 이름으로 계속 드래프트 버전이 나오고 있다. 그렇기 때문에 브라우저별로 지원하는 WebSocket 버전도 다르다.

    122111_0950_WebSocketSo3.png

    그림 3 브라우저 별 Web Socket 버전 지원 상황(이미지 출처: http://en.wikipedia.org/wiki/WebSocket)

    웹 서버 중에서는 Apache에서 별도의 모듈을 설치하여 WebSocket을 사용할 수 있다. JEE 환경의 WAS에서는 Jetty, GlassFish에서 WebSocket을 사용할 수 있다. 또한 Node.js에서도 WebSocket을 사용할 수 있다. 그러나 아직 Tomcat은 공식적인 지원 계획을 발표하고 있지 않다.

  • WebSocket API를 사용해 보자

    백문이 불여일견이듯이 백문이 불여일행, 몸으로 익히는 공부가 제일 좋다. 다음의 간단한 예제로 WebSocket API를 구현해 보고 어떻게 활용할 수 있는지 알아보자.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    if ('WebSocket' in window) {
        var oSocket = new WebSocket(“ws://localhost:80”);
     
        oSocket.onmessage = function (e) {
            console.log(e.data);
        };
     
        oSocket.onopen = function (e) {
            console.log(“open”);
        };
     
        oSocket.onclose = function (e) {
            console.log(“close”);
        };
     
        oSocket.send(“message”);
        oSocket.close();
    }

    이 몇줄의 코드만 알고 있어도 WebSocket API를 사용할 수 있다. ws://가 눈에 띌 수도 있을 것 같다. WebSocket 프로토콜을 나타내는 ws://는 URI 스키마(Scheme)를 사용한다. 암호화 소켓은 https://처럼 wss://를 사용한다.

    위의 코드를 실행하면 먼저 new WebSocket() 메서드로 웹서버와 연결한다. 그리고 생성된 WebSocket 인스턴스를 이용하여 소켓에 연결할 때(onopen), 소켓 연결을 종료할 때(onclose), 메시지를 받았을 때(onmessage) 등의 이벤트를 각각 정의할 수 있다. 서버에 메시지를 보내고 싶을 때에는 send() 메서드를 이용한다. 그 외에 WebSocket API에 대한 더 자세한 내용은 http://dev.w3.org/html5/websockets/#the-websocket-interface를 참조한다.

  • 그렇다면 Socket.io는 무엇인가?

    WebSocket은 다가올 미래의 기술이지 아직 인터넷 기업에서 시범적으로라도 써 볼 수 있는 기술이 아니다. WebSocket이 미래의 기술이라면 Socket.io는 현재 바로 사용할 수 있는 기술이다. Socket.io는 JavaScript를 이용하여 브라우저 종류에 상관없이 실시간 웹을 구현할 수 있도록 한 기술이다.

    Guillermo Rauch가 만든 Socket.io는 WebSocket, FlashSocket, AJAX Long Polling, AJAX Multi part Streaming, IFrame, JSONP Polling을 하나의 API로 추상화한 것이다. 즉 브라우저와 웹 서버의 종류와 버전을 파악하여 가장 적합한 기술을 선택하여 사용하는 방식이다. 가령 브라우저에 Flash Plugin v10.0.0 이상(FlashSocket 지원 버전)이 설치되어 있으면 FlashSocket을 사용하고, Flash Plugin이 없으면 AJAX Long Polling 방식을 사용한다.

    개발자가 각 기술을 깊이 이해하지 못하거나 구현 방법을 잘 알지 못해도 사용할 수 있다. Web Socket과 달리 Socket.io는 표준 기술이 아니고 Node.js 모듈로서 Guillermo Rauch가 CTO로 있는 LearnBoost(https://www.learnboost.com)라는 회사의 저작물이며 MIT 라이센스를 가진 오픈소스이다. 현재 Node.js가 아닌 다른 프레임워크에서 Socket.io를 사용할 수 있도록 하는 시도가 있다.

  • Socket.io를 사용해 보자

    Socket.io는 WebSocket과 마찬가지로 브라우저에서는 JavaScript를 사용한다. WebSocket 프로토콜은 IETF에서 관장하는 표준 프로토콜이라서 WebSocket을 지원하는 여러 서버 구현체(Jetty, GlassFish, Node.js, Netty, Grizzly 등)가 있지만 Socket.io는 Node.js 하나 밖에 없다.

    Socket.io를 사용하려면 다음과 같이 NPM(Node Package Management)을 이용하여 Socket.io를 웹 서버에 설치한다.

    1
    npm install socket.io

    설치 후 아래와 같이 서버 스크립트를 작성한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 80 포트로 소켓을 연다
    var io = require('socket.io').listen(80);
     
    // connection이 발생할 때 핸들러를 실행한다.
    io.sockets.on('connection', function (socket) {
    // 클라이언트로 news 이벤트를 보낸다.
        socket.emit('news', { hello: 'world' });
     
    // 클라이언트에서 my other event가 발생하면 데이터를 받는다.
    socket.on('my other event', function (data) {
            console.log(data);
        });
    });

    작성한 스크립트를 nohup 등을 이용하여 백그라운드로 실행한다. nohup을 사용하면 hang-up signal이 발생해도 스크립트의 동작이 멈추지 않는다.

    1
    nohup node ./server.js &

    클라이언트는 Socket.io 패키지에 있는 클라이언트 스크립트를 이용하여 아래와 같이 작성한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <script src="/socket.io/socket.io.js"></script>
    <script>
    // localhost로 연결한다.
    var socket =
      io.connect('http://localhost');
     
    // 서버에서 news 이벤트가 일어날 때 데이터를 받는다.
    socket.on('news',
      function (data) {
        console.log(data);
      //서버에 my other event 이벤트를 보낸다.
        socket.emit('my other event',
          { my: 'data' });
    });
    </script>

    이로써 Socket.io를 사용할 준비는 모두 끝났다. 브라우저에서 클라이언트 페이지를 열면 클라이언트 콘솔에는 "{ hello : 'world' }"가, 서버 콘솔에는 "{ my : 'data' }"가 출력되는 것을 확인할 수 있을 것이다.

    io.Socket() 메서드를 호출하면 웹 서버(Node.js를 이용하는 웹 서버)와 연결한다. 이때 서버로부터 sessionid 정보와 timeout 정보를 받고, 브라우저의 WebSocket 지원 여부, FlashSocket 지원 여부를 보내고 크로스 도메인 설정 정보 등을 주고 받은 후 적합한 실시간 웹 방식을 선택한다.

    Socket.io를 활용하는 다양한 예제는 http://socket.io/#how-to-use에서 확인할 수 있다.

  • 마치며

    실시간으로 상호작용하는 웹 서비스를 짧은 시간 안에 쉽게 구현할 수 있는 기술은 빠르게 발전하고 있다. 지금보다 훨씬 더 다양하게 상호작용하는 UX가 선보일 것이라는 게 막연한 공상은 아닐 것이다. 웹 소켓이나 Socket.io 모두 현재 발전 중인 기술이다. 이 기술이 발전하는 과정을 지켜보는 것은 큰 즐거움이 될 것이라고 생각한다.


  • 출처 - http://helloworld.naver.com/helloworld/1336


    ===================================================================================


    node.js 유용한 모듈 (8) – socket.io

    본 게시물은 원저자의 허락을 얻어 번역된 것입니다.

    원문 링크 - http://www.catonmat.net/blog/nodejs-modules-socketio/

    1회 연재 – dnode (RPC 라이브러리) 
    2회 연재 – optimist (옵션 파서) 
    3회 연재 – lazy (lazy 리스트 처리) 
    4회 연재 – request (HTTP 스트림 처리) 
    5회 연재 – hashish (해시 처리)
    6회 연재 – read(쉬운 표준 입력 처리)
    7회 연재 – ntwitter(트위터 API)

    이번에 소개할 모듈은 socket.io다. 여러분들 대부분이 socket.io 모듈에 대해서 알고 있을 거라 생각하지만, 몇몇분들이 나에게 socket.io에 대한 기사를 다뤄줄 것을 요청했기 때문에 연재에서 포함시키기로 했다.

    socket.io는 웹소켓 만들고 이를 통해 모든 브라우저에서 실시간 처리가 가능하게끔 해준다. 그것은 또한 빌트인 멀티플렉싱, 수평적 확장, 그리고 자동 JSON  인코딩/디코딩을 제공함으로써 웹소켓의 기능을 향상시켜준다. Socket.io는 LearnBoost의 공동 창업자인 Guillermo Rauch에 의해 작성됐다.

    socket.io는 현재 환경에서 가능한 최상의 실시간 커뮤니케이션 방법을 선택한다. 여기 socket.io가 지원하는 모든 커뮤니케이션 방법 리스트가 있다.

    • WebSocket
    • Adobe® Flash® Socket
    • AJAX long polling
    • AJAX multipart streaming
    • Forever Iframe
    • JSONP Polling

    예를 들어, 만약 여러분이 크롬 브라우저를 사용한다면 socket.io는 웹소켓을 사용할 것이다. 만약 웹 소켓을 지원하지 않는 브라우저를 사용한다면, 플래시 소켓, 롱 폴링 순으로 커뮤니케니션 방법을 설정할 것이다.

    가장 기본적인 socket.io 예제를 살펴보자.

    var io = require('socket.io');
    var express = require('express');
    
    var app = express.createServer()
    var io = io.listen(app);
    
    app.listen(80);
    
    io.sockets.on('connection', function (socket) {
      socket.emit('news', { hello: 'world' });
      socket.on('my other event', function (data) {
        console.log(data);
      });
      socket.on('disconnect', function () {
        console.log('user disconnected');
      });
    });

    이 예제는 아주 훌륭한 express라는 node 웹 프레임워크(express 모듈은 곧 연재에서 다룰 것이다)를 사용하는데, 웹 서버의 포트를 80번으로 설정하고 socket.io를 추가했다.

    socket.io는 새로운 커넥션 연결을 대기하다가 브라우저가 새 커넥션을 생성할 때, 브라우저로 다시 { hello: 'world' }객체를 보내는 news 이벤트를 발생시킨다.

    그것은 또한 my other event와 disconnect의 이벤트 핸들러를 설정한다. 웹 애플리케이션이 이런 이벤트들을 발생시키면, socket.io는  function (data) { console.log(data); } 콜백을 호출하는데 이는 단지 data를 콘솔에 출력하는 역할을 한다.

    아래 코드는 클라이언트 측 코드이다. (브라우저에서 동작)

    <script src="/socket.io/socket.io.js"></script>
    <script>
      var socket = io.connect('http://localhost');
      socket.on('news', function (data) {
        console.log(data);
        socket.emit('my other event', { my: 'data' });
      });
    </script>

    우선 socket.io.js 스크립트를 로드하고, http://localhost 으로 socket.io 커넥션을 생성한다. 이때 socket.io는 브라우저가 지원하는 가장 최선의 커뮤니케이션 방법을 선택한다. 만약 브라우저가 크롬이라면 웹소켓을 사용할 것이다. 그렇지 않다면 위에서 소개한 커뮤니케이션 방법 중에서 플래시 소켓, 롱 폴링 등의 순서로 순차적으로 조사하여 가장 최상의 방법을 선택할 것이다. 그런 다음엔 news 이벤트를 수신 대기하다가, 해당 이벤트가 발생하면 my other event 이벤트를 발생시킨다.

    이런 식으로 여러분은 모든 종류의 실시간 애플리케이션 (가령,  웹 채팅 서버 와 웹 IRC 클라인트)을 개발할 수 있다.

    socket.io는 네임스페이스, volatile 메시지 , 메시지 수신 확인 그리고 메시지 브로드캐스팅 같은 기능도 지원한다. 좀더 자세한 내용은 socket.io 도움말을 살펴보기 바란다.

    npm을 통해 socket.io를 설치할 수 있다.

    npm install socket.io

    Socket.io의 GitHub 사이트: https://github.com/LearnBoost/socket.io.

    아울러 socket.io 기반으로 RPC 함수를 호출했던 dnode (1회 연재)를 살펴보기 바란다.

    If you love these articles, subscribe to my blog for more, follow me on Twitter to find about my adventures, and watch me produce code on GitHub!

    관련 글:

    1. Node.js를 활용하여 웹페이지 긁어오기.
    2. node.js 유용한 모듈 (7) – ntwitter
    3. node.js 유용한 모듈 (6) – read
    4. node.js 유용한 모듈 (5) – hashish
    5. node.js 유용한 모듈 (4) – request
    6. node.js 유용한 모듈 (3) – lazy
    7. node.js 유용한 모듈 (2) – optimist
    8. node.js 유용한 모듈 (1) – dnode
    9. cloud9을 활용한 node.js 프로그래밍
    10. npm 1.0 간단정리


    출처 - http://nodejs-kr.org/insidejs/archives/704


    ===================================================================================



    'Framework & Platform > Node.js' 카테고리의 다른 글

    node.js - 이클립스에서 디버깅  (0) 2012.07.16
    node.js - npm 1.0 사용하기  (0) 2012.07.16
    node.js - CentOS에서 설치(install in linux)  (0) 2012.07.03
    node.js - 소개 3  (0) 2012.06.07
    node.js - 소개 2  (0) 2012.06.07
    Posted by linuxism
    ,