Node v0.2.6
  1. v0.2.6
  2. 한글 번역

node.js v0.2.6 한글 번역

Synopsis

예제 : "Hello World"를 응답하는 Node 웹서버

var http = require('http');

http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World\n');
}).listen(8124);

console.log('Server running at http://127.0.0.1:8124/');

이 서버를 구동하기 위해서 위 코드를 example.js에 쓰고 node 프로그램을 통해 실행시켜보자.

> node example.js
Server running at http://127.0.0.1:8124/

이 문서에 있는 모든 예제들은 이와 유사하게 실행될 것이다.

Standard Modules

Node와 함께 컴파일되는 수많은 모듈들의 대부분이 아래 문서화 되어 있다. 이 모듈들을 사용하는 가장 일반적인 방법은 require('name') 를 쓰고 리턴값을 같은 이름의 지역변수에 할당하면 된다.

예제:

var sys = require('sys');

Node는 다른 모듈들과의 확장도 가능하다. "Modules"를 참고하기 바란다.

Buffers

순수 자바스크립트는 유니코드와 비슷하지만, 이진데이타에는 좋지 않다. TCP 스트림이나 파일시스템을 다룰때는 옥텟 스트림을 핸들링할 필요가 있다. Node는 이러한 옥텟 스트림을 만들고, 사용하고, 조작하는 여러가지 전략이 있다.

Raw data는 Buffer 클래스의 인스턴스에 저장이 된다. 이 Buffer는 인티저의 배열과 흡사하지만 V8 힙의 바깥에서 raw memory에 상응한다. Buffer는 리사이징 할 수 없다.

Buffer 객체는 전역이다.

Buffer 에서 자바스크립트의 String 객체로 변환할 때는 explicit 인코딩 메소드가 필요하다. 스트링 인코딩 메소드는 다음과 같다.

new Buffer(size)

- size 옥텟만큼의 새로운 Buffer를 할당한다.

new Buffer(array)

- 옥텟들로 이루어진 하나의 배열만큼 새로운 buffer를 할당한다.

new Buffer(str, encoding='utf8')

- 주어진 str을 가지는 새로운 buffer를 할당한다.

buffer.write(string, offset=0, encoding='utf8')

- "string"을 주어진 encdoing을 사용하여 buffer에 쓴다. 쓰여진 옥텟의 수가 리턴된다. 만약 buffer가 전체 스트링을 담을 정도의 공간을 가지고 있지 않다면 스트링의 일부만을 쓸 것이다. utf8의 경우에 부분적인 문자를 쓰지 않는다.

예제 : utf8 스트링을 Buffer에 쓰고 프린트하기

buf = new Buffer(256);
len = buf.write('\u00bd + \u00bc = \u00be', 0);
console.log(len + " bytes: " + buf.toString('utf8', 0, len));
// 12 bytes: ½ + ¼ = ¾

buffer.toString(encoding, start=0, end=buffer.length) - 디코딩 후 주어진 encoding으로 start에서 end까지의 buffer data를 스트링으로 리턴한다.

위의 buffer.write()를 보자.

Buffer[index] - index의 옥텟을 가져와서 세팅한다. 각각의 바이트의 값을 나타내는데, 이 값의 범위는 0x00~0xFF 혹은 0~255 이다.

예제 : 아스키 스트링을 buffer에 한번에 한 바이트씩 복사한다.

str = "node.js";
buf = new Buffer(str.length);

for (var i = 0; i < str.length ; i++) {
  buf[i] = str.charCodeAt(i);
}

console.log(buf);

// node.js

Buffer.byteLength(string, encoding='utf8') - 스트링의 실제 바이트 길이를 리턴한다. 이는 스트링의 문자 수를 리턴하는 String.prototype.length 와 같지 않다.

예제

str = '\u00bd + \u00bc = \u00be';

console.log(str + ": " + str.length + " characters, " +
  Buffer.byteLength(str, 'utf8') + " bytes");

// ½ + ¼ = ¾: 9 characters, 12 bytes

buffer.length - buffer의 사이즈를 바이트단위로 리턴한다.이는 반드시 컨텐트의 사이즈를 나타내는 것은 아님을 주의하자. length는 buffer 객체가 할당된 메모리의 양을 나타낸다. 이는 컨텐트가 변할 때, 변하지 않는다.

buf = new Buffer(1234);

console.log(buf.length);
buf.write("some string", "ascii", 0);
console.log(buf.length);

// 1234
// 1234

buffer.copy(targetBuffer, targetStart, sourceStart, sourceEnd=buffer.length) - buffer들간의 memcpy를 수행한다.

예제 : 두개의 buffer를 만들고, buf1을 16바이트 부터 19바이트째까지 buf2의 8번째 바이트로 복사한다.

buf1 = new Buffer(26);
buf2 = new Buffer(26);

for (var i = 0 ; i < 26 ; i++) {
  buf1[i] = i + 97; // 97 is ASCII a
  buf2[i] = 33; // ASCII !
}

buf1.copy(buf2, 8, 16, 20);
console.log(buf2.toString('ascii', 0, 25));

// !!!!!!!!qrst!!!!!!!!!!!!!

buffer.slice(start, end) - 원래 buffer의 start에서 end까지를 자른 새로운 buffer를 리턴한다. 이 buffer는 원래 buffer의 같은 메모리를 참조한다.

새로운 buffer를 수정하는 것은 원본 buffer의 메모리를 수정하게 되는 것을 명심해라!

예제 : 아스키 알파벳으로 이루어진 buffer를 만들어 slice하고 원본 buffer의 1 바이트를 수정한다.

var buf1 = new Buffer(26);

for (var i = 0 ; i < 26 ; i++) {
  buf1[i] = i + 97; // 97 is ASCII a
}

var buf2 = buf1.slice(0, 3);
console.log(buf2.toString('ascii', 0, buf2.length));
buf1[0] = 33;
console.log(buf2.toString('ascii', 0, buf2.length));

// abc
// !bc

EventEmitter

node에 있는 많은 객체들은 이벤트를 발생시킨다: 가령 TCP서버는 스트림이 들어올 때 마다 이벤트를 발생시키고, 자식 프로세스는 죽을 때 이벤트를 발생시킨다. 이벤트를 발생시키는 모든 객체들은 events.EventEmitter의 인스턴스이다.

이벤트는 "camel-cased" 방식으로 표현된다. 예: "stream", "data", "messageBegin"

이벤트가 발생했을 때 실행되는 함수가 객체에 추가될 수 있는데, 이러한 함수들을 listener라고 한다.

EventEmiiter class에 접근하려면 require('events').EventEmitter 라고 쓰면 된다.

모든 EventEmitters는 새로운 listener가 더해졌을 때, "newListener" 이벤트를 발생한다.

EventEmitter에서 에러가 발생하면 "error"이벤트를 발생한다. 에러 이벤트는 특별하다. 만약 이런 이벤트에 대한 핸들러가 없다면 스택 트레이스를 출력하고 프로그램을 종료할 것이다.

Event: 'newListener' function(event, listener) {}
이 이벤트는 새로운 listener가 등록될 때 발생한다.

Event: 'error' function(exception) {}
에러가 발생했을 때 이 이벤트가 발생한다. 이 이벤트는 특별하다. 이 에러를 받는 핸들러가 없다면 node는 프로그램을 종료하고 스택트레이스를 출력한다.

emitter.on(event, listener)
특정 이벤트를 받기 위한 listener를 listener 배열의 마지막에 추가한다.

server.on('stream', function (stream) {
  console.log('someone connected!');
});

emitter.removeListener(event, listener)
특정 이벤트에 대한 listener를 listener 배열에서 제거한다.
주의 : 이 때 배열의 index가 변한다.

var callback = function(stream) {
  console.log('someone connected!');
};
server.on('stream', callback);
// ...
server.removeListener('stream', callback);

emitter.removeAllListeners(event)
특정 이벤트에 대한 모든 listener를 제거한다.

emitter.listeners(event)
특정 이벤트에대한 listener 배열을 리턴한다. 이 배열은 listener 제거와 같은 조작을 할 수 있다.

