2017년 10월 25일 수요일

Chapter4. NodeJS의 기본 모듈3



학습 목표

1. 스트림에서 이벤트와 데이터를 다룰 수 있습니다.
2. URL 모듈로 URL을 분석하고 생성할 수 있습니다.
3. queryString 모듈로 쿼리 문자열을 다룰 수 있습니다.
4. 클러스터 모듈을 이용해서 클러스터링의 장점을 활용할 수 있습니다.

1. 스트림

◎ 스트림 : 데이터의 전송 흐름

  • 콘솔 입력/출력
  • 파일 읽기/쓰기
  • 서버/클라이언트 - 데이터 전송
◎ 스트림 모듈
  • 스트림을 다루기 위한 추상 인터페이스
  • 다양한 스트림을 같은 인터페이스로 다룰 수 있다.
◎ 스트림 종류
  • 읽기 스트림 : Readable Stream
  • 쓰기 스트림 : Writable Stream
  • 읽기/쓰기 : Duplex
  • 변환 : Transform
◎ Readable Stream
  • 읽기 스트림 : Readable
  • 모드 : flowing, paused
  • flowing mode
    → 데이터를 자동으로 읽는 모드
    → 전달되는 데이터를 다루지 않으면 데이터 유실
  • paused mode
    → 데이터가 도착하면 대기
    → read() 함수로 데이터 읽기
▷ Readable 메소드
  • 읽기
    → readable.read([size])
    → readable.setEncoding(encoding)
  • 중지/재개
    → readable.pause()
    → readable.resume()
  • 파이프
    → readable.pipe(destination[, options])
    → readable.unpipe([destination])
▷ Readable 이벤트
  • readable : 읽기 가능한 상태
  • data : 읽을 수 있는 데이터 도착
  • end : 더 이상 읽을 데이터가 없는 상태
  • close : 스트림이 닫힌 상태
  • error : 에러
▷ flowing mode
  • data 이벤트 구현
  • pipe 연결
  • resume() 호출
▷ 파일 스트림에서 읽기 : flowing mode
var is = fs.createReadStream(file);
is.on('readable', function() {
    console.log('== READABLE EVENT');
});

// flowing모드
is.on('data', function(chunk) {
    console.log('== DATA EVENT');
    console.log(chunk.toString());
    // buffering 필요
});

// end 이벤트
is.on('end', function() {
    console.log('== END EVENT');
});

▷ 파일 스트림에서 읽기  : paused mode
var is = fs.createReadStream(file);

// 'data'이벤트가 없으면 pause mode
is.on('readable', function() {
    console.log('== READABLE EVENT');

    // 10바이트씩 읽기
    while(chunk == is.read(10)) {
        console.log('chunk : ', chunk.toString());
    }
});

◎ Writable Stream
▷ Writable Stream : 데이터 출력
▷ 예

  • http 클라이언트의 요청
  • http 서버의 응답
  • 파일 쓰기 스트림
  • tcp 소켓
▷ 메소드
▷ 데이터 쓰기, 인코딩
  • writable.setDefaultEncoding(encoding)
  • writable.write(chunk[, encoding][, callback])
▷ 스트림 닫기
  • writable.end([chunk][, encoding][, callback])
▷ 버퍼
  • writable.cork()
  • writable.uncork()
▷ 이벤트
  • drain : 출력 스트림에 남은 데이터를 모두 보낸 이벤트
  • error : 에러
  • finish : 모든 데이터를 쓴 이벤트
  • pipe ; 읽기 스트림과 연결(pipe)된 이벤트
  • unpipe : 연결(pipe)해제 이벤트
◎ 출력 스트림에 쓰기
▷ 파일 기반의 출력 스트림에 쓰기
var os = fs.createWriteStream('output.txt');
os.on('finish', function() {
    console.log('==FINISH EVENT');
});

os.write('1234\n');
os.write('5678\n');

os.end('9\n'); // finish event

◎ 표준 입출력 스트림
▷  표준 입출력 스트림

  • process.stdin : 콘솔 입력
  • process.stdout : 콘솔 출력
◎ 스트림 연결
▷ 스트림 연결과 해제(Readable)
  • readable.pipe(destination[, options])
  • readable.unpipe([destination])
▷ 연결 이벤트(Writable)
  • pipe
  • unpipe
▷ 스트림 연결
  • 입력 스트림 : stdin
  • 출력 스트림 : 파일
▷ 스트림 연결 예제
var is = process.stdin;
var os = fs.createWritableStream('ouput.txt');

os.on('pipe', function(src) {
    console.log('pipe event');
});

