[번역] Creating a HTTP Server in Node.js, #Haroopress


 sitepoint.com의 Node.js 관련 Article 번역

  1. [번역] An Introduction to Node.js

 원문 sitepoint.com의 Creating a HTTP Server in Node.js(http://sitepoint.com/creating-a-http-server-in-node-js/)

 오역 주의 오역을 발견하시면 꼭 알려주세요~ :-)

Creating a HTTP Server in Node.js

최근에 작성한 글에서 가장 기본적인 Node.js 프로그램을 소개했었다. 물론 Hello World 프로그램도 괜찮지만, 사실 Node.js는 높은 성능의 확장 가능한 서버 애플리케이션을 작성하기 위한 것으로 더 많이 알려졌다. 이 글에서는 Node.js로 만든 간단한 HTTP 서버를 소개한다.

Running the Server

우선 “web_server.js”라는 파일을 만들고 아래의 코드를 작성 후 저장하자.

var http = require("http");
var server = http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/html"});
  response.write("<!DOCTYPE \"html\">");
  response.write("<html>");
  response.write("<head>");
  response.write("<title>Hello World Page</title>");
  response.write("</head>");
  response.write("<body>");
  response.write("Hello World!");
  response.write("</body>");
  response.write("</html>");
  response.end();
});
server.listen(80);
console.log("Server is listening");

이 서버를 구동시키려면 아래의 명령어를 실행해라. 정상적으로 실행이 된다면 “Server is listening”이라는 메시지를 보게될 것이다. 예제의 서버가 HTTP의 표준 포트인 80번 포트에 바인딩하고 있다는 것에 주목하자. 이 포트가 시스템에서 이미 사용중이거나 제한되어 있다면 에러가 발생할 것이다.

$ node web_server.js

다음은 웹 브라우저를 사용해서 서버에 연결해 볼 차례이다. 원하는 브라우저를 실행하고 다음 링크 중 하나를 직접 연결한다. 네트워크 측면에서 localhost(및 로컬호스트의 IP인 127.0.0.1)는 현재 사용중인 시스템을 가르킨다. 브라우저가 “Hello World!”라고 보여주면 정상인 것이다.

http://localhost
http://127.0.0.1

How the Server Works

이제 서버가 이상없이 실행되고 있으니 코드를 분석해 볼 차례이다. 첫번째로 살펴봐야 할 것은 1 라인에서 require()를 호출하고 있다는 것이다. Node.js는 대형 개발자 커뮤니티를 통해 간단한 모듈 시스템을 제공한다. Node.js 프로그램은 require() 메서드를 사용해서 각각의 모듈을 로드할 수 있다. 많은 모듈들의 경우 다운로드해서 사용해야 하지만, http와 같은 특정 모듈들은 Node.js 설치 시 포함되어 있다.

2 라인에서는 http 모듈의 createServer() 메서드를 사용해서 HTTP 서버를 생성했다. 대부분의 Node.js 함수와 마찬가지로createServer() 도 콜백 함수를 인자로 받는다. 이 콜백 함수는 서버가 새로운 요청을 받을때마다 매번 실행된다.

이 콜백 함수에서는 request와 response라는 두개의 인자를 받는다. request 객체는 URL, HTTP 헤더 등과 같은 클라이언트의 요청에 관한 정보를 포함하고 있다. 마찬가지로 response 객체는 클라이언트에게 데이터를 돌려보내는데 사용한다.

위 콜백 함수는 response.writeHead() 메서드의 호출로 시작한다. 이 메서드는 클라이언트에 HTTP 상태 코드와 response 헤더의 컬렉션을 보낸다. 여기서 상태 코드라는 것은 요청에 대한 결과를 가르키는 것이다. 예를 들면, 모든 사람들이 “페이지를 찾을 수 없다”는 것을 나타내는 404 에러를 만난 적이 있을 것이다. 위 예제의 서버는 “성공”을 나타내는 200 코드를 반환한다.

그 상태 코드에 따라서 서버는 응답의 파라미터들을 정의하고 있는 여러 HTTP 헤더를 반환하게 된다. 직접 헤더를 명시하지 않아도 Node.js는 암묵적으로 헤더를 전송한다. 예제의 서버는 Content-Type 헤더만을 명시하고 있다. 이 헤더는 응답의 MIME 타입을 정의한다. 응답이 HTML인 경우에 MIME 타입은 “text/html”이다.