server.on('stream', function (stream) {
  console.log('someone connected!');
});
console.log(sys.inspect(server.listeners('stream'));
// [ [Function] ]

emitter.emit(event, [arg1], [arg2], [...])
제공된 인자 순서로 각 listener들을 실행한다.

Streams

스트림은 node에서 다양한 객체들을 통해 구현되는 추상화된 인터페이스이다. 예를 들어 HTTP 서버에 대한 요청은 스트림이고 stdout 역시 스트림이다. 스트림은 읽을 수 있고, 쓸 수 있으며, 둘 다 가능하기도 하다. 모든 스트림은 EventEmitter의 인스턴스이다.

Readable Stream

Readable Stream은 다음과 같은 메소드, 멤버, 이벤트를 가진다.

Event:'data'
function(data) {}

'data'이벤트는 버퍼나 스트링에서 setEncoding()이 사용되었을 때 발생한다.

Event:'end'
function() {}

스트림이 EOF(TCP에서는 FIN)를 받을 경우 발생한다. 더이상 'data'이벤트를 발생되지 않는다는 것을 뜻한다. 스트림이 쓰기가능하다면, 쓰기는 계속 진행시킬 수 있을 것이다.

Event:'error'
function(exception) {}

데이타를 받는 도중 에러가 발생한 경우 이 이벤트가 발생한다.

Event:'close'
function() {}

파일 디스크립터가 종료되었을 때 발생한다. 모든 스트림이 이 이벤트를 발생시키지는 않는다( 예를 들면, HTTP 요청은 'close'를 발생시키지 않는다.)

Event:'fd'
function(fd) {}

파일 디스크립터가 스트림을 받았을 때 발생한다. 유닉스 스트림만이 이 기능을 제공한다. 다른 데서는 이 이벤트가 발생하지 않는다.

stream.readable
디폴트는 true이고, 스트림이 'error', 'end'가 발생한 경우 혹은 destroy()가 불린 경우 false를 리턴한다.

stream.setEncoding(encoding)
데이타 이벤트가 만드는 문자열의 encoding을 정한다. encoding은 'utf8', 'ascii', 'base64'가 될 수 있다.

stream.pause()
'data'이벤트를 일시정지한다.

stream.resume()
pause후 'data'이벤트를 재개한다.

stream.destory()
파일디스크립터를 닫는다. 스트림은 더이상 어떤 이벤트도 발생시키지 않을 것이다.

Writable Stream

Writable stream은 다음과 같은 메소드, 멤버, 이벤트를 가진다.

Event: 'drain'
function () { }
다시 쓰기를 해도 된다는 뜻의 false를 리턴하는 write메소드가 불린후 발생한다.

Event: 'error'
function (exception) { }
에러가 발생했을 때 'exception'이라는 예외와 함께 발생한다.

Event: 'close'
function () { }
파일디스크립트가 닫히면 발생한다.

stream.writable
디폴트는 true이고 'error'가 발생하거나 end()/destroy()가 불렸을 때 false를 리턴한다.

stream.write(string, encoding='utf8', [fd])
주어진 encoding으로 스트림에 'string'을 쓴다. 커널 버퍼에 해당 문자열이 플러쉬되면 true를 리턴한다. 커널 버퍼가 꽉차 있을 때는 false를 리턴하고, 이 데이타는 이후에 보내진다. 'drain'이벤트가 커널버퍼가 다시 비어있음을 알려준다. encoding의 디폴트값은 'utf8'이다.
선택사항인 fd 파라미터가 지정되면, 스트림을 통해 보내지는 필수적인 파일 디스크립터가 된다. 이것은 유닉스에서만 지원되고 다른 곳에선 무시된다. 이 방식으로 파일 디스크립터에 쓰기를 수행할 때, 부적절한(닫혀있는) 파일디스크립터인 경우 쓰기를 시도하기 전에 이 파일 디스크립터를 닫는다.

stream.write(buffer)
buffer를 사용한다는 것만 빼면 위의 write와 같다.

stream.end()
스트림을 EOF 혹은 FIN을 보내고 종료한다.

stream.end(string, encoding)
주어진 encoding으로 문자열을 보내고 스트림을 EOF나 FIN을 보내고 종료한다. 이것은 보내지는 패킷의 수를 주일 때 유용하다.

stream.end(buffer)
'buffer'를 사용한다는 것만 빼면 위 end와 같다.

stream.destroy()
파일디스크립터를 닫는다. 스트림은 더이상 이벤트를 발생시키지 않는다.

Global Objects

이 객체들은 전역 범위에서 사용될 수 있고, 어디서든 접근 가능하다.

global
전역 네임스페이스 객체

process
프로세스 객체. 'process object' 섹션을 보도록 하자.

require()
모듈을 얻는다. 'Modules' 섹션을 보도록 하자.

require.paths
require()를 위한 탐색 path들에 대한 배열. 이 배열은 사용자가 정의하는 path를 등록할 수 있다.
예제 : 탐색 리스트의 처음에 새 path 등록하기

require.paths.unshift('/usr/local/node');
console.log(require.paths);
// /usr/local/node,/Users/mjr/.node_libraries

__filename
실행되는 스크립트의 파일 이름. 절대경로이며, 커맨드라인 인자로 전달되는 파일이름과 반드시 같지는 않다.
예제: /Users/mjr 에서 node example.js 실행중

console.log(__filename);
// /Users/mjr/example.js

__dirname
스크립트가 실행되는 디렉토리 이름
예제: /Users/mjr 에서 node example.js 실행중

console.log(__dirname);
// /Users/mjr

module
현재 모듈에 대한 (process.Module 타입의) 레퍼런스. 특히 module.exports는 exports 객체와 같다. 자세한 것은 src/process.js를 보기 바란다.

process

process 객체는 전역 객체이며 어디서든 접근할 수 있다. EventEmitter의 인스턴스이다.

Event: 'exit'
function() {}
프로세스가 종료될 때 발생한다. 모듈의 수행시간을 체크할 때 좋다. 'exit' 콜백이 끝나면 메인 이벤트 루프는 더이상 돌지 않고, 타이머도 기록되지 않는다.

exit 이벤트를 리스닝하는 예제

process.on('exit', function () {
  process.nextTick(function () {
   console.log('This will not run');
  });
  console.log('About to exit.');
});

Event: 'uncaughtException'
function(err) {}
익셉션이 이벤트 루프로 항상 돌아올 때 발생한다. 특정 리스너가 이 익셉션에 추가되면 스택 트레이스를 출력하고 종료되는 디폴트 액션이 일어나지 않는다.

uncaughtException을 리스닝하는 예제

process.on('uncaughtException', function (err) {
  console.log('Caught exception: ' + err);
});

setTimeout(function () {
  console.log('This will still run.');
}, 500);

// Intentionally cause an exception, but don't catch it.
nonexistentFunc();
console.log('This will not run.');

uncaughtException은 익셉션 핸들링에 있어서 상당히 엉성한 매커니즘이다. try/catch구문을 사용하는 것이 여러분의 프로그램의 흐름을 제어하는데 더 도움이 될것이다. 특별히, 영구적으로 돌아야 하는 서버인 경우 uncaughtException은 안전을 위한 유용한 메커니즘이 될 수 있다.

Signal Events
function() {}
프로세스가 시그널을 받으면 발생한다. 스탠다드 POSIX 시그널 이름(SIGINT, SIGUSR1 등)들의 리스트에서 sigaction(2)를 보기 바란다.

SIGINT를 리스닝하는 예제

var stdin = process.openStdin();

process.on('SIGINT', function () {
  console.log('Got SIGINT.  Press Control-D to exit.');
});

SIGINT 시그널을 보내는 쉬운 방법은 CONTROL-C를 누르는 것이다.

process.stdout
stdout에 쓰기 가능한 스트림을 보낸다.
예제: console.log 의 정의

console.log = function (d) {
  process.stdout.write(d + '\n');
};

process.openStdin()
스탠다드 인풋 스트림을 열고 읽기 가능한 스트림을 리턴한다.
스탠다드 인풋을 열고 두개의 이벤트를 리스닝하는 예제

var stdin = process.openStdin();

stdin.setEncoding('utf8');

stdin.on('data', function (chunk) {
  process.stdout.write('data: ' + chunk);
});

stdin.on('end', function () {
  process.stdout.write('end');
});

process.argv
커맨드라인 인자를 가지는 배열. 첫번째 요소는 'node'가 될 것이다. 두번째는 자바스크립트 파일의 이름이 될 것이고 다음 요소들이 부가적인 인자들이 될 것이다.

// print process.argv
process.argv.forEach(function (val, index, array) {
  console.log(index + ': ' + val);
});

이는 다음을 출력할 것이다.

$ node process-2.js one two=three four
0: node
1: /Users/mjr/work/node/process-2.js
2: one
3: two=three
4: four

process.execPath
시작된 프로세스의 절대 경로.
예제:

/usr/local/bin/node

process.chdir(directory)
프로세스의 현재 작업디렉토리를 변경한다. 실패하면 익셉션을 던진다.

console.log('Starting directory: ' + process.cwd());
try {
  process.chdir('/tmp');
  console.log('New directory: ' + process.cwd());
}
catch (err) {
  console.log('chdir: ' + err);
}

process.compile(code, filename)
더 나은 에러 리포팅을 위한 파일이름을 정할 수 있는 것과 'code'가 로컬 영역을 볼 수 없다는 것을 제외하면, 'eval'과 유사하다. 컴파일된 코드에 의해 스택트레이스가 생성된다면 그 파일이름으로 'filename'이 사용될 것이다.

같은 코드를 돌리기 위해 process.compile과 eval을 사용한 예제

var localVar = 123,
    compiled, evaled;

compiled = process.compile('localVar = 1;', 'myfile.js');
console.log('localVar: ' + localVar + ', compiled: ' + compiled);
evaled = eval('localVar = 1;');
console.log('localVar: ' + localVar + ', evaled: ' + evaled);

// localVar: 123, compiled: 1
// localVar: 1, evaled: 1

process.compile 은 지역 스코프에 접근할 수 없다. 그래서 localVar가 변하지 않았다. eval은 접근할 수 있으므로, localVar가 변한 것을 볼 수 있다.
'code'에서 syntax error가 발생한다면, process.compile은 node를 종료한다. "Script"섹션을 참고하기 바란다.

process.cwd()
프로세스의 현재 작업 디렉토리를 리턴한다.

console.log('Current directory: ' + process.cwd());

process.env
사용자 환경을 담고 있는 객체. environ(7)을 보도록 하자.

process.exit(code=0)
특정 'code'와 함께 프로세스를 종료시킨다. code가 생략된다면 성공 코드인 0과 함께 종료된다.
실패 코드와 함께 종료되려면:

process.exit(1);

node를 실행한 쉘은 종료 코드를 1로서 인식한다.

process.getgid()
프로세스의 그룹 아이디를 얻는다. getgid(2)를 참고하라. 이는 숫자로 표현되는 아이디이지 그룹 이름이 아니다.

console.log('Current gid: ' + process.getgid());

process.setgid(id)
프로세스의 그룹아이디를 세팅한다. setgid(2)를 참고하라. 이는 숫자로 표현되는 아이디나 그룹 이름을 허용한다. 그룹 이름이 들어간다면, 이 메소드는 이 이름을 통해 숫자 아이디를 얻어내는 동안 블록된다.

console.log('Current gid: ' + process.getgid());
try {
  process.setgid(501);
  console.log('New gid: ' + process.getgid());
}
catch (err) {
  console.log('Failed to set gid: ' + err);
}

process.getuid()
프로세스의 사용자 아이디를 얻어낸다. getuid(2)를 참고하라. 이는 숫자로 표현하는 사용자 아이디이고, 사용자 이름이 아니다.

console.log('Current uid: ' + process.getuid());

process.setuid(id) 프로세스의 사용자 아이디를 세팅한다. setuid(2)를 참고하라. 이는 숫자로 표현하는 아이디 뿐 아니라 사용자이름을 허용한다. 사용자 이름이 들어가면, 이 메소드는 이 이름을 통해 숫자 아이디를 얻어내는 동안 블록된다.

console.log('Current uid: ' + process.getuid());
try {
  process.setuid(501);
  console.log('New uid: ' + process.getuid());
}
catch (err) {
  console.log('Failed to set uid: ' + err);
}

proces.version
node의 버전을 보여주는 컴파일 된 프로퍼티

console.log('Version: ' + process.version);

process.installPrefix
node의 prefix를 보여주는 컴파일 된 프로퍼티

console.log('Prefix: ' + process.installPrefix);

process.kill(pid, signal='SIGINT')
프로세스에 시그널을 보낸다. pid는 프로세스의 아이디이며, signal은 보낼 시그널을 정하는 문자열이다. 시그널 이름은 'SIGINT'나 'SIGUSR1'같은 것들이 있다. 생략되면, 시그날은 'SIGINT'가 될 것이다. kill(2)를 참고하라.
이 함수의 이름이 process.kill이라는 이름이기 때문에, 시스템 콜인 kill과 같이 시그널을 보내주는 역할을 한다. 보내진 시그널은 해당 프로세스를 죽이는 것 말고도 다른 일을 할 수 있다.

자신에게 시그날을 보내는 예제

process.on('SIGHUP', function () {
  console.log('Got SIGHUP signal.');
});

setTimeout(function () {
  console.log('Exiting.');
  process.exit(0);
}, 100);

process.kill(process.pid, 'SIGHUP');

process.pid
프로세스의 PID

console.log('This process is pid ' + process.pid);

process.title
'ps'를 통해 보여지는 것을 세팅한다.

process.platform
현재 node를 구동하고 있는 플랫폼( linux2, darwin 등)

process.memoryUsage()
node 프로세스의 메모리 사용량을 나타내는 객체를 리턴한다.

var sys = require('sys');

console.log(sys.inspect(process.memoryUsage()));


이 결과는 다음과 같다.
{ rss: 4935680
, vsize: 41893888
, heapTotal: 1826816
, heapUsed: 650472
}


heapTotal과 heapUsed는 V8의 메모리 사용량을 나타낸다.

process.nextTick(callback)
이벤트 루프의 다음 루프에서 이 콜백을 호출한다. 이는 setTimeout(fn, 0)과는 다르다. 훨씬 효과적이다.

process.nextTick(function () {
  console.log('nextTick callback');
});

process.umask([mask])
프로세스의 파일 모드에 대한 마스킹을 세팅한다. 자식 프로세스는 부모 프로세스의 마스크를 상속 받는다. mask 인자가 주어지면 이전 mask를 리턴하고, 그렇지 않으면 현재 마스크를 리턴한다.

var oldmask, newmask = 0644;

oldmask = process.umask(newmask);
console.log('Changed umask from: ' + oldmask.toString(8) +
            ' to ' + newmask.toString(8));

sys

다음 함수들은 sys 모듈에 있다. 접근하려면 require('sys')를 사용하도록 하자.

sys.print(string)
console.log()와 비슷하지만, 줄넘김을 지원하지 않는다.

require('sys').print('String with no newline');

sys.debug(string)
동기화된 아우풋 함수이다. 프로세스가 블로킹 되고 string이 stderr에 즉시 쓰여진다.

require('sys').debug('message on stderr');

sys.log(string)
타임스탬프와 함께 stdout에 쓰여진다.

require('sys').log('Timestmaped message.');

sys.inspect(object, showHidden=false, depth=2)
객체를 나타내는 문자열을 리턴한다.이는 디버깅에 유용하다.
showHidden이 true면 객체의 non-enumerable한 프로퍼티를 보여준다.
depth가 제공되면, 객체를 서식화하는데 어느 정도의 depth로 들어갈지를 (recurse) 결정한다.이는 복잡한 객체를 분석하는데 도움이 된다.
디폴트값은 2 이다. 무한 recurse를 위해서 depth에 null을 넣으면 된다.
sys 객체의 모든 프로퍼티를 보여주는 예제

var sys = require('sys');

console.log(sys.inspect(sys, true, null));

sys.pump(readableStream, writeableStream, [callback])
Experimental
readableStream으로부터 데이타를 읽고 writableStream에 보낸다. writeableStream.write(data)가 false를 리턴하면, callback은 유일한 인자로 error를 받으며 writeableStream이 닫히거나 error를 발생할때 불린다.

Timers

setTimeout(callback, delay, [arg], [...])
delay 밀리초 후에 callback을 호출하도록 스케쥴한다. clearTimeout()에 쓰이는 timeoutId를 리턴한다. 다른 인자들을 선택적으로 더 callback에 넘겨줄 수 있다.

clearTimeout(timeoutId)
트리거된 타임아웃을 막는다.

setInterval(callback, delay, [arg], [...])
매 delay 밀리초마다 callback을 반복적으로 실행하도록 스케쥴한다. clearInterval()에서 사용되는 intervalId를 리턴한다. 다른 인자들을 선택적으로 더 callback에 넘겨줄 수 있다.

clearInterval(intervalId)
트리거된 인터발을 정지한다.

Child Processes

node는 ChildProcess 클래스를 통해 3방향 popen(3) 기능을 제공한다.
이는 자식의 stdin, stdout, stderr에 논블로킹 방식으로 데이타를 보내주는 것을 가능하게 한다.
자식프로세스를 만들려면, require('child_process').spawn()을 사용하면 된다.
자식 프로세스들은 항상 child.stdin, child.stdout, child.stderr, 세 개의 스트림을 가진다.
ChildProcess는 하나의 EventEmitter이다.

Event: 'exit'
function(code, signal) {}

이 이벤트는 자식프로세스가 종료됐을 때 발생한다. 프로세스가 정상적으로 종료되면, code는 프로세스의 마지막 종료값이 되지만, 그렇지 않은 경우에는 null이 된다. 프로세스가 시그날을 받고 종료되는 경우에는 signal은 시그널의 이름이 되고, 그렇지 않은 경우엔 null이 된다.
waitpid(2)를 보기 바란다.

child.stdin
자식 프로세스의 stdin을 나타내는 Writable stream. end()를 통해 스트림을 종료하는 것은 자식프로세스의 종료로 이어진다.

child.stdout
자식 프로세스의 stdout을 나타내는 readable stream.

child.stderr
자식 프로세스의 stderr을 나타내는 Readable stream.

child.pid
자식 프로세스의 PID

Example

var spawn = require('child_process').spawn,
    grep  = spawn('grep', ['ssh']);

console.log('Spawned child pid: ' + grep.pid);
grep.stdin.end();

child_process.spawn(command, args=[], [options])
주어진 command를 가지고 새로운 프로세스를 실행시킨다. 커맨드라인 인자로 args가 들어간다. 생략되면 args의 디폴트값은 빈(empty) 배열이다.
세번째 인자는 부가적인 옵션들을 정하는 데 쓰인다. 디폴트값은 다음과 같다.

{ cwd: undefined
, env: process.env,
, customFds: [-1, -1, -1]
}


cwd는 프로세스가 실행된 작업 디렉토리를 규정한다. env는 새 프로세스에서 쓰이는 환경변수를 지정한다. customFds는 새 프로세스의 [stdin, stdout, stderr] 스트림을 기존의 스트림으로 연결시킨다. -1은 새로운 스트림이 만들어져야 한다는 것을 의미한다.

'ls -lh /usr'를 실행시키는 예제에서 stdout, stderr, 종료 코드를 캡춰하는 모습이다

var sys   = require('sys'),
    spawn = require('child_process').spawn,
    ls    = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', function (data) {
  sys.print('stdout: ' + data);
});