// exist 입력이 오면 파이프 연결 해제
is.on('data', function(data) {
    if(data.trim() == 'exit') {
        is.unpipe(os);
    }
});

is.pipe(os);


2. URL 다루기

◎ 네트워킹
▷ 네트워킹의 시작

  • 서버 주소
  • 서버에서 요청 위치
  • 서버에서 리소스의 위치
▷ URL : Uniform Resource Locator
  • http://nodejs.org/api/
  • http://nodejs.org/api/http.html
  • http://nodejs.org/api/http.html#http_event_connect // 뒤에 프레그먼트가 붙음
◎ URL
▷ UR L 구성 요소
  • 프로토콜(Protocol)
  • 호스트(Host)
  • 포트번호(Post)
  • 경로(Path)
  • 쿼리(Query)
  • 프래그먼트(Fragment)

http://images.apple.com/mac/home/images/tap_hero_macpro_2x.jpg
scheme  host            path
http://www.google.com/search?q=iphone&format=json
            host                    query

▷ URL 모듈
var url = require('url');

▷ URL 모듈
url.parse(urlStr[, parseQueryString][, slashesDenoteHost])
  • urlStr : URL 문자열
  • parseQueryString : 쿼리 문자열 파싱 여부, 기본값 false
  • slashesDenoteHost : //로 시작하는 주소의 경우, 호스트 인식 여부
    기본값 false
▷ URL 분석하기
var urlStr = 'http://idols.com/q?group=EXID&name=하니&since=';
var parse = url.parse(urlStr);

▷ 결과
host : 'idols.com'
search : '?group=EXID&name=하니&since=',
query : group=EXID&name=하니&since=,
pathname : '/q',
path : '/q?group=EXID&name=하니&since=,

◎ URL과 쿼리 문자열
▷ 쿼리 문자열(query string)
이름=값&이름=값 형태로 정보 전달
http://idolos.com/q?group=EXID&name=하니&since=
▷ URL 모듈로 쿼리 문자열 파싱
url.parse('http:/...', true);

▷ URL 분석하기
var urlStr = 'http://idols.com/q?group=EXID&name=하니&since=';
var parsed = url.parse(urlStr, true);
var query = parsed.query;

▷ 결과
query.group // EXID
query.name  // 하니
query.since   //

◎ URL 만들기
▷ URL 만들기
url.format(urlObj)

▷ URL 변환
url.resolve(from, to)

▷ URL 만들기 : format

  • protocol : 프로토콜
  • host : 서버 호스트 주소
  • pathname : 경로
  • search : 쿼리 스트링
  • auth : 인증 정보
var urlObj = {
    protocol : 'http',
    host : 'idols.com',
    pathname : 'schedule/radio',
    search : 'time=9pm&day=monday'
}

var urlStr = url.format(urlObj);
// http://idols.com/schedule/radio?time=9pm&day=monday

◎ URL 인코딩
▷ URL에 허용되는 문자

  • 알파벳, 숫자, 아이폰, 언더스코어, 점, 틸드
▷ URL 인코딩하기
https://www.google.com/search?q=아이폰
https://www.google.com/search?q=%EC%95%84%EC%9D%B4%ED%8F%B0

▷ 써드 파티 모듈
  • urlencode

3. 쿼리 스트링


◎ 쿼리 문자열

  • 쿼리 문자열은 URL 외에도 사용
  • 쿼리 문자열(query string)
    name1=value1&name2=value2&name3=&name4=
  • HTTP 메시지 바디로 정보를 전달할 때도 사용
◎ URL과 쿼리 문자열
▷ querystring 모듈
var querystring = require('querystring');

▷ 쿼리 문자열 분석하기
querystring.parse(str[, sep][, eq][, options])

sep, eq : 쿼리 구분자와 = 기호(&, = 대체)
var querystring = require('querystring');
var str = 'group=EXID&NAME=하니&since=';

var parsed = querystring.parse(str);

parsed.group // EXIT
parsed.name // 하니
parsed.since // ''
parsed.last // undefined

◎ 쿼리 스트링 중 배열
▷ 쿼리 스트링의 배열

  • qroup=걸스데이&member=혜리&member=유라&member=민아
◎ 쿼리 문자열 만들기

  • querystring.stringfy(obj[, sep][, eq][, options])
  • sep, eq : 쿼리 구분자와 = 기호
  • 인코딩 자동
var queryObj = {
    name : 'IU',
    best : '좋은날'
};

var queryStr = querystring.stringfy(queryObj);
// name=IU&best=%EC%A2%8B%EC%9D%80%EB%82%A0

4. 클러스터

◎ 클러스터(Cluster)
여러 시스템을 하나로 묶어서 사용하는 기술