다음으로 서버는 response.write()를 여러번 호출한다. 이것은 HTML 페이지를 작성하기 위해서 사용되는 것이다. 기본적으로 UTF-8 문자셋으로 인코딩된다. 성능 향상을 위해 기술적으로는 하나의 호출로 합치면 좋겠지만, 이 정도의 예제에서는 코드 가독성을 위해서 성능은 신경쓰지 않았다.

HTML 페이지를 모두 작성한 후에는 response.end() 메서드를 호출한다. 이 메서드를 호출함으로써 응답 헤더와 본문이 전송되고 요청에 대한 처리가 완료된다. 예제의 서버에서는 아무 파라미터 없이 end()를 호출하지만, 단지 한번의 호출만 필요하다고 가정한다면 write()와 같은 방식으로 호출될 수 있다.

15 라인에서는 listen()을 호출하여 서버에 포트를 바인딩하고 연결 요청을 리스닝하게 된다. 컴퓨터들은 종단간 통신에 사용되는 수천개의 포트를 가지고 있다. 서버에 연결하기 위해서는 클라이언트들은 서버가 리스닝하고 있는 포트를 정확히 알아야만 한다. HTTP 서버가 전통적으로 80번 포트를 사용하듯이 포트들은 각각의 포트 번호로써 식별된다.

Conclusion

이 글에서는 아주 기본적인 HTTP 서버를 보여줬다. 현재 상태로는 서버가 하나의 HTML 페이지만을 반환할 뿐이다. 다음주에는 파일 시스템으로부터 웹 페이지를 읽거나 HTTP 인증을 통합하는 것과 같은 추가적인 특성에 대해서 살펴보는 등 Node.js에 대해서 더 자세히 알아볼 것이다.



저작자 표시 비영리 변경 금지
신고
Posted by JuHoi
TAG node, node.js


[번역] An Introduction to Node.js, #Haroopress