ls.stderr.on('data', function (data) {
  sys.print('stderr: ' + data);
});

ls.on('exit', function (code) {
  console.log('child process exited with code ' + code);
});

예제 : 'ps ax | grep ssh'를 실행하는 매우 정교한 방법

var sys   = require('sys'),
    spawn = require('child_process').spawn,
    ps    = spawn('ps', ['ax']),
    grep  = spawn('grep', ['ssh']);

ps.stdout.on('data', function (data) {
  grep.stdin.write(data);
});

ps.stderr.on('data', function (data) {
  sys.print('ps stderr: ' + data);
});

ps.on('exit', function (code) {
  if (code !== 0) {
    console.log('ps process exited with code ' + code);
  }
  grep.stdin.end();
});

grep.stdout.on('data', function (data) {
  sys.print(data);
});

grep.stderr.on('data', function (data) {
  sys.print('grep stderr: ' + data);
});

grep.on('exit', function (code) {
  if (code !== 0) {
    console.log('grep process exited with code ' + code);
  }
});

실행이 실패했는지 체크하는 예제

var spawn = require('child_process').spawn,
    child = spawn('bad_command');

child.stderr.on('data', function (data) {
  if (/^execvp\(\)/.test(data.asciiSlice(0,data.length))) {
    console.log('Failed to start child process.');
  }
});

child_process.exec() 도 같이 보도록 하자.

child_process.exec(command, [options], callback)
자식프로세스로서 명령을 실행하는 고수준의 방법이다. 아웃풋을 버퍼링하여 콜백을 통해 모두를 리턴한다.

var sys   = require('sys'),
    exec  = require('child_process').exec,
    child;

child = exec('cat *.js bad_file | wc -l', 
  function (error, stdout, stderr) {
    sys.print('stdout: ' + stdout);
    sys.print('stderr: ' + stderr);
    if (error !== null) {
      console.log('exec error: ' + error);
    }
});

콜백은 (error, stdout, stderr)을 받는다. 성공시, error는 Error의 인스턴스이고, error.code는 자식 프로세스의 종료코드가 될 것이다. 그리고 err.signal에는 프로세스를 종료시킨 시그널이 세팅된다.

두번째 선택적인 인자는 몇가지 옵션을 정할 수 있다. 디폴트값은 다음과 같다.

{ encoding: 'utf8'
, timeout: 0
, maxBuffer: 200*1024
, killSignal: 'SIGTERM'
, cwd: null
, env: null
}

timeout이 0보다 클 경우 자식 프로세스가 timeout만큼의 밀리초가 지나면 종료된다. 이 경우, killSignal(디폴트:SIGTERM)을 통해 종료된다.maxBuffer는 stdout이나 stderr에 허용되는 데이타의 최대값을 정한다. 만약 데이타가 이 값을 초과하면 자식 프로세스는 종료된다.

child.kill(signal='SIGTERM')
자식프로세스에 시그널을 보낸다. 어떤인자도 주어지지 않으면 프로세스는 'SIGTERM'을 받는다. 사용할 수 있는 시그날의 리스트는 signal(7)을 보면 된다.

var spawn = require('child_process').spawn,
    grep  = spawn('grep', ['ssh']);

grep.on('exit', function (code, signal) {
  console.log('child process terminated due to receipt of signal '+signal);
});

// send SIGHUP to process
grep.kill('SIGHUP');

kill 함수가 불리는 동안, 자식 프로세스로 가는 시그날은 실제로 프로세스를 종료시키지는 않을 것이다. kill은 단지 프로세스에게만 시그널을 보낸다.
kill(2)를 보도록 하자.

Script

Script 클래스는 자바스크립트 코드를 컴파일하고 실행시킨다. 다음과 같이 이 클래스에 접근할 수 있다.

var Script = process.binding('evals').Script;

Script.runInThisContext(code, [filename])
process.compile과 유사하다. Script.runInThisContext는 code를 마치 filename에서 로딩된 것처럼 컴파일하고 실행시킨 후 결과를 리턴한다. 실행되는 코드는 지역 스코프에 접근할 수 없다. filename은 선택사항이다.

같은 코드를 Script.runInThisContext와 eval을 실행시키는 예제

var localVar = 123,
    usingscript, evaled,
    Script = process.binding('evals').Script;

usingscript = Script.runInThisContext('localVar = 1;',
  'myfile.js');
console.log('localVar: ' + localVar + ', usingscript: ' +
  usingscript);
evaled = eval('localVar = 1;');
console.log('localVar: ' + localVar + ', evaled: ' +
  evaled);

// localVar: 123, usingscript: 1
// localVar: 1, evaled: 1
Script.runInThisContext 는 지역 스코프에 접근할 수 없기 때문에 localVar가 변하지 않았다. eval은 접근할 수 있으므로 localVar가 변했다.

code에 구문 에러가 있는 경우, Script.runInThisContext는 stderr에 syntax error를 발생시키고, 익셉션을 던진다.

Script.runInNewContext(code, [sandbox], [filename])
Script.runInNewContext는 sandbox와 함께 실행시키기 위해, 마치 filename에서 로드된 것처럼, code를 컴파일하고 실행시킨 후 결과를 리턴한다. 실행되는 code는 지역 스코프에 접근할 수 없고 sandbox객체는 code의 전역 객체로 사용된다. sandbox와 filename은 선택사항이다.

예제 : 전역변수를 증가시키고 새로운 값을 저장하는 코드를 컴파일하고 실행한다. 이 전역변수들은 sandbox안에 포함된다.

var sys = require('sys'),
    Script = process.binding('evals').Script,
    sandbox = {
      animal: 'cat',
      count: 2
    };

Script.runInNewContext(
  'count += 1; name = "kitty"', sandbox, 'myfile.js');
console.log(sys.inspect(sandbox));

// { animal: 'cat', count: 3, name: 'kitty' }

실행되는 신뢰되지 않는 코드는 커다란 주의가 필요한 곤란한 것이다. Script.runInNewContext는 매우 유용하지만, 갑작스런 전역 변수 누설을 막기 위해서 안전하게 다른 프로세스에서 신뢰되지 않는 코드를 실행시킨다.

new Script( code, [filename])
new Script는 code를 마치 filename에서 로드한 것처럼 컴파일하지만 실행시키지는 않는다. 대신, 컴파일된 코드를 나타내는 Script객체를 리턴한다. 이 스크립트는 아래 메소드를 사용하여 이후에 여러차례 실행될 수 있다. 리턴된 스크립트는 어떤 전역객체에도 속하지 않고, 각각 해당 실행(run)에만 속하게 된다.

구문에러가 code에 있는 경우 new Script는 syntax error를 stderr에 발생시키고 익셉션을 던진다.

script.runInThisContext()
Script.runInThisContext 와 유사하다( 대문자 S). 하지만 이번엔 프리컴파일 된 Script객체의 메소드이다. script.runInThisContext는 script의 code를 실행하고 결과를 리턴한다. 실행되는 code는 지역 스코프에 접근할 수 없지만 전역 객체에는 접근할 수 있다.

script.runInThisContext를 사용하여 code를 한번 컴파일하고 여러차례 사용한 예제

var Script = process.binding('evals').Script,
    scriptObj, i;

globalVar = 0;

scriptObj = new Script('globalVar += 1', 'myfile.js');

for (i = 0; i < 1000 ; i += 1) {
  scriptObj.runInThisContext();
}

console.log(globalVar);

// 1000

script.runInNewContext([sandbox])
Script.runInNewContext와 유사하다(대문자S). 하지만 이번엔 프리컴파일된 Script객체의 메소드이다. script.runInNewContext는 script의 code를 전역객체로서의 sandbox와 함께 실행하고 결과를 리턴한다. 실행되는 code는 지역 스코프에 접근할 수 없다. sandbox는 선택사항이다.

예제 : 전역 변수를 증가시키고 저장하는 코드를 컴파일하고 이를 여러차례 실행한다. 이 전역변수들은 sandbox안에 담겨있다.

var sys = require('sys'),
    Script = process.binding('evals').Script,
    scriptObj, i,
    sandbox = {
      animal: 'cat',
      count: 2
    };

scriptObj = new Script(
    'count += 1; name = "kitty"', 'myfile.js');

for (i = 0; i < 10 ; i += 1) {
  scriptObj.runInNewContext(sandbox);
}

console.log(sys.inspect(sandbox));

// { animal: 'cat', count: 12, name: 'kitty' }

실행되는 신뢰되지 않는 코드는 커다란 주의가 필요한 곤란한 것이다. Script.runInNewContext는 매우 유용하지만, 갑작스런 전역 변수 누설을 막기 위해서 안전하게 다른 프로세스에서 신뢰되지 않는 코드를 실행시킨다.

File System

표준 POSIX함수들을 간단히 래핑하여 File I/O가 제공된다. 이 모듈을 사용하려면 require('fs')를 하면 된다. 모든 메소드는 비동기와 동기식의 형태를 가진다.

비동기 형태는 항상 마지막 인자로서 완전한 콜백을 가진다. 콜백에 전달되는 인자는 메소드에 따라 다르지만, 첫번째 인자는 항상 익셉션으로 예약되어 있다. 만약 오퍼레이션이 성공적으로 완료되면 첫번째 인자는 null 이나 undefined가 된다.

비동기 버전에 대한 예제

var fs = require('fs');

fs.unlink('/tmp/hello', function (err) {
  if (err) throw err;
  console.log('successfully deleted /tmp/hello');
});

동기 버전에 대한 예제

var fs = require('fs');

fs.unlinkSync('/tmp/hello')
console.log('successfully deleted /tmp/hello');

비동기 메소드를 사용하는 경우, 순서가 보장되지 않는다. 따라서 다음은 error가 발생하기 쉽다.

fs.rename('/tmp/hello', '/tmp/world', function (err) {
  if (err) throw err;
  console.log('renamed complete');
});
fs.stat('/tmp/world', function (err, stats) {
  if (err) throw err;
  console.log('stats: ' + JSON.stringify(stats));
});
fs.stat이 fs.rename 전에 실행될 수 있다. 이를 제대로 하기 위한 방법은 콜백을 차례로 묶는 것이다.
fs.rename('/tmp/hello', '/tmp/world', function (err) {
  if (err) throw err;
  fs.stat('/tmp/world', function (err, stats) {
    if (err) throw err;
    console.log('stats: ' + JSON.stringify(stats));
  });
});

바쁜 프로세스에서는 프로그래머는 비동기를 사용할 것을 강하게 권장한다. 동기 방식은 모든 연결을 끝낼때까지 프로세스 전체를 블로킹할 것이다.

fs.rename(path1, path2, [callback])
비동기 rename(2). 콜백에 주어지는 인자는 발생 가능한 익셉션밖에 없다.

fs.renameSync(path1, path2)
동기 rename(2).

fs.truncate(fd, len, [callback])
비동기 ftruncate(2). 콜백에 주어지는 인자는 발생 가능한 익셉션밖에 없다.

fs.truncateSync(fd, len)
동기 ftruncate(2).

fs.chmod(path, mode, [callback])
비동기 chmod(2). 콜백에 주어지는 인자는 발생 가능한 익셉션밖에 없다.

fs.chmodSync(path, mode)
동기 chmod(2).

fs.stat(path, [callback])
비동기 stat(2). 콜백은 두개의 인자(err, stats)를 받는다. stats는 fs.Stats 객체이고, 다음과 같은 형태를 가진다.
{ dev: 2049
, ino: 305352
, mode: 16877
, nlink: 12
, uid: 1000
, gid: 1000
, rdev: 0
, size: 4096
, blksize: 4096
, blocks: 8
, atime: '2009-06-29T11:11:55Z'
, mtime: '2009-06-29T11:11:40Z'
, ctime: '2009-06-29T11:11:40Z' 
}

자세한 정보는 아래 fs.Stats 섹션을 보기바란다.

fs.lstat(path, [callback])
비동기 lstat(2). 콜백은 두개의 인자(err, stats)를 받는다. stats는 fs.Stats 객체이고, 다음과 같은 형태를 가진다.