개별 시스템 내에서 클러스터

  • 멀티 프로세스
  • 멀티 코어
▷ NodeJS의 클러스터
  • Node.js 애플리케이션 : 1개의 싱클 스레드
  • 멀티 코어 시스템의 장점을 살리기 - 클러스터
  • Node.js 클러스터
    → 클러스터 사용시 포트 공유 - 서버 작성 편리
    → 코어(프로세서)의 개수 만큼 사용
▷ 클러스터 생성시 개념
  • 클러스터링 : 마스터와 워커 프로세스
  • 마스터
    → 메인 프로세스
    → 워커 생성
  • 워커
    → 보조 프로세스
    → 마스터가 생성
◎ 클러스터 모듈
▷ 클러스터 모듈
  • var cluster = require('cluster');
▷ 클러스터 생성(마스터)
  • cluster.fork()
▷ 구분하기
  • cluster.isMaster
  • cluster.isWorker
◎ 클러스터 생성과 동작
클러스터링을 사용하는 대략적인 구조

마스터 - 워커 생성
if( cluster.isMaster ) {
    // 마스터 코드
    cluster.fork();
}
else {
    // 워커 코드
}

◎ 클러스터의 이벤트
▷ 클러스터의 이벤트
  • fork : 워커 생성 이벤트
  • online : 워커 생성 후 동작하는 이벤트
  • listening : 워커에 작성한 서버의 listen 이벤트
  • disconnect : 워커 연결 종료
  • exit : 워커 프로세스 종료
▷ 워커의 이벤트
  • message : 메시지 이벤트
  • disconnect : 워커 연결 종료
◎ 워커
▷ 워커 접근
// 워커 접근
  • cluster.worker
▷ 워커 식별자
// 워커 id
  • worker.id
◎ 워커 종료
▷ 워커 종료
  • worker.kill([signal='SIGTERM'])

◎ 클러스터 생성과 동작
▷ 클러스터를 사용하는 대략적인 구조
if(cluster.isMaster) {
    cluster.fork();
    cluster.on('online', function(worker) {
        // 워커 생성 후 실행
        console.log('Worker #' + worker.id + ' is Online');
    });
    cluster.on('exit', function(worker, code, signal) {
        // 워커 종료 이벤트
        console.log('Worker #' + worker.id + ' exit');
    });
}
else {
    var worker = cluster.worker;
    // 워커 종료
    worker.kill();
}

◎ 서버 클러스터
▷ 서버에 클러스터 적용
if(cluster.isMaster) {
    cluster.fork();
} else {
    http.createServer(function(req, res) {
        // 서버 코드
    }).listen(8000);
}

▷ 클러스터링 기능 지원 프로세스 모듈

  • pm2

◎ 데이터 전달
▷ 마스터가 워커에게 데이터 전달

  • worker.send(data)
▷ 워커의 데이터 이벤트
  • worker.on('message', function(data) {
    });
▷ 워커가 마스터에게 데이터 전달
  • process.send(data)
▷ 마스터에서의 데이터 이벤트
  • var worker = cluster.fork();
  • worker.on('message', function(data) {
    });
if(cluster.isMaster) {
    var worker = cluster.fork();
    worker.on('message', function(message) {
        console.log('Master received : ', message);
    });

    cluster.on('online', function(worker) {
        worker.send({message : 'Hello Worker'});
    });
} else {
    var worker = cluster.worker;

    worker.on('message', function(message) {
        process.send({message:'Fine thank you!'});
    });
}

◎ 마스터와 워커 분리
▷ 별도의 파일로 분리하기
cluster.setupMaster([settings])
  • exec : 워커 파일
  • args : 실행 파라미터
▷ 마스터 - fork
cluster.setupMaster({
    exe:'worker.js'
});
cluster.fork();

학습정리

◎ 지금까지 'Node.JS의 기본모듈 3'에 대해 살펴보았습니다.

▷ 스트림
네트워크를 이용한 통신은 스트림을 이용해서 데이터를 주고받습니다. 스트림
모듈을 이용해서 데이터와 이벤트를 알아봤습니다.

▷ URL 다루기
네트워크를 이용한 통신에서 URL은 리소스 위치를 다룹니다. URL 모듈로 정보를
분석하고 생성할 수 있었습니다.

▷ 쿼리 문자열 다루기
쿼리 문자열은 정보를 전달하는 방법으로 자주 사용합니다. querystring 모듈로
정보를 분석하고 생성할 수 있었습니다.

▷ 클러스터링
클러스터 모듈을 이용해서 다중 프로세서의 장점을 살릴 수 있는 클러스터링을
구현해봤습니다.





댓글 없음: