주요한 노드 내장 모듈들에 대해 빠르게 알아보자!
1️⃣ os
- 사용자 컴퓨터의 운영체제 정보
- 일반적인 웹 서비스를 제작할 때는 사용 빈도가 높지 않지만 운영체제 별로 다른 서비스를 제공하고 싶을 때 유용
• os.arch(): process.arch와 동일
• os.platform(): process.platform과 동일
• os.type(): 운영체제의 종류를 보여줌
• os.uptime(): 운영체제 부팅 이후 흐른 시간(초)을 보여줌. process.uptime()은 노드의 실행 시간
• os.hostname(): 컴퓨터의 이름을 보여줌
• os.release(): 운영체제의 버전을 보여줌
• os.homedir(): 홈 디렉터리 경로를 보여줌
• os.tmpdir(): 임시 파일 저장 경로를 보여줌
• os.cpus(): 컴퓨터의 코어 정보를 보여줌
• os.freemem(): 사용 가능한 메모리(RAM)를 보여줌
• os.totalmem(): 전체 메모리 용량을 보여줌
2️⃣ path
- 폴더와 파일의 경로를 쉽게 조작하도록 도와주는 모듈
- 앞으로 노드 프로그래밍을 하면서 매우 자주 쓰게 될 모듈 중 하나
• path.sep: 경로의 구분자. 윈도는 \, POSIX는 /
• path.delimiter: 환경 변수의 구분자. process.env.PATH를 입력하면 여러 개의 경로가 이 구분자로 구분됨. 윈도는 세미콜론(;)이고, POSIX는 콜론(:).
• path.dirname(경로): 파일이 위치한 폴더 경로를 보여줌.
• path.extname(경로): 파일의 확장자를 보여줌.
• path.basename(경로, 확장자): 파일의 이름(확장자 포함)을 표시. 파일의 이름만 표시하고 싶다면 basename의 두 번째 인수로 파일의 확장자를 넣으면 됨
• path.parse(경로): 파일 경로를 root, dir, base, ext, name으로 분리
• path.format(객체): path.parse()한 객체를 파일 경로로 합침
• path.normalize(경로): /나 \를 실수로 여러 번 사용했거나 혼용했을 때 정상적인 경로로 변환
• path.isAbsolute(경로): 파일의 경로가 절대경로인지 상대경로인지를 true나 false로 알림
• path.relative(기준경로, 비교경로): 경로를 두 개 넣으면 첫 번째 경로에서 두 번째 경로로 가는 방법을 알림
• path.join(경로, …): 여러 인수를 넣으면 하나의 경로로 합침. 상대경로인 ..(부모 디렉터리)과 .(현 위치)도 알아서 처리.
• path.resolve(경로, …): path.join()과 비슷하지만 차이가 있음.
3️⃣ url
- 인터넷 주소를 쉽게 조작하도록 도와주는 모듈
url 처리의 두가지 방식
1. WHATWG
const url = require('url');
// url 모듈 안에 URL 생성자가 있음
// 이 URL 생성자에 주소를 넣어 객체로 만들면 주소가 부분별로 정리됨
// WHATWG에만 있는 username, password, origin, searchParams 속성이 존재
const { URL } = url;
const myURL = new URL('http://www.gilbut.co.kr/book/bookList.aspx?sercate1=001001000#anchor');
console.log('new URL():', myURL);
console.log('url.format():', url.format(myURL));
console.log('------------------------------');
const parsedUrl = url.parse('http://www.gilbut.co.kr/book/bookList.aspx?sercate1=001001000#anchor');
console.log('url.parse():', parsedUrl);
console.log('url.format():', url.format(parsedUrl));
2. 기존 노드 방식 : 아래 두개의 메서드를 주로 사용
(1) url.parse(주소)
- 주소를 분해
- WHATWG의 username과 password 대신 auth 속성
- WHATWG의 searchParams 대신 query 속성
(2) url.format(객체)
- WHATWG 방식 url과 기존 노드의 url을 모두 사용할 수 있음
- 분해되었던 url 객체를 다시 원래 상태로 조립
searchParams 객체의 여러 메서드들
• getAll(키): 키에 해당하는 모든 값들을 가져옴. category 키에는 nodejs와 javascript라는 두 가지 값이 들어 있음.
• get(키): 키에 해당하는 첫 번째 값만 가져옴.
• has(키): 해당 키가 있는지 없는지를 검사
• keys(): searchParams의 모든 키를 반복기(iterator)(ES2015 문법) 객체로 가져옴
• values(): searchParams의 모든 값을 반복기 객체로 가져옴
• append(키, 값): 해당 키를 추가합니다. 같은 키의 값이 있다면 유지하고 하나 더 추가
• set(키, 값): append와 비슷하지만, 같은 키의 값들을 모두 지우고 새로 추가.
• delete(키): 해당 키를 제거
• toString(): 조작한 searchParams 객체를 다시 문자열로 만듦. 이 문자열을 search에 대입하면 주소 객체에 반영
📌 query 같은 문자열보다 searchParams가 유용한 이유는 query의 경우 다음에 배우는 querystring 모듈을 한 번 더 사용해야 하기 때문
📌 querystring
- WHATWG방식의 url 대신 기존 노드의 url을 사용할 때, search 부분을 사용하기 쉽게 객체로 만드는 모듈
• querystring.parse(쿼리): url의 query 부분을 자바스크립트 객체로 분해
• querystring.stringify(객체): 분해된 query 객체를 문자열로 다시 조립
4️⃣ crypto
- 다양한 방식의 암호화를 도와주는 모듈
📌 단방향 암호화 알고리즘
- 비밀번호와 같이 복호화가 필요없는 경우
- 해시 기법을 주로 사용
- 해시 기법? 어떠한 문자열을 고정된 길이의 다른 문자열로 바꿔버리는 방식
• createHash(알고리즘): 사용할 해시 알고리즘을 넣음. md5, sha1, sha256, sha512 등이 가능하지만, md5와 sha1은 이미 취약점이 발견. 현재는 sha512 정도로 충분하지만, 나중에 sha512마저도 취약해지면 더 강화된 알고리즘으로 바꿔야 함.
• update(문자열): 변환할 문자열을 넣음.
• digest(인코딩): 인코딩할 알고리즘을 넣음. base64, hex, latin1이 주로 사용되는데, 그중 base64가 결과 문자열이 가장 짧아 애용. 결과물로 변환된 문자열을 반환.
📌 양방향 암호화 알고리즘
- 키를 통해 암호화된 문자열을 복호화 할 수 있음
• crypto.createCipheriv(알고리즘, 키, iv): 암호화 알고리즘과 키, iv를 넣습니다. 암호화 알고리즘은 aes-256-cbc를 사용했으며, 다른 알고리즘을 사용해도 됩니다. aes-256-cbc 알고리즘의 경우 키는 32바이트여야 하고, iv는 16바이트여야 합니다. iv는 암호화할 때 사용하는 초기화 벡터를 의미하지만, 이 책에서 설명하기에는 내용이 많으므로 AES 암호화에 대해 따로 공부하는 것이 좋습니다. 사용 가능한 알고리즘 목록은 crypto.getCiphers()를 호출하면 볼 수 있습니다.
• cipher.update(문자열, 인코딩, 출력 인코딩): 암호화할 대상과 대상의 인코딩, 출력 결과물의 인코딩을 넣습니다. 보통 문자열은 utf8 인코딩을, 암호는 base64를 많이 사용합니다.
• cipher.final(출력 인코딩): 출력 결과물의 인코딩을 넣으면 암호화가 완료됩니다.
• crypto.createDecipheriv(알고리즘, 키, iv): 복호화할 때 사용합니다. 암호화할 때 사용했던 알고리즘과 키, iv를 그대로 넣어야 합니다.
• decipher.update(문자열, 인코딩, 출력 인코딩): 암호화된 문장, 그 문장의 인코딩, 복호화할 인코딩을 넣습니다. createCipheriv의 update()에서 utf8, base64순으로 넣었다면 createDecipheriv의 update()에서는 base64, utf8순으로 넣으면 됩니다.
• decipher.final(출력 인코딩): 복호화 결과물의 인코딩을 넣습니다.
5️⃣ util
- 각종 편의 기능을 모아둔 모듈
• util.deprecate: 함수가 deprecated 처리되었음을 알립니다. 첫 번째 인수로 넣은 함수를 사용했을 때 경고 메시지가 출력됩니다. 두 번째 인수로 경고 메시지 내용을 넣으면 됩니다. 함수가 조만간 사라지거나 변경될 때 알려줄 수 있어 유용합니다.
• util.promisify: 콜백 패턴을 프로미스 패턴으로 바꿉니다. 바꿀 함수를 인수로 제공하면 됩니다. 이렇게 바꿔두면 async/await 패턴까지 사용할 수 있어 좋습니다. 3.5.5.1절의 randomBytes와 비교해보세요. 프로미스를 콜백으로 바꾸는 util.callbackify도 있지만 자주 사용되지는 않습니다.
6️⃣ worker_threads
- 노드에서 멀티 스레드 방식으로 작업하는 것이 가능하게 하는 모듈
worker_threads.js
const {
Worker, isMainThread, parentPort,
} = require('worker_threads');
if (isMainThread) { // 부모일 때
const
worker = new Worker(__filename);
worker.on('message', message => console.log('from worker', message));
worker.on('exit', () => console.log('worker exit'));
worker.postMessage('ping');
} else { // 워커일 때
parentPort.on('message', (value) => {
console.log('from parent', value);
parentPort.postMessage('pong');
parentPort.close();
});
}
worker.postMessage : 워커에 데이터를 보냄
parentPort.on('message') 이벤트리스너 : 부모로부터 메시지를 받음
parentPost.postMessage('pong'): 부모에게 메시지를 보냄
worker.on('message') : 부모가 메시지를 받는 방법
parentPort.close() : 부모와의 연결 종료
→ 종료될때는 worker.on('exit')이 실행
$ node worker_threads
from parent ping
from worker pong
worker exit
📌 여러개의 worker thread에 데이터를 보내보기
// worker_data.js
const {
Worker, isMainThread, parentPort, workerData,
} = require('worker_threads');
if (isMainThread) { // 부모일 때
const threads = new Set();
threads.add(new Worker(__filename, {
workerData: { start: 1 },
}));
threads.add(new Worker(__filename, {
workerData: { start: 2 },
}));
for (let worker of threads) {
worker.on('message', message => console.log('from worker', message));
worker.on('exit', () => {
threads.delete(worker);
if (threads.size === 0) {
console.log('job done');
}
});
}
} else { // 워커일 때
const data = workerData;
parentPort.postMessage(data.start + 100);
}
new Worker을 호출할 때, 두번째 인수의 workerData 속성으로 원하는 데이터를 보낼 수 있음
각 워커에서는 workerData로 부모로부터 데이터를 받음
위의 코드에서는 두개의 워커가 돌아가고 있으며, 각각 부모로부터 숫자를 받아서 100을 더해 돌려줌 → 돌려주는 순간 워커가 종료되어 worker.on('exit') 수행 → 두개의 워커 모두 종료되면 job done이 로깅
$ node worker_data
from worker 101
from worker 102
job done
7️⃣ child_process
- 노드에서 다른 프로그램을 실행하고 싶거나 명령어를 수행하고 싶을 때 사용하는 모듈
- 현재 노드 프로세스 외에 새로운 프로세스를 띄워서 명령을 수행하고, 노드 프로세스에 결과를 알려줌 (그래서 이름이 자식 프로세스 인 것!)
📌 exec
- 명령 프롬프트의 명령어 ls를 노드를 통해 실행해보자! (윈도우의 경우 dir)
const exec = require('child_process').exec;
var process = exec('dir');
process.stdout.on('data', function(data) {
console.log(data.toString());
}); // 실행 결과
process.stderr.on('data', function(data) {
console.error(data.toString());
}); // 실행 에러
결과
- stdout(표준출력)과 stderr(표준에러)에 붙여둔 data 이벤트 리스너에 버퍼 형태로 전달
- 현재 폴더의 파일 목록이 표시됨.
📌 spawn
- 파이썬 코드를 실행해보자
- spawn의 첫번째 인수 : 명령어
- spawn의 두번째 인수 : 옵션 배열
const spawn = require('child_process').spawn;
var process = spawn('python', ['test.py']);
process.stdout.on('data', function(data) {
console.log(data.toString());
}); // 실행 결과
process.stderr.on('data', function(data) {
console.error(data.toString());
}); // 실행 >에러
exec 와 spawn의 차이점
- exec : 셸을 실행해서 명령어를 수행
- spawn : 새로운 프로세스를 띄우면서 명령어를 실행
Reference
- Node.js 교과서 개정 2판
'Node.js' 카테고리의 다른 글
[Node] REST, HTTP 메서드 개념 (0) | 2022.12.11 |
---|---|
[Node] 이벤트, 이벤트 메서드 (0) | 2022.12.10 |
[Node] 파일시스템, 버퍼, 스트림 알아보기 (0) | 2022.12.10 |
[Node] 노드의 내장 객체들 (0) | 2022.12.08 |
[Node] Node의 동작 방식과 장단점 (0) | 2022.12.05 |