fs.fstat(fd, [callback])
비동기 fstat(2). 콜백은 두개의 인자(err, stats)를 받는다. stats는 fs.Stats 객체이고, 다음과 같은 형태를 가진다.

fs.statSync(path)
동기 stat(2). fs.Stats의 인스턴스를 리턴한다.

fs.lstatSync(path)
동기 lstat(2). fs.Stats의 인스턴스를 리턴한다.

fs.fstatSync(fd)
동기 fstat(2). fs.Stats의 인스턴스를 리턴한다.

fs.link(srcpath, dstpath, [callback])
비동기 link(2). 콜백에 주어지는 인자는 발생 가능한 익셉션밖에 없다.

fs.linkSync(srcpath, dstpath)
동기 link(2).

fs.symlink(linkdata, path, [callback])
비동기 symlink(2). 콜백에 주어지는 인자는 발생 가능한 익셉션밖에 없다.

fs.symlinkSync(linkdata, path)
동기 symlink(2).

fs.readlink(path, [callback])
비동기 readlink(2). 콜백은 두개의 인자를 받는다(err, resolvedPath)

fs.readlinkSync(path)
동기 readlink(2). resolved path를 리턴한다.

fs.realpath(path, [callback])
비동기 realpath(2). 콜백은 두개의 인자를 받는다(err, resolvedPath)

fs.realpathSync(path)
동기 realpath(2). resolved path를 리턴한다.

fs.unlink(path, [callback])
비동기 unlink(2). 발생가능한 익셉션만이 콜백에 주어진다.

fs.unlinkSync(path)
동기 unlink(2).

fs.rmdir(path, [callback])
비동기 rmdir(2). 발생가능한 익셉션만이 콜백에 주어진다.

fs.rmdirSync(path)
동기 rmdir(2).

fs.mkdir(path, mode, [callback])
비동기 mkdir(2). 발생가능한 익셉션만이 콜백에 주어진다.

fs.mkdirSync(path, mode)
동기 mkdir(2).

fs.readdir(path, [callback])
비동기 readdir(3). 디렉토리를 읽는다. 콜백은 두개의 인자를 받는다(err, files). files는 '.'과 '..'을 제외한 디렉토리안의 파일의 이름들에 대한 배열이다.

fs.readdirSync(path)
동기 readdir(3). '.'과 '..'을 제외한 파일이름의 배열을 리턴한다.

fs.close(fd, [callback])
비동기 close(2). 발생가능한 익셉션만이 콜백에 주어진다.

fs.closeSync(fd)
동기 close(2)

fs.open(path, flags, mode=0666, [callback])
비동기 open(2). flags는 r, r+, w, w+, a, a+ 를 쓸 수 있다. 콜백은 두개의 인자를 받는다(err, fd).

fs.openSync(path, flags, mode=0666)
동기 open(2)

fs.write(fd, buffer, offset, length, position, [callback])
fd로 지정된 파일을 buffer에 쓴다.
offset과 length는 쓰여질 버퍼의 offset과 length를 결정한다.
position은 파일의 처음으로부터의 offset을 나타내고, 여기에 데이타가 쓰여진다. position이 null이면, 데이타는 현재 위치에서 부터 쓰여진다. pwrite(2) 를 보도록 하자.
콜백은 두개의 인자가 주어진다(err, written). written은 얼마나 쓰여졌는지를 지정한다.

fs.writeSync(fd, buffer, offset, length, position)
버퍼 기반의 fs.write의 동기식 버전. 쓰여진 데이타의 길이(bytes)를 리턴한다.

fs.writeSync(fd, str, position, encoding='utf8')
문자열 기반의 fs.write의 동기식 버전. 쓰여진 데이타의 길이(bytes)를 리턴한다.

fs.read(fd, buffer, offset, length, position, [callback])
fd로 지정된 파일로부터 데이타를 읽는다.
buffer는 데이타가 쓰여질 버퍼를 의미한다.
offset은 쓰기가 시작될 버퍼의 위치를 나타내는 offset이다.
length는 읽을 데이타 길이를 나타낸다.
position은 파일에서 읽기가 시작될 위치를 나타낸다. position이 null이면 데이타는 파일의 현재위치에서부터 읽기가 시작된다.
콜백은 두개의 인자가 주어진다.(err, bytesRead)

fs.readSync(fd, buffer, offset, length, position)
버퍼기반의 fs.read()의 동기식 버전. bytesRead를 리턴한다.

fs.readSync(fd, length, position, encoding)
문자열 기반의 fs.read()의 동기식 버전. bytesRead를 리턴한다.

fs.readFile(filename, [encoding], [callback])
비동기적으로 파일의 전체 내용을 읽는다.
예제

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});
콜백은 두개의 인자를 받는다(err, data). data는 파일의 내용을 의미한다.
encoding이 지정되지 않으면 raw 버퍼가 리턴된다.

fs.readFileSync(filename, [encoding])
fs.readFile의 동기식 버전. filename의 내용을 리턴한다.
encoding이 지정되면, 이 함수는 문자열을 리턴한다. 그렇지 않으면 버퍼를 리턴한다.

fs.writeFile(filename, data, encoding='utf8', [callback])
비동기적으로 파일에 데이타를 쓴다. data는 문자열이나 버퍼가 될 수 있다.
예제

fs.writeFile('message.txt', 'Hello Node', function (err) {
  if (err) throw err;
  console.log('It\'s saved!');
});

fs.writeFileSync(filename, data, encoding='utf8')
fs.writeFile의 동기식 버전

fs.watchFile(filename, [options], listener)
filename의 변화를 감시한다. 콜백인 listener는 파일의 변화가 생길 때마다 호출된다.
두번째 인자는 선택사항이다. options를 제공하려면, 두개의 멤버(persistent(boolean), interval(밀리초단위의 폴링값))를 가지는 객체여야 한다.
디폴트 값은 {persistent: true, interval: 0} 이다.
listener는 현재 stat 객체와 이전 stat객체 등, 두개의 인자를 받는다.

fs.watchFile(f, function (curr, prev) {
  console.log('the current mtime is: ' + curr.mtime);
  console.log('the previous mtime was: ' + prev.mtime);
});
이 stat 객체들은 fs.Stat의 인스턴스이다.

fs.unwatchFile(filename)
filename의 변화 감시를 멈춘다.

fs.Stats

fs.stat()과 fs.lstat()으로부터 리턴되는 객체들이 이 타입이다.

fs.ReadStream

ReadStream은 읽기 가능한 스트림이다.

fs.createReadStream(path, [options])
새로운 ReadStream 객체를 리턴한다.
options는 다음과 같은 디폴트값을 가지는 객체이다.

{ 'flags': 'r'
, 'encoding': null
, 'mode': 0666
, 'bufferSize': 4 * 1024
}

options는 전체 파일 대신 파일의 특정 영역을 읽을 수 있도록 start와 end 값을 가진다. 둘 다 0에서 시작한다. 이들이 쓰였을 때는 항상 양쪽 모두가 지정되어야 한다.

100바이트 길이를 가진 파일의 마지막 10바이트를 읽는 예제

fs.createReadStream('sample.txt', {start: 90, end: 99});

fs.WriteStream

WriteStream은 쓰기 가능한 스트림이다.

Event:'open'
function(fd){}

fd는 WriteStream에 의해 쓰이는 파일 디스크립터이다.

fs.createWriteStream(path, [options])
새로운 WriteStream 객체를 리턴한다.
options는 다음과 같은 디폴트값을 가지는 객체이다.

{ 'flags': 'w'
, 'encoding': null
, 'mode': 0666
}

HTTP

HTTP 서버와 클라이언트 기능을 사용하기 위해서는 require('http')문을 선언한다.

Node의 HTTP 인터페이스들은 일반적으로 사용하기 힘들었던 다양한 HTTP 프로토콜 특성들을 지원하기 위해 설계됐다. 특히 용량이 크거나 청크 단위로 인코딩 될 수 있는 메시지들을 지원한다. 인터페이스는 전체 request나 response들을 저장하지 않는 것을 주의해라. -- 사용자는 데이터를 스트림할 수 있다.

HTTP 메시지 헤더는 다음과 같은 객체 형태로 표현된다.

{ 'content-length': '123'
, 'content-type': 'text/plain'
, 'stream': 'keep-alive'
, 'accept': '*/*'
}

키들은 소문자로 표현된다. 값들은 수정되지 않는다.

가능한한 모든 범위의 HTTP 애플리케이션들을 지원하기 위해, Node의 HTTP API는 저수준으로 설계됐다. 때문에 API에서는 스트림 처리나 메시지 파싱 기능만을 제공한다. 파싱 기능은 메시지를 헤더와 바디로 구분해서 파싱할 뿐 실제 헤더나 바디의 내용을 파싱하지는 않는다.

HTTPS는 플랫폼에 OpenSSL이 설치됐다면 사용 가능하다.

http.Server

이 객체는 다음과 같은 이벤트를 발생시키는 EventEmitter이다.

'request' 이벤트

function (request, response) { }

requesthttp.ServerRequest의 인스턴스이며 responsehttp.ServerResponse의 인스턴스를 가리킨다.

'connection' 이벤트

function (stream) { }

새로운 TCP 스트림이 생성될 때 발생한다. stream 인자는 net.Stream 타입의 객체이다. 대개 사용자들은 이 이벤트를 처리할 필요가 없다. streamrequest.connection을 통해 접근할 수 있다.

'close' 이벤트

function (errno) { }

서버가 종료할 때 발생한다.

'request' 이벤트

function (request, response) {}

HTTP Request 시 발생. 1개의 연결 내에 다수의 request가 존재할 수 있다. (특히 keep-alive 연결의 경우)

'upgrade' 이벤트

function (request, socket, head)

클라이언트가 http upgrade를 요청할 때 발생한다. 이 이벤트가 수신되지 않는다면 upgrade를 요청한 클라이언트는 연결을 닫을 것이다.

이 이벤트가 발생한 후, request의 소켓에는 data event 리스너가 없을 것이다. 이것은 당신이 소켓에서 서버로 보낸 데이터를 다루기 위해 이 이벤트 바인딩이 필요하다는 것을 의미한다.

'clientError' 이벤트

function (exception) {}

클라인어트 연결에서 error가 생기면 발생한다.

http.createServer(requestListener)

웹 서버 객체를 반환한다.

requestListener 인자는 ’request’ 이벤트가 자동으로 전달될 함수이다.

server.listen(port, [hostname], [callback])

지정된 포트와 호스트네임에 해당하는 연결의 수신을 시작한다. 만약 hostname인자가 생략됐다면 서버는 아무 IPv4 주소(INADDR_ANY)와의 연결을 수신할 것이다.

unix 소켓을 수신하기 위해서는 호스트 네임과 포트 대신에 파일명을 제공해야 한다.

이 함수는 비동기로 동작한다. 마지막 callback 인자는 서버가 포트에 바인딩 됐을때 호출될 것이다.

server.listen(path, [callback])

path인자로 주어진 경로의 파일명으로 접근하는 연결을 수신하는 UNIX 소켓 서버를 시작한다.

이 함수는 비동기로 동작한다. 마지막 callback 인자는 서버가 바인딩 됐을 때 호출될 것이다.

server.setSecure(credentials)

서버가 HTTPS 지원을 가능하게 한다. credentials 인자는 crypto 모듈을 통해 제공되며 개인키와 서버의 인증서 그리고 옵션으로 클라이언트 인증에서 사용될 CA 인증서를 나타낸다.

credentials이 하나 또는 여러개의 CA 인증서를 가지고 있다면, 서버는 HTTPS 연결 핸드세이킹 과정에서 클라이언트가 자신의 인증서를 보내게 끔 요청할 것이다. 여기서 검증이나 컨텐트 내용으로의 접근은 서버의 request.connection의 verifyPeer()과 getPeerCertificate() 함수를 통해 처리할 수 있다.

server.close()

새 연결을 수신하는 웹 서버를 종료한다.

http.ServerRequest

이 객체는 사용자가 아닌 HTTP 서버에 의해 내부적으로 생성된다. 그리고 ’request’ 리스너의 첫번째 인자로 전달된다.

이 객체는 다음과 같은 이벤트를 발생시키는 EventEmitter이다.

'data' 이벤트

function (chunk) { }

하나의 메시지 바디 부분이 수신됐을 때 발생한다.

Example: A chunk of the body is given as the single argument. The transfer-encoding has been decoded. The body chunk is a string. The body encoding is set with request.setBodyEncoding().

'end' 이벤트

function () { }

각 메시지당 한번 발생한다. 인자 없음. 다른 모든 이벤트들이 발생된 후 발생한다.

request.method

HTTP 요청 메서드를 나타내는 문자열이다. 읽기 전용. (예) : ‘GET’, ‘DELETE’

request.url

HTTP 요청 URL을 나타내는 문자열이다. 이것은 실제 HTTP 요청에서 URL 부분만을 포함한다. 만약 HTTP 요청이 다음과 같다면:

GET /status?name=ryan HTTP/1.1\r\n
Accept: text/plain\r\n
\r\n

request.url은 다음과 같다.

'/status?name=ryan'

만일 URL의 특정 부분을 파싱하고 싶다면, require(‘url’).parse(request.url) 구문을 사용할 수 있다.
(예제)

