Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

node.js는 무엇인가? #2 : Hello World 실행하기

이 포스팅은 node.js는 무엇인가? #1에 이어진 포스팅입니다.



Hello World에 대한 예제는 여러가지가 있지만 아무래도 node.js를 만든 Ryan Dahl가 보여준 예제가 node.js를 가장 잘 표현해 주는것 같아서 Ryan Dahl가 JSConf에 사용한 Hello World 예제를 그대로 사용하였습니다. nettuse+의 Learning Server-Side JavaScript with Node.js에 나온 소스도 참고하시면 도움이 될 듯 합니다.



Node.js 설치하기
Node.js는 Mac OS X, Linux, FreeBSD같은 Unix기반의 시스템에서만 구동됩니다. (최근 Windows쪽에서도 할 수잇다느 포스팅을 본적이 있는것 같은데 지금은 찾을  수 없네요.) Node.js v0.6.x부터는 Windows에서도 동작합니다.

node.js를 다운로드 받습니다. node.js 공식사이트에서 최신 릴리즈버전을 다운로드를 받을 수 있으며 현재 버전은 0.1.97입니다. 다운로드 받은 파일을 원하는 위치에 압축을 풀면 됩니다. Node.js는 GITHUB에서 저장소를 사용하고 있기 때문에 GIT을 이용해서 git clone http://github.com/ry/node.git 명령어을 사용하면 현재 개발중인 최신소스를 받아서 테스트 해 볼 수 있습니다.

node.js가 소스가 있는 폴더로 이동하여 다음과 같은 명령어를 실행합니다.
./configure
make
sudo make install

설치할때 각 라이브러리를 체크하는데 단순히 현재 시스템에 지원여부를 체크하는 것이므로 not found라고 나와도 문제가 있는 것이 아니므로 신경쓰지 않아도 됩니다. (./configure를 하지 않으면 Project not configured 오류가 발생합니다.)

Node.js를 실행하기 위해서는 Node.js의 node명령어를 사용해야 하기 때문에 환경변수 path에 node.js가 설치된 경로(/Users/Outsider/node 같은)를 추가하면 아무데서나 node명령어를 사용할 수 있습니다.(우분투에서는 sudo gedit /etc/environment로 OSX는 sudo vi /etc/paths를 사용해서 PATH를 수정해 볼 수 있습니다. 수정된 PATH는 재로그인 후에 적용이 되며 env나 echo $PATH를 사용해서 확인할 수 있습니다.) V8은 내장되어 있고 별도의 의존성이 전혀 없기 때문에 설치하고 바로 사용할 수 있습니다.



Hello World 실행하기
아래의 예제들은 Node.js 0.1.96버전을 사용하였습니다. Ryan Dahl가 시연했던 코드와는 API가 변경된 내용이 많기 때문에 아래의 예제들은 0.1.96버전에서 동작하도록 수정하였습니다.

// helloworld1.js
var sys = require("sys")
setTimeout(function() {
    sys.puts("world");
}, 2000);
sys.puts("hello");

Hello World 예제입니다.

node helloworld1.js

위의 명령어를 실행하면 node.js가 실행됩니다. Node.js는 더이상 할일이 없으면 자동으로 종료됩니다.

Hello World 실행화면



Hello World 실행하기2

puts = require("sys").puts;

setInterval(function() {
    puts("hello");
}, 500);

process.addListener("SIGINT", function() {
    puts("good-bye");
    process.exit(0);
});

Hello World 실행화면

두번째 예제입니다. setIntervla을 이용해서 hello라는 메시지를 0.5초마다 계속 반복적으로 출력해 주고 종료명령인 Ctrl + C를 입력하면 good-bye라는 메시지를 출력한 후에 종료해줍니다. process는 V8 그 자체를 의미합니다. process에 SIGINT라는 이벤트리스너를 추가하여 해당시그널이 왔을때 이벤트가 발생하게 됩니다.



TCP 서버 예제

var tcp = require("net");

var s = tcp.createServer();
s.addListener("connection", function(c) {
    c.write("hello!");
    c.end();
});

s.listen(8000);

TCP 서버 예제입니다. 1번라인의 tcp는 현재 버전에서 net으로 변경되었으며 5번라인의 send()는 write()로, 6번라인의 close()는 end()로 변경되었기 때문에 현재 버전에 맞게 수정되었습니다.

TCP 서버 실행화면

위 화면에서 뒷쪽의 터미널에서 TCP서버를 실행시켜두고 터미널을 새로 띄워서 localhost에 TCP서버에 접속한 것입니다. 작성해 놓은대로 hello!를 출력한 뒤에 접속을 종료합니다. 9번 라인에서 TCP서버는 8000포트를 이용하도록 설정되어 있습니다. net객체는 접속이 들어올때마다 connection이벤트를 발생시키며 HTTP 업로드가 될때 각 패킷마다 body 이벤트가 호출됩니다.

구버전의 API를 사용했을때 오류메시지

아직 완전히 API가 Fix되지 않았기 때문에 버전에 따라서 변경되는 내용들이 있는 상황입니다. 일일이 다 테스트 해 본것은 아니지만 버전에 따라 변경되는 내용이 존재하고 있고 바로바로 문서에 반영되는 것은 아니기 때문에 상황에 따라서는 소스를 직접 열어보아야 하는 상황입니다만 위의 화면처럼 현재버전의 require("sys")대신 구버전에서 사용하던 require("tcp")를 사용할 경우 'tcp'가 'net'으로 변경되었다고 친절하게 알려줍니다.

connection리스너는 createServer의 첫번째 아규먼트로 사용할 수 있기 때문에 위의 코드는 아래처럼 변경할 수 있습니다.

var tcp = require("net");

 tcp.createServer(function(c) {
     c.write("hello!\n");
    c.end();
 }).listen(8000);




Simple HTTP 서버 예제

var http = require("http");
    
http.createServer(function(req, res) {
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.write("Hello\r\n");
    res.write("World\r\n");
    res.end();
}).listen(8080);


Simple HTTP서버 실행화면

웹브라우저에서 접속하면 서버에서 작성한대로 Hello world가 정상적으로 출력됩니다.



스트리밍 서버 예제

var http = require("http");
    
http.createServer(function(req, res) {
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.write("Hel");
    res.write("lo\r\n");
    
    setTimeout(function() {
        res.write("World\r\n");
        res.end();
    }, 2000);
}).listen(8000);



스트리밍서버 실행화면

웹브라우저에서는 스트림을 비동기로 받아지지 않아서 curl을 사용해서 테스트하였습니다. 접속하면 Hello가 바로 찍힌뒤 setTimeout으로 설정한대로 2초뒤에 World가 출력되고 접속이 종료됩니다.



node.js의 시스템 접근 예제

var sys = require("sys"),
    spawn = require("child_process").spawn;

var ls = spawn("ls", ["-ls", "/"]);

ls.stdout.addListener("data", function(data) {
    sys.print(data);
});


시스템접근 실행화면

위 예제는 시스템에 접근하는 예제입니다. ls -ls /을 실행하여 그 결과를 출력하여줍니다. Node.js는 앞에서도 언급했든이 버퍼링을 강제하지 않습니다. data를 child process의 STDIO를 통해서 스트림하도록 저레벨의 기능(facility)을 사용합니다. (Simple IPC 예제는 chile process의 방법이 완전히 바뀐것 같은데 어떻게 똑같은 예제를 만들어야 할지 전혀 모르겠더군요. ㅠㅠ)



Epilogue
간단히 헬로월드만 따라해보고는 Node.js를 감히 판단할 수는 없겠지만 Node.js가 보여주는 미래는 놀랍습니다. 이벤트드리븐을 이용해서 서버의 퍼포먼스를 엄청나게 끌어들일 수 있으면 현재 프론트앤드 개발자가 가지고 있는 Javascript 스킬을 그대로 사용해서 자신이 원하는 웹서버를 직접 만들어 낼 수 있습니다. 엔터프라이즈급의 서버까지 만들어 낼 수 있을지는 아직 판단하기 어렵지만 정해진 일정기능의 서버는 아주 간단하게 충분한 퍼포먼스를 가지고 만들어 낼 수 있을 듯 합니다. 현재 버전이 0.2도 가지 않은 상황에서 수많은 모듈들이 개발되고 있는 것으로 보아도 그 미래가 상당히 기대가 됩니다. 아마 올해 node.js를 많이 만지게 될것 같습니다.


updated: 2012-01-08
2010/06/06 23:18 2010/06/06 23:18