지난번 sitepoint.com의 Introduction to Node.js Streams(http://sitepoint.com/introduction-to-streams/)를 번역 했었다. Node.js의 stream에 대해서 살펴보다 번역을 하게된 것인데, 자세히 보니 Node.js 카테고리에 8개의 article이 더 있었다. article 별로 내용이 그리 길지 않은 것 같아서 시간이 되는대로 처음부터 하나씩 번역을 해보기로 했다.

 원문 sitepoint.com의 An Introduction to Node.js(http://sitepoint.com/an-introduction-to-node-js/)

 오역 주의 오역을 발견하시면 꼭 알려주세요~ :-)

An Introduction to Node.js

JavaScript는 오랬동안 클라이언트측 웹 개발을 위한 사실상 표준이었다. 대부분의 클라이언트 코드가 JavaScript로 작성되는 반면 서버측 개발은 PHP, Java 그리고 여러가지 다른 기술들과의 매시업으로 이루어진다. 만약 하나의 언어가 어디서나 사용된다면 웹 개발자의 인생은 훨씬 편해질 것이다. 브라우저에서는 JavaScript가 지배적이기 때문에 서버에서 사용하는 것도 그럴 듯해 보인다.

서버측 JavaScript라는 발상은 새로운 것은 아니다. 처음에는 1994년에 Netscape에서 JavaScript를 서버 영역에 소개했다. 그 이후 JavaScript를 서버측 언어로 대중화 시키기 위한 몇몇의 프로젝트가 시도됐지만 실패하고 말았다. 실제 서버 영역에서 기반을 확보하기에는 성능상의 문제로 JavaScript의 사용을 금기시했다.

지난 수년간 JavaScript는 성능이 크게 향상되었다. 브라우저와의 연관성으로 인해 구글과 같은 대형 벤더에서 JavaScript를 가능한 빠르게 만들기 위해 많은 시간과 비용을 투자했다. Joyent의 Ryan Dahl(라이언 달)은 2009년에 Node.js 프레임워크를 만들 당시 서버상에서도 훌륭하게 사용될만한 성능을 새롭게 찾아 모든 것을 집약시켰다. 그는 구글의 V8 JavaScript 엔진을 기반으로 Node.js를 만들었다. V8은 구글 크롬에게 아주 훌륭한 JavaScript 성능을 가져다 주어 지구상에서 가장 대중적인 브라우저로 만들어 준 바로 그 엔진이다.

The Node.js Execution Model

아파치와 같은 많은 서버들은 여러 동시 접속을 처리하기 위해 스레드 풀을 유지 관리한다. 새로운 연결이 설정될 때는 그것을 처리하기 위해 별도의 스레드에게 위임한다. 어떤 요청이 처리되어 서비스되면 그 스레드는 향후 다른 요청에 재사용하기 위해 스레드 풀로 다시 반환된다. 이러한 방법의 문제점은 확장성이 부족하다는 것이다. 예를 들면, 많은 웹 애플리케이션들이 연결이 끊기지 않고 무한정 접속되어 있는 AJAX 연결을 만들어서 사용 가능한 모든 스레드들을 소비하게 된다.

Node.js는 요청을 처리하기 위해 완전히 다른 방법으로 접근하고 있다. Node.js 실행 모델은 이벤트 중심(event-driven)이고 확장성을 극대화하기 위해 비동기(asynchronous) 프로그래밍을 강조하고 있다. 또한, 싱글스레드(single-threaded)라는 가장 큰 약점을 감추기 위해넌블러킹(non-blocking) I/O를 활용한다. 개발자들은 “하나의 블러킹 I/O를 호출하는 것이 잠재적으로 전체 서버를 멈추게 할 수 있다”는 제한사항을 항상 알고 있어야 한다. Node.js 환경에서는 많은 함수들이 콜백 함수(I/O 이벤트가 완료되면 실행되는 함수)를 사용한다. 일부 개발자들의 경우 처음에는 이런 코딩 스타일을 어색해 하지만 사실은 웹페이지상에서 이벤트를 처리하는 것과 다를게 없다.

Getting Started with Node.js

Node.js를 사용하는 것은 무료이며, 프로젝트 홈페이지(공식 웹사이트)에서 다운로드할 수 있다. Windows, Mac, Linux 그리고 SunOS를 위한 바이너리 버전과 소스 코드 모두 사용 가능하다. 다운로드하고 설치하면 바로 Node.js 애플리케이션 개발을 시작할 수 있다.

아래에 보이는 것은 “Hello World”를 출력하는 가장 간단한 Node.js 프로그램이다. 이 예제는 터미널 창에 메시지를 보여주기 위해 내장 객체인 console 객체를 사용한다. “hello.js”라는 새로운 파일을 만들고 아래의 코드를 복사해 보자.

console.log("Hello World!");

이 예제를 실행시키려면 터미널 창에 다음의 명령어를 실행한다.

$ node hello.js

Node.js가 제대로 구성되어 있다면 터미널 창에 “Hello World!”가 출력될 것이다. 다들 알겠지만 이 예제는 Node.js가 할 수 있는 것들 중 극히 일부일 뿐이다. 다음주에는 Node.js에 대해서 더 자세히 살펴볼 것이다.

저작자 표시 비영리 변경 금지
신고
Posted by JuHoi
TAG node, node.js


[번역] Introduction to Node.js Streams, #Haroopress


 원문 sitepoint.com의 Introduction to Node.js Streams(http://sitepoint.com/introduction-to-streams/)

오역 주의 - 번역도 하다보면 나아질런지... :-)

Introduction to Node.js Streams

확장성. 빅데이터. 실시간... 이것들은 최근 인터넷이 직면한 몇가지 도전 과제들이다. 또한 이것은 Node.js와 Node.js의 넌블럭킹(non-blocking) I/O 모델이 나오게 된 배경이라고도 할 수 있다. 이 글에서는 Node의 데이터 집약적인 컴퓨팅을 위한 가장 강력한 API들 중 하나인 스트림(streams)에 대해서 소개할 것이다.

Why Use Streams?

다음 예제를 생각해 보자:

var http = require('http')
   , fs = require('fs')
   ;
var server = http.createServer(function (req, res) {
  fs.readFile(__dirname + '/data.txt', function (err, data) {
    res.end(data);
  });
});
server.listen(8000);

이 코드는 완벽하게 실행된다. 한가지 사실을 제외한다면 전혀 잘못된 점이 없다. 그것은 클라이언트에게 데이터를 보내기 전 data.txt 파일 내용 전체를 버퍼링한다는 것이다. 애플리케이션에 클라이언트의 요청이 증가하면 많은 메모리를 사용하게 되고 또한 지연시간이 증가하게 되어 클라이언트는 서버 애플리케이션에서 전체 파일을 읽을때까지 기다려야만 한다.

다른 예제를 보도록 하자:

var http = require('http')
  , fs = require('fs')
  ;
var server = http.createServer(function (req, res) {
  var stream = fs.createReadStream(__dirname + '/data.txt');
  stream.pipe(res);
});
server.listen(8000);

여기에서는 확장성에 대한 이슈를 극복하기 위해 스트림 API를 사용한다. 스트림 객체를 사용함으로써 data.txt 파일을 클라이언트에게 보낼때 서버 버퍼링이나 클라이언트의 대기시간 없이 디스크에서 읽어서 바로 한번에 하나의 청크(chunk, 데이터 단위)를 전송하는 것을 보장한다.

What are Streams?

스트림이란 데이터의 입, 출력 시 비동기적으로 처리될 수 있는 데이터의 연속된 흐름이라고 정의할 수 있다. Node.js에서는 스트림을 읽을(readable) 수도 있고 쓸(writable) 수도 있다. readable stream(읽기용 스트림)은 데이터 청크가 도착할 때마다 data 이벤트를 발생시키는 EventEmitter 객체이다. 바로 이전 예제에서는 HTTP 클라이언트에게 파일의 내용을 pipe 하기 위해 readable stream이 사용됐다. 스트림이 파일의 끝에 닿으면 더이상 data 이벤트가 발생하지 않는다는 것을 알려주는 end 이벤트를 발생시킨다. 또한 readable stream은 잠시 중지시키거나 재시작 시킬 수 있다.

반면 writable stream(쓰기용 스트림)은 데이터의 스트림을 받는다. 이것 역시 EventEmitter 객체를 상속하고 write() 와 end() 메소드 두가지를 구현하고 있다. 첫번째 메소드는 버퍼에 데이터를 쓰는 것으로 데이터가 정확하게 쓰여져 메모리가 비워지면(flush) true를 반환하고 만약 버퍼가 꽉 차게 되면 false를 반환하게 된다(이번 경우는 데이터가 늦게 전송될 것이다). end() 메소드는 단순히 스트림이 끝났다는 것을 나타낸다.

Your First Streams Application

그럼 스트림에 대해서 자세히 살펴보자. 그러기 위해서 우리는 간단한 파일 업로드 프로그램을 만들어 볼 것이다. 우선 readable stream을 사용하여 파일을 읽고 특정 목적지에 데이터를 pipe 시킬 클라이언트를 만들어야 한다. pipe의 반대편 끝에는 writable stream을 사용하여 업로드된 데이터를 저장하는 서버를 구현할 것이다.

클라이언트부터 시작해 보자. 우선 HTTP 및 file 시스템 모듈을 임포트하여 시작한다.

var http = require('http')
  , fs = require('fs');

그리고 HTTP 요청(request)을 정의한다.

var options = {
  host: 'localhost'
  , port: 8000
  , path: '/'
  , method: 'POST'
};
var req = http.request(options, function(res) {
  console.log(res.statusCode);
});

이제 파일을 읽을 readable stream을 생성하고 request 객체에 파일 내용을 pipe 한다.

var readStream = fs.ReadStream(__dirname + "/in.txt");
readStream.pipe(req);

모든 데이터를 읽어서 스트림이 끝나면 서버와의 연결을 끊고 request의 end() 메소드를 호출한다.

readStream.on('close', function () {
  req.end();
  console.log("I finished.");
});

The Server

클라이언트에서 했던 것처럼 Node.js 모듈을 임포트하는 것으로 시작한다. 그리고, 텍스트 파일에 데이터를 저장할 새로운 writable stream을 생성한다.

var http = require('http')
  , fs = require('fs');
var writeStream = fs.createWriteStream(__dirname + "/out.txt");

클라이언트에서 파일을 업로드할 수 있도록 새로운 웹서버 객체를 생성한다. request 객체로부터 데이터를 받으면 서버는 스트림을 호출하여 버퍼의 내용을 출력 파일로 쓰게 된다.

var server = http.createServer(function (req, res) {
  req.on('data', function (data) {
    writeStream.write(data);
  });
  req.on('end', function() {
    writeStream.end();
    res.statusCode = 200;
    res.end("OK");
  });
});
server.listen(8000);

createServer() 에서 반환되는 req 객체와 res 객체가 각각 readable stream과 writable stream이라는 것을 주목하기 바란다. 우리는 data 이벤트를 리스닝할 수 있고 모든 처리가 끝나면 클라이언트에게 결과를 파이프할 수도 있다.

Conclusion

이 글에서는 Node.js의 가장 강력한 부분 중 하나인 스트림 API에 대해서 소개를 했다. 다음주에는 Node.js에 내장된 다른 모든 유형들과 써드파티 스트림까지 스트림의 세계에 더 깊이 살펴볼 것이다.

 헉~! 다음주라니... 연재인줄 알았으면 번역하지 말것을... :-)

 Node.js 스트림 관련 문서


저작자 표시 비영리 변경 금지
신고
Posted by JuHoi