node> require('url').parse('/status?name=ryan')
{ href: '/status?name=ryan'
, search: '?name=ryan'
, query: 'name=ryan'
, pathname: '/status'
}

쿼리 문자열(query string)으로부터 파라메터 값들 추출하기 위해서, require(‘querystring’).parse 함수를 이용하거나 require(‘url’).parse 함수의 두번째 인자에 true를 넘기면 된다.
(예제)

node> require('url').parse('/status?name=ryan', true)
{ href: '/status?name=ryan'
, search: '?name=ryan'
, query: { name: 'ryan' }
, pathname: '/status'
}

request.headers

읽기 전용.

request.httpVersion

HTTP 프로토콜 버전을 나타내는 문자열. 읽기 전용. (예제) ‘1.1’, ‘1.0’ 또한 request.httpVersionMajor는 버전의 메이저 번호를, request.httpVersionMinor은 버전에서 마이너 번호를 나타낸다.

request.setEncoding(encoding=null)

HTTP 요청 바디의 인코딩을 설정. ‘utf8’이나 ’binary’ 값이 가능. encoding 인자의 디폴트 값은 null이며 이것은 ’data’ 이벤트가 Buffer 객체를 전달할 것이다.

request.pause()

발생하는 이벤트를 무시하고 HTTP 요청을 중단한다. 업로드 제어에 유용하다.

request.resume()

중단된 HTTP 요청을 재개한다.

request.connection

HTTP 연결과 관련된 net.Stream 객체를 나타냄.

HTTPS 처리에 필요한 클라이언트의 인증 관련 상세 정보를 얻기 위해서는 request.connection.verifyPeer()와 request.connectino.getPeerCertivicate()를 이용한다.

http.ServerResponse

이 객체는 사용자가 아닌 HTTP 서버에 의해 내부적으로 생성된다. 이것은 ’request’ 이벤트에 두번째 인자로 전달된다. 그것은 Writable Stream 이다.

response.writeHead(statusCode, [reasonPhrase], [headers])

HTTP 요청에 대한 응답 헤더를 보낸다. statusCode 인자는 3자리의 HTTP 상태 코드(가령 404)이다. 마지막 인자인 headers는 응답 헤더들이다. 옵션 값인 두번째 인자 reasonPhrase를 통해 우리가 읽을 수 있는 메시지를 전달할 수 있다.

(예제):

var body = 'hello world';
response.writeHead(200, {
  'Content-Length': body.length,
  'Content-Type': 'text/plain'
});

이 메서드는 메시지당 한번만 호출되고, 반드시 response.end()가 호출되기 전에 호출돼야 한다.

response.write(chunk, encoding='utf8')

이 메서드는 writeHead가 호출된 후 호출돼야 한다. 이것은 청크 단위의 응답 바디를 보낸다. 이 메서드는 바디의 연속된 부분을 보내기 위해 여러 번 호출될 수 있다.

chunk는 스트링이나 버퍼가 가능한다. 만약 chunk가 스트링이면, 두번째 인자는 그것을 어떤 방식으로 바이트 스트림으로 인코딩할 지를 나타낸다. 디폴트 인코딩 방식은 'utf8'이다.

주의: 이것은 별도의 처리를 하지 않은 HTTP 바디 자체이다. 따라서 고수준 멀티파트 바디 인코딩과는 관계가 없다.

response.write()가 최초 호출 시에, 저장된 헤더 정보와 첫번째 바디를 클라이언트에게 전송한다. 두 번째 response.write()가 호출되면 Node는 여러분이 데이터를 스트리밍한다고 가정하고 분리해서 보낸다. 즉 응답은 바디의 첫번째 청크까지 저장된다.

response.end([data], [encoding])

이 메서드는 모든 응답 헤더와 바디를 전송했다고 서버에게 알린다. 즉, 서버는 이것을 메시지 완료로 여긴다. response.end() 메서드는 각 응답마다 반드시 호출돼야 한다.

data 인자가 설정됐다면, 이것의 동작은 response.write(data, encoding)를 호출한 후 response.end()를 호출한 것과 같다.

http.Client

HTTP client는 인자로 전달되는 서버 주소를 통해 생성되고, 반환된 핸들은 다수의 HTTP 요청들을 처리하기 위해서 사용된다. client는 연결된 서버에 따라 HTTP 요청을 파이프라인하거나, 각 스트림 처리 후에 다시 스트림을 연결할 수 있다. (현재 구현은 요청을 파이프라인 하지 않는다.)

google.com에 연결하는 예제:

var http = require('http');
var google = http.createClient(80, 'www.google.com');
var request = google.request('GET', '/',
  {'host': 'www.google.com'});
request.end();
request.on('response', function (response) {
  console.log('STATUS: ' + response.statusCode);
  console.log('HEADERS: ' + JSON.stringify(response.headers));
  response.setEncoding('utf8');
  response.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

주의 깊게 살펴볼 몇가지 특별한 헤더들이 있다.

'upgrade' 이벤트

function (request, socket, head)

서버가 HTTP upgrade 요청에 응답할 때 발생한다. 이 이벤트를 수신하고 있지 않다면 upgrade 헤더를 수신한 클라이언트는 관련한 HTTP 연결을 종료할 것이다.

자세한 설명은 http.Serverupgrade 이벤트 설명 부분을 참조하라.

http.createClient(port, host='localhost', secure=false, [credentials])

HTTP 클라이언트를 생성한다. 인자로 전달되는 porthost는 연결할 서버에 대한 정보다. HTTP 요청이 시작하기 전까지 스트림은 생성되지 않는다.

secure 인자는 옵션값으로 HTTPS 사용을 결정하는 불린(boolean) 플래그다. credentials 인자는 옵션 값으로 crypto 모듈에서 생성된 credentials 객체를 나타낸다. 이 객체는 클라이언트의 개인키, 인증서 그리고 공인된 CA 인증서 리스트를 가진다.

만약 암호화된 연결에서 인자로 전달된 credentials 객체에 CA 인증서들이 포함되지 않았다면, node.js는 http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt 링크에서 제공되는 공인된 CA 인증서를 디폴트로 사용할 것이다.

client.request(method='GET', path, [request_headers])

HTTP 요청을 보낸다. 필요하다면 스트림을 생성한다. http.ClientRequest 인스턴스를 반환한다.

method 인자는 옵션값으로 생략하면 ’GET’ 메서드를 디폴트로 전달한다.

request_headers는 옵션값이다. 부가적인 HTTP 요청 헤더들은 Node에 의해 내부적으로 추가될 수 있다. ClientRequest객체를 반환한다.

body 부분을 보내고자 한다면, Content-Length 헤더를 포함해야 한다는 것을 기억해라. body를 스트링하기 위해서는 Transfer-Encoding: chunked 를 설정해야 한다.

주의 : request가 아직 완료되지 않았다. 이 메서드는 단지 http 요청의 헤더만을 보낸다. 요청을 완료하고 HTTP 응답을 받기 위해서는 request.end()를 호출해야 한다. (이것은 복잡하게 들리지만, 사용자가 request.write()를 통해 서버로 바디를 스트림할 수 있는 기회를 제공한다.)

client.verifyPeer()

정의됐거나 공인된 디폴트 CA 인증서 리스트를 통해 서버 인증서의 타당성을 검증 후 참 또는 거짓을 반환한다.

client.getPeerCertificate()

서버의 인증서와 관련된 JSON 구조체를 반환한다. 이 구조체에는 인증서 제목, 발행처, 유효 기간 등의 정보가 포함되어 있다.

http.ClientRequest

이 객체는 내부적으로 생성되는데, http.client 객체의 request() 메서드의 리턴값이다. 이것은 이미 진행 중인 HTTP 요청을 표현하는데, 여기서 헤더는 이미 전송된 상태이다

응답을 받기 위해서는 request 객체에 대한 ’response’ 이벤트 리스너를 추가해야 한다. 응답 헤더가 수신됐을 때, request 객체는 ’response’ 이벤트를 발생시킨다. ’response’ 이벤트는 하나의 인자를 가지고 실행되는데 이것은 http.ClientResponse 인스턴스이다.

이벤트 동안, response 객체에 리스너(가령 ’data’ 이벤트를 수신하는) 를 추가할 수 있다. 응답 body의 어떤 부분이라도 그것이 수신되기 전에 ‘response’ 이벤트가 호출되기 때문에, body의 첫번째 부분을 얻기 위한 경쟁을 할 필요가 없다는 것을 기억해라. ’response’ 이벤트 동안에 'data’ 이벤트 리스너가 추가되는 한, 전체 body는 수신될 것이다.

// Good
request.on('response', function (response) {
  response.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

// Bad - misses all or part of the body
request.on('response', function (response) {
  setTimeout(function () {
    response.on('data', function (chunk) {
      console.log('BODY: ' + chunk);
    });
  }, 10);
});

이것은 Writable Stream 이다.

이것은 다음과 같은 이벤트를 발생시키는 EventEmitter다.

'response' 이벤트

function (response) { }

이 요청에 대한 응답을 수신했을 때 발생한다.이 이벤트는 오직 한번만 발생한다. 이 메서드의 response 인자는 http.ClientResponse 인스턴스다.

request.write(chunk, encoding='utf8')

하나의 청크 단위 HTTP 바디를 보낸다. 사용자는 이 메서드를 여러 번 호출해서 서버로 HTTP 요청을 스트리밍 할 수 있다. 이 경우 요청을 생성할 때 ['Transfer-Encoding', 'chunked'] 헤더 라인을 이용해야 한다.

chunk 인자는 정수의 배열이나 스트링이 된다.

The encoding argument is optional and only applies when chunk is a string.

encoding 인자는 옵션 값으로 chunk가 스트링일때만 적용된다.

request.end([data], [encoding])

http 요청에 대한 전송을 종료한다. 만약 바디의 특정 부분이 전송되지 않았다면, 나머지들을 스트림으로 전송시킬 것이다. 만약 http 요청이 청크화 됐다면, 이것은 ’0\r\n\r\n’ 종료 문자열을 보낼 것이다.

data 인자가 설정되어 있는 경우, 그것은 request.write(data, encoding)을 호출한 후 request.end() 값을 호출하는 동작과 동일하다.

http.ClientResponse

이 객체는 http.Client를 통해 HTTP 요청을 만들 때 생성된다. 그것은 request 객체의 ’response’ 이벤트로 전달된다.

응답은 Readable Stream 인터페이스를 구현한다.

'data' 이벤트

function (chunk) {}

한 개의 메시지 바디가 수신됐을 때 발생

Example: A chunk of the body is given as the single
argument. The transfer-encoding has been decoded.  The
body chunk a String.  The body encoding is set with
`response.setBodyEncoding()`.

'end' 이벤트

function () {}

메시지당 한번 발생한다. 인자 없음. 더 이상 발생시킬 이벤트가 없는 경우 발생시킨다.

response.statusCode

3자리 HTTP 응답 상태 코드 (예. 404)

response.httpVersion

서버로 연결할 HTTP 버전. ‘1.1’ 또는 ’1.0’이 가능하다. 또한 response.httpVersionMajor는 메이저 버전 넘버를, response.httpVersionMinor은 마이너 버전 렌즈를 나타낸다.

response.headers

응답 헤더 객체

response.setEncoding(encoding=null)

응답 바디의 인코딩을 설정한다. ‘utf8’, ‘ascii’ 또는 ’base64’가 가능. 인자로 전달되는 encoding의 디폴트값이 널이며, 이것은 ‘data’ 이벤트가 Buffer 객체를 발생시킨다는 것을 의미한다.

response.pause()

이벤트 발생을 막고, response를 중단. 다운로드 제어에 유용

response.resume()

중지된 응답을 재개 시킴.

response.client

이 응답과 관련된 http.Client의 레퍼런스.

net.Server

이 클래스는 TCP나 UNIX 서버를 생성하기 위해 사용된다.

다음은 8124 TCP 포트에서 연결을 처리하는 에코 서버 예제이다.:

var net = require('net');
var server = net.createServer(function (stream) {
  stream.setEncoding('utf8');
  stream.on('connect', function () {
    stream.write('hello\r\n');
  });
  stream.on('data', function (data) {
    stream.write(data);
  });
  stream.on('end', function () {
    stream.write('goodbye\r\n');
    stream.end();
  });
});
server.listen(8124, 'localhost');

Unix Domain 소켓‘/tmp/echo.sock’의 연결을 수신하기 위해서는 위 예제의 마지막 라인을 server.listen(‘/tmp/echo.sock’)으로 고치면 된다.

server.listen('/tmp/echo.sock');

이 객체는 다음과 같은 이벤트를 발생시키는 EventEmitter이다:

'connection'

function (stream) {}

새로운 연결이 맺어질 때 발생한다. stream인자는 net.Stream의 인스턴스다.

Event: 'close'

function () {}

서버가 닫힐 때 발생한다.

net.createServer(connectionListener)

TCP 서버를 생성한다. connectionListener 인자는 ‘connection’ 이벤트에 리스너로 자동 설정된다.

server.listen(port, [host], [callback])

지정된 hostport에 대한 연결을 수신 대기함. host 인자가 생략된 경우, 서버는 어느 IPv4 주소(INADDR_ANY)의 호스트의 연결을 승인한다.

이것은 비동기 함수이다. 마지막 인자인 callback은 서버가 바인딩 될 때 호출된다.

server.listen(path, [callback])

path 인자로 주어진 경로에 대한 연결을 수신 대기하는 Unix 소켓 서버를 시작한다.

이것은 비동기 함수이다. 마지막 인자인 callback은 서버가 바인딩 될 때 호출된다.

server.listenFD(fd)

주어진 파일 디스크립터에 대한 연결을 수신 대기하는 서버를 시작한다.

여기서 파일 디스크립터는 bind(2)와 listen(2) 시스템콜이 호출된 상태여야 한다.

server.close()

연결을 수신하는 서버를 멈춘다. 이것은 비동기 함수이기 때문에, 서버가 ‘close’ 이벤트를 발생시킬 때 서버는 닫힌다.

server.maxConnections

이 프로퍼티를 설정하고 서버의 연결 수가 이 값을 초과하면, 연결을 거부한다.

server.connections

서버 상의 동시 접속된 연결 수

net.Stream

이 객체는 TCP나 UNIX 소켓을 추상화한 것이다. net.Stream 인스턴스는 양방향 스트림 인터페이스를 구현한다. 이것은 사용자가 생성해서 클라어인트로 이용하거나(connect()와 같이) 또는 Node에 의해 생성되고 서버의 ‘connection’ 이벤트를 통해 사용자에게 전달될 수 있다.

net.Stream 인스터스는 다음 이벤트를 발생시키는 EventEmitter다.

'connect' 이벤트

function () { }

스트림 연결이 성공적으로 맺어질 때 발생. connect()를 보라.

'secure' 이벤트

function () { }

스트림 연결에서 상대와의 SSL 핸드셰이크가 성공적으로 이뤄질 때 발생.

'data' 이벤트

function (data) { }

데이터를 수신할 때 발생. data 인자는 BufferString이 된다. 데이터의 인코딩 방식은 stream.setEncoding()에서 설정한다. (더 많은 정보를 위해서는 Readable Stream 섹션을 참조해라)

'end' 이벤트

function () { }

스트림의 마지막에서 FIN 패킷을 보낼 때 발생. 이 이벤트가 발생한 후에는 readyState는 'writeOnly'가 된다. 이 이벤트가 발생할 때 단지 stream.end()를 호출하면 될 것이다.

'timeout' 이벤트

function () { }

스트림에서 특정 시간동안 아무 작업이 없으면 발생. 이것은 스트림이 대기 상태에 있다는 것을 알리기 위한 것이다. 사용자는 직접 연결을 닫아야 한다.

stream.setTimeout()을 참조하라.

'drain' 이벤트

function () { }

버퍼가 비었을 때 발생. 업로드 제어를 위해 이용할 수 있다.

'error' 이벤트

function (exception) { }

에러가 발생할 때 발생. 이 이벤트 직후 바로 ‘close’ 이벤트가 발생한다.

'close' 이벤트

function (had_error) { }

스트림이 완전히 닫히면 발생한다. had_error 인자는 전송 에러로 스트림이 닫혔는지를 알려주는 불린 값이다.

net.createConnection(port, host='127.0.0.1')

새로운 stream 객체를 생성하고, 특정 porthost에 해당하는 스트림을 연다. 만약 두번째 인자가 생략될 경우, localhost로 가정한다.

스트림이 생성됐을 때, ‘connect’ 이벤트가 발생할 것이다.

stream.connect(port, host='127.0.0.1')

특정 porthost에 해당하는 스트림을 연다. createConnection()도 스트림을 열 수 있기 때문에 보통 이 메서드는 필요없다. 스트림이 닫히고 다른 서버에 연결하기 위해 객체를 재사용하고 싶을 때만 이 메서드를 사용해라.

이것은 비동기 함수다. ‘connect’ 이벤트가 발생되면 스트림이 생성된다. 만약 연결 중에 문제가 있을 경우, ‘connect’ 이벤트는 발생하지 않고 예외와 함께 ‘error’ 이벤트가 발생한다.

stream.remoteAddress

접속할 원격지 주소를 나타내는 문자열. 예를 들면, ‘74.125.127.100’ 또는 ‘2001:4860:a005::68’

이 멤버는 서버측 연결에서만 존재한다.

stream.readyState

'closed', 'open', 'opening', 'readOnly', 'writeOnly' 상태 중 하나.

stream.setEncoding(encoding=null)

수신 데이터의 인코딩 설정('ascii', 'utf8', 또는 'base64' 가능)

stream.setSecure([credentials])

스트림에서 HTTPS 지원을 가능하게 한다. credentials 인자는 crypto 모듈을 통해 제공되며 개인키와 스트림에 대한 인증서 그리고 옵션으로 상대편 인증 시에 사용될 CA 인증서를 나타낸다.

credentials이 하나 또는 여러개의 CA 인증서를 가지고 있다면, 스트림은 상대측에 SSL 연결 핸드세이킹 과정에서 클라이언트가 자신의 인증서를 보내게 끔 요청한다. 여기서 검증이나 컨텐트 내용으로의 접근은 서버의 request.connection의 verifyPeer()과 getPeerCertificate() 함수를 통해 처리할 수 있다.

stream.verifyPeer()

정의됐거나 공인된 디폴트 CA 인증서 리스트를 통해 서버 인증서의 타당성을 검증 후 참 또는 거짓을 반환한다.

stream.getPeerCertificate()

상대편의 인증서와 관련된 JSON 구조체를 반환한다. 이 구조체에는 인증서 제목, 발행처, 유효 기간 등의 정보가 포함되어 있다.

stream.write(data, encoding='ascii')

스트림을 통해 데이터를 전송한다. 두번째 인자 encoding은 문자열의 경우 인코딩 방식을 기술한다. (디폴트는 ASCII 방식인데, 이유는 UTF8 인코딩이 상대적으로 느리기 때문이다.)

전체 데이터가 커널 버퍼로 성공적으로 보내진다면 true 반환한다. 만약 데이터의 일부가 사용자 메모리 상에 남아있다면 false를 반환한다. 이후 사용자 버퍼가 모두 비워진다면 ‘drain’ 이벤트가 발생한다.

stream.end([data], [encoding])

스트림을 일부 종료. 이것은 FIN 패킷을 보낸다. 이때 서버가 일부 데이터를 보낼 수 있다. 이 함수가 호출된 후 readyState‘readOnly’가 된다.

data인자에 값이 넘어온다면, 그것은 stream.write(data, encoding) 호출 후에 바로 stream.end()를 호출하는 것과 같은 동작이다.

stream.destroy()

스트림에 더 이상 I/O 작업이 발생하지 않을 것을 보장한다. 에러가 발생(파싱 에러 등)한 경우 필요

stream.pause()

데이터 수신을 중단. 즉, ‘data’ 이벤트가 발생하지 않는다. 업로드 제어에 유용.

stream.resume()

pause() 함수 호출이 된후, 수신을 재개함.

stream.setTimeout(timeout)

스트림에서 timeout 동안(ms 단위) 동작이 없을 경우, 해당 스트림을 타임아웃 시킨다. 디폴트로 net.Stream은 타임아웃되지 않는다.

대기 타임아웃이 발생할 때 스트림은 ‘timeout’ 이벤트를 받고 연결이 진행되지 않을 것이다. 사용자는 직접 end()destroy()를 통해 스트림을 중단시키면 된다.

timeout 인자의 값이 0이면 기존 대기 타임아웃은 비활성화된다.

stream.setNoDelay(noDelay=true)

Nagle 알고리즘을 비활성화한다. 디폴트로 TCP 연결은 Nagle 알고리즘을 사용하므로 데이터를 보내기 전에 이를 버퍼에 저장한다. noDelay 인자를 설정하면 stream.write()가 호출될 때 마다 곧바로 데이터를 전송한다.

stream.setKeepAlive(enable=false, [initialDelay])

keep-alive 기능의 활성화/비활성화 설정. 그리고 옵션으로 스트림 대기 상태에서 최초 keppalive probe를 보내기 전에 initialDelay 값을 설정한다. 마지막 수신 패킷과 최초 keepalive prove 패킷 사이의 딜레이를 주기 위해 initialDelay(단위 밀리초) 인자 값을 설정한다. intialDelay 값이 0이면 디폴트 세팅(또는 이전 세팅)값을 변경없이 그대로 이용한다.

Crypto

Crypto 모듈에 접근하기 위해서 require(‘crypto’) 문을 이용한다.

crypto 모듈을 이용하기 위해서는 플랫폼 상에 OpenSSL이 설치되어 있어야 한다. 그것은 HTTPS 네트워크이나 HTTP 연결 등에서 사용되는 보안 인증서를 캡슐화 하는 기능을 제공한다.

또한 이 모듈은 OpenSSL의 hash, hmac, cipher, decipher, sign, verfity 메서드들의 랩퍼 함수들을 제공한다.

crypto.createCredentials(details)

인증서 객체를 생성하는데, 해당하는 추가적인 키 정보는 다음과 같다:

key : PEM 인코딩된 개인키 값을 저장한 문자열

cert : PEM 인코딩된 인증서를 저장한 문자열

ca : PEM 인코딩된 신뢰할 만한 CA 인증서 문자열 또는 문자열 리스트

만약 아무 ‘ca’ 키 값을 넘겨주지 않는다면, node.js는 http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt 에서 제공하는 공인된 CA 리스트를 디폴트로 사용할 것이다.

crypto.createHash(algorithm)

해시 객체를 생성 후 반환한다. 인자로 전달된 algorithm에 의해 암호화된 해시는 해시 다이제스트(digests)를 생성하는 데 사용할 수 있다.

algorithm 인자에는 플랫폼에 설치된 OpenSSL 버전에 따라 사용 가능한 알고리즘이 정해지는데, 예로는 sha1, md5, sha256, sha512 등이 있다. 최근 릴리즈에서는 openssl list-message-digest-algorithms 명령은 사용 가능한 다이제스트 알고리즘을 보여준다.

hash.update(data)

인자로 주어진 data에 대한 해시 내용을 업데이트 한다. 이것은 데이터가 스트림되는 경우, 새 데이터와 함께 여러번 호출될 수 있다.

hash.digest(encoding='binary')

해시된 모든 데이터의 다이제스트를 계산한다. encoding은 hex, binary, base64가 될 수 있다.

crypto.createHmac(algorithm, key)

주어진 algorithm과 key를 바탕으로 한 암호화된 hmac 객체를 생성하고 리턴한다.

algorithm 인자에는 플랫폼에 설치된 OpenSSL에 따라 이용 가능한 알고리즘이 결정된다. - 위의 createHash 부분을 봐라. key인자는 사용될 hmac 키이다.

hmac.update(data)

전달된 data 인자 값을 가지고 hmac 컨텐트를 업데이트 한다. 이것은 데이터가 스트림되는 경우, 새 데이터와 함께 여러번 호출될 수 있다.

hmac.digest(encoding='binary')

hmac에 전달된 모든 데이터의 다이제스트를 계산한다. encoding 인자는 ’hex’, ‘binary’, ‘base64’가 될 수 있다.

crypto.createCipher(algorithm, key)

인자로 전달된 algorithm과 key를 기반으로 cipher 객체를 생성 및 반환한다.

algorithm 은 설치된 OpenSSL에 달려있는데, aes192 같은 것들이 이에 해당한다. OpenSSL의 최신 릴리즈에는 openssl list-cipher-algorithms 명령을 통해 사용 가능한 cipher 알고리즘을 확인할 수 있다.

cipher.update(data, input_encoding='binary', output_encoding='binary')

input_encoding 인자(‘utf8’, ‘ascii’ 또는 ’binary’ 값이 될 수 있음)가 가리키는 형태로 인코딩된 data를 암호화한다. output_encoding 인자는 암호화된 데이터의 출력 포맷을 결정하는데 ’binary’, ‘base64’ 또는 ’hex’ 값을 지정할 수 있다.

반환값은 암호화된 데이터이며, data가 스트림 되는 경우 이 함수는 여러분 호출 될 수 있다.

cipher.final(output_encoding='binary')

암호화된 데이터의 나머지를 반환한다. output_encoding은 출력 포맷을 가리키면 ’binary’, ‘ascii’ 또는 ’utf8’ 중 하나이다.

crypto.createDecipher(algorithm, key)

algorithm과 key인자를 통해 복호화 객체를 생성하고 반환한다. 이것은 위의 cipher 객체와 대응된다.

decipher.update(data, input_encoding='binary', output_encoding='binary')

‘binary’, ‘base64’ 또는 ’hex’로 인코딩된 암호화된 data를 복호화한다. ouput_decoding 은 반환할 복호화된 데이터의 출력 포맷을 설정하는 데, ‘binary’나 ’ascii’ 값이 될 수 있다.

decipher.final(output_encoding='binary')

복호화된 나머지 데이터를 반환한다. output_encoding 인자 값은 ’binary’, ‘ascii’, ‘utf8’ 중 하나가 될 수 있다.

crypto.createSign(algorithm)

인자로 전달된 algorithm에 기반한 서명 객체를 생성 및 반환한다. 최근 OpenSSL 릴리즈에는 openssl list-public-key-algorithms 명령을 통해 사용 가능한 서명 알고리즘(가령, RSA-SHA256)을 알 수 있다.

signer.update(data)

data를 통해 singer 객체를 업데이트 한다. data가 스트림 되는 경우 이 함수는 여러번 호출될 수 있다.

signer.sign(private_key, output_format='binary')

signer를 통해 업데이트된 전체 데이터의 시그너처를 계산한다. private_key는 서명에 사용되는 PEM 인코딩된 개인키를 포함하는 문자열이다.

‘binary’, ‘hex’ 또는 ’base64’ 등의 output_format 형태로 시그너처를 리턴한다.

crypto.createVerify(algorithm)

인자로 주어진 algorithm에 해당하는 verification 객체를 생성 및 반환한다. 이것은 위의 signing 객체와 상관 관계이다.

verifier.update(data)

data를 통해 verifyer 객체를 업데이트 한다. data가 스트림 되는 경우 이 함수는 여러번 호출될 수 있다.

verifier.verify(public_key, signature, signature_format='binary')

PEM 인코딩된 공개키를 포함한 문자열을 저장하고 있는 public_key 인자를 이용해서 서명된 데이터를 검증한다. 그리고 signature 인자는 이미 계산된 특정 data의 시그너처이며 signature_format의 형태를 가지는데 그 값은 ’binary’, ‘hex’ 또는 ’base64’가 가능하다.

data에 해당하는 시그너처와 공개키의 적합성 여부에 따라 참 또는 거짓이 반환된다.

DNS

Module를 사용하기 위해서는 require(‘dns')를 사용한다.

이번 예제는 ‘www.google.com’을 변화하고 변환된 IP address를 다시 변환하는 것이다.

dns.lookup(domain, family=null, callback)

도메인(예를 들어 ‘google.com’)을 첫번째로 찾아진 A(IPv4) 혹은 AAAA(IPv6) 로 변환한다.

var dns = require('dns');
 
dns.resolve4('www.google.com', function (err, addresses) {
  if (err) throw err;
 
  console.log('addresses: ' + JSON.stringify(addresses));
 
  addresses.forEach(function (a) {
	dns.reverse(a, function (err, domains) {
  	if (err) {
    	console.log('reverse for ' + a + ' failed: ' +
      	err.message);
  	} else {
    	console.log('reverse for ' + a + ': ' +
      	JSON.stringify(domains));
  	}
	});
  });
});
 

Callback의 인자는 err, address, family이다.

address는 IPv4 혹은 IPv6 주소의 String 형태이다. family는 integer 4 혹은 6 과 family의 주소(필요하지 않게 처음 조회로 전달되는 값)를 나타낸다.

dns.resolve(domain, rrtype='A', callback)

도메인 (예를 들어 ‘google.com’)을 rrtype에 의해 지정된 레코드 형식의 배열로 변환한다.

가능한 rrtype은 A (IPv4 주소), AAAA (IPv6 주소), MX (메일 교환 기록), TXT (text 기록), SRV (SRV 기록), PTR (역방향 IP 조회) 이다.

Callback의 인자는 err, addresses를 갖기도 한다.

addresses는 레코드 타입에 의해서 결정되고 해당 방법은 아래에 설명되어있다.

오류에서 err은 Error 객체의 인스턴스이고 err.errono는 아래에 나열된 err 코드중에 하나이며 err.message는 영어로 오류를 설명한 문자열이다.

dns.resolve4(domain, callback)

IPv4 쿼리 (A 기록)만을 위해서는 dns.resolve()와 똑같다.

주소는 IPv4 주소의 배열이다.

(예 ['74.125.79.104', '74.125.79.105', '74.125.79.106']).

dns.resolve6(domain, callback)

IPv6 질의(AAA 질의)를 제외하고 dns.resolve4() 와 똑같다.

dns.resolveMx(domain, callback)

메일 교환 질의를 위해서 (MX 기록) dns.resolve() 와 똑같다.

주소는 각각이 우선순위와 교환 속성을 가지고 있는 MX 기록의 배열이다.

(예를 들어 [{'priority': 10, 'exchange': 'mx.example.com'},...]).

dns.resolveTxt(domain, callback)

text 질의를 위해서 dns.reslove()와 똑같다.

주소는 도메인을 가능하게 하는 text 기록의 배열이다.

(예를 들어 ['v=spf1 ip4:0.0.0.0 ~all']).

dgram

Datagram 소켓을 사용하기 위해서는 require('dgram')를 사용한다.

Datagrams 일반적으로 IP/UDP 메시지를 통해서 구현된다. 그렇지만 Unix domain sockets 위에서 동작하기도 한다.

Event: 'message'

function (msg, rinfo) { }

새로운 datagramsocket이 가능할때 나오는 이벤트 이다.

msg는 버퍼이고 rinfo라는 객체로서 보내는 쪽의 주소 정보와 datagram의 바이트의 숫자를 가지고 있다.

Event: 'listening'

function () { }

소켓이 datagram을 받기 시작할 때 나오는 이벤트이다.

이것은 UDP소켓이 생성될때 바로 나타난다.

UNIX 도메인에서 소켓은 bind() 호출전에 준비 되지 않는다.

Event: 'close'

function () { }

소켓이 close()와 함께 닫힐 때 나오는 이벤트이다.

새로운 메시지 이벤트는 나오지 않는다.

dgram.createSocket(type, [callback])

특별한 타입의 datagram 소켓을 생성한다. 가능한 타입은udp4, udp6, andunix_dgram 다음과 같다.

Message 이벤트를 위한 추가적인 콜백은 리스너 형태이다.

dgram.send(buf, offset, length, path, [callback])

유닉스 도메인 소켓 데이터 그램은 목적지 주소가 파일 시스템의 경로명과 같다.

추가적인 콜백은 sendto 호출이 완료 된 이후에 사용이 가능하다.

콜백이 호출될 때까지 사용한 Buf는 다시 사용하지 않는 것이 좋다.

var dgram = require('dgram');
var message = new Buffer("A message to log.");
var client = dgram.createSocket("unix_dgram");
client.send(message, 0, message.length, "/var/run/syslog",
  function (err, bytes) {
    if (err) {
  	throw err;
    }
    console.log("Wrote " + bytes + " bytes to socket.");
});

dgram.send(buf, offset, length, port, address, [callback])

UDP소켓을 위해서 목적지의 대상포트와 IP 주소는 지정되어 있어야한다.

문자열은 주소 매개 변수에 대해 제공할 수 있다

이것은 DNS가 해결할 일이다. 추가적인 콜백은 DNS 오류를 감지 지정할 수 있으며 사용된 buf는 다시 사용이 가능하다

로컬 호스트에서 임의의 포트로 UDP 패킷을 전송하는 예제:

var dgram = require('dgram');
var message = new Buffer("Some bytes");
var client = dgram.createSocket("udp4");
client.send(message, 0, message.length, 41234, "localhost");
client.close();

dgram.bind(path)

UNIX

도메인에서 데이터그램 소켓에 대한 경로로 지정된 소켓으로 부터 들어오는 데이터 그램을 리쓴하기 시작한다.

그렇지만 클라이언트의 경우는 바인딩 하지 않고 보낼 수 있다

유닉스 도메인에서 받은 패킷을 모두 돌려주는 데이터그램 서버에 대한 예제:

var dgram = require("dgram");
var serverPath = "/tmp/dgram_server_sock";
var server = dgram.createSocket("unix_dgram");
 
server.on("message", function (msg, rinfo) {
  console.log("got: " + msg + " from " + rinfo.address);
  server.send(msg, 0, msg.length, rinfo.address);
});
 
server.on("listening", function () {
  console.log("server listening " + server.address().address);
})
 
server.bind(serverPath);

유닉스 도메인에서 서버에 데이터그램을 보내는 예제:

var dgram = require("dgram");
var serverPath = "/tmp/dgram_server_sock";
var clientPath = "/tmp/dgram_client_sock";
 
var message = new Buffer("A message at " + (new Date()));
 
var client = dgram.createSocket("unix_dgram");
 
client.on("message", function (msg, rinfo) {
  console.log("got: " + msg + " from " + rinfo.address);
});
 
client.on("listening", function () {
  console.log("client listening " + client.address().address);
  client.send(message, 0, message.length, serverPath);
});
 
client.bind(clientPath);

dgram.bind(port, [address])

UDP소켓에서 port와 추가적인 address에 대해서 데이터그램을 리스닝하게 만든다.

만약에 address가 정해지지 않는 다면 OS는 모든 주소에 대해서 리슨을 하게 된다.

UDP서버가 41234 포트를 리스닝 하고 있는 예제:

var dgram = require("dgram");
 
var server = dgram.createSocket("udp4");
var messageToSend = new Buffer("A message to send");
 
server.on("message", function (msg, rinfo) {
  console.log("server got: " + msg + " from " +
    rinfo.address + ":" + rinfo.port);
});
 
server.on("listening", function () {
  var address = server.address();
  console.log("server listening " +
  	address.address + ":" + address.port);
});
 
server.bind(41234);
// server listening 0.0.0.0:41234

dgram.close()

리스닝하는 소켓을 닫는다.

UDP소켓 bind()를 호출하지 않아도 자동으로 메시지를 리슨하고 있다.

dgram.address()

주소 정보를 가지고있는 객체를 반환한다.

UDP소켓을 위해서 이 객체는 주소와 포트 정보를 가지고있다.

유닉스 도메인 소켓을 위해서는 단지 주소정보만을 가지고있다.

dgram.setBroadcast(flag)

SO_BROADCAST 소켓 옵션을 사용해서 세팅하거나 풀어준다.

이 옵션이 셋팅되면 UDP 패킷은 브로드케스트 주소로 보내진다.

dgram.setTTL(ttl)

IP_TTL 소켓 옵션을 설정한다. TTL은 Time To Live를 의미하지만 이 함수는 패킷이 넘어갈 수 있는 홉의 숫자를 의미한다.

각 라우터나 게이트웨이는 TTL값을 줄이면서 다음으로 패킷을 넘긴다.

만약에 TTL이 라우터에 의해서 0이 되면 이것은 전달되지 않을 것이다.

setTTL의 아규먼트는 홉의 숫자이며 이것은 1에서 255까지이다.

그리고 대부분 시스템의 기본값은 64이다.

Assert

이 모듈은 unit test에 사용된다. 사용하기 위해서는 require('assert')이 필요하다.

assert.fail(actual, expected, message, operator)

actual값과 expected 값이 operator 연산으로 같은지 테스트 한다.

assert.ok(value, [message])

value값이 true 인지 테스트한다.

assert.equal(actual, expected, [message])

assert.fail에서 operator 를 == 으로 한것과 같은 결과이다.

assert.notEqual(actual, expected, [message])

assert.fail에서 operator 를 != 으로 한것과 같은 결과이다.

assert.deepEqual(actual, expected, [message])

deep Equality를 테스트한다.

assert.notDeepEqual(actual, expected, [message])

deep Equality가 아닌것을 테스트한다.

assert.strictEqual(actual, expected, [message])

엄격하게 동일함을 테스트한다.

assert.notStrictEqual(actual, expected, [message])

다름을 엄격하게 테스트한다.

assert.throws(block, [error], [message])

block이 에러를 발생하는 것을 기대한다.

assert.doesNotThrow(block, [error], [message])

block이 에러를 발생하지 않는 것을 기대한다.

Path

이 모듈은 file path와 관련된 기능들을 포함하고 있다. 이를 사용하기 위해서는 require('path')이 필요하다.

path.join([path1], [path2], [...])

모든 인자들을 합치고 결과로 path를 돌려준다.

예제:

node> require('path').join(
...   '/foo', 'bar', 'baz/asdf', 'quux', '..')
'/foo/bar/baz/asdf'

path.normalizeArray(arr)

배열에 있는 path부분을 정형화 시킨다.

예제:

path.normalizeArray(['',
  'foo', 'bar', 'baz', 'asdf', 'quux', '..'])
// returns
[ '', 'foo', 'bar', 'baz', 'asdf' ]

path.normalize(p)

문자열로 된 path를 정형화 시킨다.

예제:

path.normalize('/foo/bar/baz/asdf/quux/..')
// returns
'/foo/bar/baz/asdf'

path.dirname(p)

path에서 디렉토리 이름을 돌려준다. Unix에서 dirname과 비슷한 명령어이다.

예제:

path.dirname('/foo/bar/baz/asdf/quux')
// returns
'/foo/bar/baz/asdf'

path.basename(p, [ext])

path의 마지막 부분을 돌려준다. Unix의 basename과 비슷한 명령어이다.

예제:

path.basename('/foo/bar/baz/asdf/quux.html')
// returns
'quux.html'
 
path.basename('/foo/bar/baz/asdf/quux.html', '.html')
// returns
'quux'

path.extname(p)

path의 확장자 부분을 돌려준다. 마지막 ‘.’뒤의 모든 부분을 돌려준다. 만약에 path에 ‘.’이 없다면 빈 문자열을 돌려준다.

예제:

path.extname('index.html')
// returns
'.html'
 
path.extname('index')
// returns
''

path.exists(p, [callback])

path가 존재하는지 아닌지를 테스트 해준다. 콜백 인자를 불러서 true나 false를 불러준다.

예제:

path.exists('/etc/passwd', function (exists) {
  sys.debug(exists ? "it's there" : "no passwd!");
});

URL

파싱된 URL 객체는 부분이나 모든 다음의 필드를 포함하고 있다. URL 문자열에 있지 않은 부분은 파싱된 객체에 포함되지 않는다. 예를 들어서 다음과 같은 URL을 보면

'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'

href

원본에서 파싱된 모든 URL예:

'http://user:pass@host.com:8080/p/a/t/h?query=string#hash'

protocol

요청된 프로토콜. 예: 'http:'

host

포트와 인증 정보가 포함된 전체 host 부분 예:

'user:pass@host.com:8080'

auth

인증정보 예:

'user:pass'

hostname

hostname에 대한 부분. 예:

'host.com'

port

포트 부분. 예:

'8080'

pathname

URL에서 path관련 부분이다. 이것은 host 뒷부분과 쿼리 앞부분을 의미한다. ‘/’를 포함하고 있다. 예:

'/p/a/t/h'

search

URL에서 쿼리 문자열을 의미하고 질의문 까지 포함한다. 예:

'?query=string'

query

쿼리문의 파싱된 객체나 쿼리문에서 파라미터부분 예:

'query=string' or {'query':'string'}

hash

파운드 사인들 포함한 부분. 예:

'#hash'

다음은 URL모듈이 제공하는 메소드들이다.:

url.parse(urlStr, parseQueryString=false)

URL 문자열을 가지고 와서 객체를 반환한다. 두번째 인자로 true를 보내면 querystring 모듈을 사용해서 파싱을 한다.

url.format(urlObj)

파싱된 URL을 가져와서 포맷화된 URL문자열을 돌려준다.

url.resolve(from, to)

base URL, href URL를 브라우저 형태로 분해한다.

Query String

이 모듈은 query문자열의 기능을 제공한다. 아래와 같은 메소드들을 제공한다.:

querystring.stringify(obj, sep='&', eq='=', munge=true)

객체를 쿼리 문자열로 정렬한다. 선택적으로 기본 분리자와 할당자를 바꿀 수 있다. 예:

querystring.stringify({foo: 'bar'})
// returns
'foo=bar'
 
querystring.stringify({foo: 'bar', baz: 'bob'}, ';', ':')
// returns
'foo:bar;baz:bob'

기본으로 이 함수는 PHP/Rails 형태를 배열과 객체가 사용할 수 있도록 변경했다. 예:

querystring.stringify({foo: ['bar', 'baz', 'boz']})
// returns
'foo%5B%5D=bar&foo%5B%5D=baz&foo%5B%5D=boz'
 
querystring.stringify({foo: {bar: 'baz'}})
// returns
'foo%5Bbar%5D=baz'

만약에 배열 변경(예 자바 서블릿을 위해서 파라메터를 만드는경우)하고 싶다면, munge 인자를 false로 세팅하면 된다. 예:

querystring.stringify({foo: ['bar', 'baz', 'boz']}, '&', '=', false)
// returns
'foo=bar&foo=baz&foo=boz'

주의 mung 이 false인 경우, 파라메터 값은 여전히 munged하다.

querystring.parse(str, sep='&', eq='=')

쿼리 스트링을 deserialize한다. 선택적으로 분리자와 변경자를 바꿀 수 있다.

querystring.parse('a=b&b=c')
// returns
{ 'a': 'b'
, 'b': 'c'
}

이 함수는 munged한것과 unmunged한 쿼리 문자여을 모두 파싱할 수 잇다. (자세한 사항은 stringify 참조)

querystring.escape

escape함수는 querystring.stringify에서 사용되고 필요하다면 오버라이드하면 된다.

querystring.unescape

unescape 함수는 querysting.parse에서 사용되고 필요하다면 오버라이드하면 된다.

REPL

Read-Eval-Print-Loop(REPL)은 독립 실행 프로그램과 다른 프로그램에서 모두 쉽게 사용할 수 있다.

REPL은 자바스립트를 실행하고 결과를 볼 수 있는 방법을 제공한다.

또 디버깅, 테스팅 혹은 간단한 작업을 할 수 있다.

Node를 아무 인자 없이 실행하면서 REPL이 되는 것이다.

이것은 간단한 emacs 라인 에디팅이다.

mjr:~$ node
Type '.help' for options.
node> a = [ 1, 2, 3];
[ 1, 2, 3 ]
node> a.forEach(function (v) {
...   console.log(v);
...   });
1
2
3

고급 라인 편집기를 위해서 Node를 환경변수 NODE_NO_READLINE = 1 과 함께 시작한다.

이것은 rlwrap과 함께 사용할 수 있는 표준 터미널 설정이다. 예를 들어, bashrc파일을 추가할 수 있다.:

alias node="env NODE_NO_READLINE=1 rlwrap node"
repl.start(prompt='node> ', stream=process.openStdin())

REPL을 promp로 시작을 한다. promp는 변경이 가능하고 기본적으로 node> 이다. stream도 선택가능 하고 기본값은 process.openStdin()을 통해서 확인이 가능하다.

여러개의 REPL을 한개의 Node 인스턴스로 실행 가능하다. 각각은 같은 global 객체를 공유하지만 I/O는 그렇지 않다.

Unix 소켓과 TCP 소켓에 관련해서 REPL을 stdin으로 실행하는 예제가 있다.:

var net = require("net"),
    repl = require("repl");
 
connections = 0;
 
repl.start("node via stdin> ");
 
net.createServer(function (socket) {
  connections += 1;
  repl.start("node via Unix socket> ", socket);
}).listen("/tmp/node-repl-sock");
 
net.createServer(function (socket) {
  connections += 1;
  repl.start("node via TCP socket> ", socket);
}).listen(5001);

command line에서 이 프로그램을 실행하면 REPL이 실행된다. 다른 REPL 클라이언트는 Unix 소켓이나 TCP 소켓 telnet을 이용해서 접속 가능하고 socat 또한 연결이 가능하다.

Unix 소켓 서버를 REPL로 실행함으로써 재시작없이 길게 실행가능한 Node 프로그램을 만들 수 있다.

REPL Features

REPL안에서는 Control+D 를 사용해서 종료가 가능하다. 멀티라인으로 입력도 가능하다. 특수 기호인 _(underscore) 는 마지막 표현을 포함하고 있다.

node> [ "a", "b", "c" ]
[ 'a', 'b', 'c' ]
node> _.length
3
node> _ += 1
4

REPL은 global 영역에 있는 모든 변수에 접근이 가능하다. REPL에 변수를 노출시키고 싶다면 각 REPLServer에 context 객체에 할당하면 된다. 예를 들어서:

// repl_test.js
var repl = require("repl"),
    msg = "message";
 
repl.start().context.m = msg;
REPL에서 context 객에 있는 것은 마치 자신의 것처럼 나타난다 :
mjr:~$ node repl_test.js
node> m
'message'

몇가지 특수한 REPL 명령어가 있다.:

.break - 여러중의 명령을 입력하는 동안 가끔 까먹거나 컴파일 하는것에 관심이 없다면 .break 가 끝내는 것을 도와준다.

.clear - context 객체를 초기화 시킨다.

.exit - I/O 스트림을 닫고 REPL을 종료 시킨다.

.help - 특수 명령어들을 보여준다.

Modules

Node는 CommonJS 모듈 시스템을 사용한다.

Node는 간단한 모듈 로딩 시스템을 가지고있다.

Node에서 파일과 모듈은 1 대 1 매칭이 된다. 예를 들어서 foo.js 가 같은 디렉토리에 있는 모듈 circle.js 을 로드 한다고 하면

foo.js 내용은 다음과 같다. :

var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
       	+ circle.area(4));

circle.js 내용은 다음과 같다.:

var PI = 3.14;
 
exports.area = function (r) {
  return PI * r * r;
};
 
exports.circumference = function (r) {
  return 2 * PI * r;
};
 

모듈 circle.js 은 함수 area() 과 circumference()을 외부에 노출시킨다.

객체를 노출시키기 위해서 exports 라는 객체를 사용한다. 모듈의 변수들은 모두 private 이다. 예를 들어서 변수 PI 는 circle.js. 에서 pirvate 이다.

모듈에서 접두사 './' 이 붙은require() 는 상대주소를 이야기한다. 말하자면 circle.js 은 같은 디렉토리에 접두사 './', 가 없는 경우 require('assert'), 모듈은 require.paths 배열을 검색한다.

내 시스템에서 require.paths 은 다음과 같다. [ '/home/ryan/.node_libraries' ] 말하자면 require('assert') 을 호출하면 Node는 다음을 찾는다.

1: /home/ryan/.node_libraries/assert.js

2: /home/ryan/.node_libraries/assert.node

3: /home/ryan/.node_libraries/assert/index.js

4: /home/ryan/.node_libraries/assert/index.node

파일 확장자가 '.node' 인 경우 이것은 Addon 모듈이다. 아래에 있는 Addons에 대한 내용을 보도록 하자. 'index.js' 은 한 디렉토리로 모듈을 패키지할 수 있다.

require.paths 는 단순히NODE_PATH 환경변수(colon으로 분리된 경로 리스트로 구성) 로 시작되고 새로운 경로는 실시간으로 수정이 가능하다.

Addons

Addons 은 동적으로 링크되는 shared object이다. C, C++ 라이브러리와 연동이 가능하다.

API는 연관된 몇몇 라이브러리에 대한 지식 때문에 다소 복잡하다.

V8 JavaScript 는 C++ 라이브러리를 사용해서 JavaScript와 연동한다. 객체 생성, 함수 호툴 등과 같은 작업들이 가능하다. 도큐먼트는 대부분 v8.h 헤더 파일에 나와있고 파일은 deps/v8/include/v8.h 에서 볼 수 있다.

libev 는 C event loop 라이브러리이다. 파일을 읽기 위해서는 파일 디스크립터를 가져오는 동안 타이머 혹은 시그널을 받는 방식으로 기다리게 되는데 이 경우에 libev를 사용해야한다. 이것은 만약 당신이 I/O를 사용하려고 한다면 libev가 사용된다는 것을 의미한다. Node는 EV_DEFAULT 이벤트 루프를 사용한다. 이에 관련된 문서는 다음 사이트에서 확인할 수 있다. http:/cvs.schmorp.de/libev/ev.html[here].

libeio는 C 쓰레드 풀 라이브러리이다. 블록킹 POSIX 시스템을을 비동기적으로 만들어준다. 대부분의 wrapper는 만들어져 있고, 더 자세한 것은 다음 헤더를 참조하면 된다. deps/libeio/eio.h.

Node는 디펜던시가 있는 것들을 모두 실행파일에 컴파일에서 포함한다. 모듈을 커파일할때 다른 라이브러리와 링킹하는 것에 고민을 가질 필요는 없다.

아래의 예제를 통해서 간단한 Addon 예제를 만들어 보자.

exports.hello = 'world';

시작하기 위해서 hello.cc 를 만들도록 하겠다.

#include 
 
using namespace v8;
 
extern "C" void
init (Handle<Object> target)
{
  HandleScope scope;
  target->Set(String::New("hello"), String::New("World"));
}

이 소스 코드는hello.node 로 binary Addon 형태로 들어가야 한다. 그렇게 하기 위해서 파이썬으로 만들어진 wscript 를 사용해서 파일을 만들어야 한다.

srcdir = '.'
blddir = 'build'
VERSION = '0.0.1'
 
def set_options(opt):
  opt.tool_options('compiler_cxx')
 
def configure(conf):
  conf.check_tool('compiler_cxx')
  conf.check_tool('node_addon')
 
def build(bld):
  obj = bld.new_task_gen('cxx', 'shlib', 'node_addon')
  obj.target = 'hello'
  obj.source = 'hello.cc'

node-waf configure build를 사용해서 파일을 만든다.

build/default/hello.node 가 우리가 만든 Addon이다.

node-waf sms http://code.google.com/p/waf/[WAF] 이곳에 있으며 , 이것은 Python을 바탕으로 만들어진 빌드 시스템이다.

모든 Node Addon은 아래와 같은 init 을 가지고 있어야한다.

extern 'C' void init (Handle target)

지금 이에 대한 자세한 문서는 http://github.com/ry/node_postgres 이곳을 통해서 확인하기 바란다.

Appendix - Third Party Modules

Node에는 많은 서드파티 모듈들이 있다. 201년 8월 기준으로 모듈의 마스터 저장소는 http://github.com/ry/node/wiki/modules[위키 페이지] 이다.

이 Appendix 는 새로운 개발자를 위해 빠르게 적용할 수 있는 모듈들을 나열한 작은 가이드이다. 완벽한 리스트를 만드는 것은 의도하지 않았기 때문에 보다 좋은 모듈은 다른 장소에서 찾아보는 것이 좋을 것이다.

Module Installer: npm

HTTP Middleware: Connect

Web Framework: Express

Web Sockets: Socket.IO

HTML Parsing: HTML5

mDNS/Zeroconf/Bonjour

RabbitMQ, AMQP

mysql

Serialization: msgpack

Scraping: Apricot

Debugger: ndb is a CLI debugger inspector is a web based tool.

pcap binding

ncurses

Testing/TDD/BDD: vows, expresso, mjsunit.runner