/**
* ์น์๋ฒ ๊ทธ ์ด์์ ๊ฒ๋ค
* - Socket IO
* - TCP/IP ๋คํธ์ํน
* - OS์ ์ํธ์์ฉํ๊ธฐ ์ํ ํด
* - ์ปค๋งจ๋๋ผ์ธ ํด ๊ฐ๋ฐํ๊ธฐ
*/
13.1. Socket.io
Socket IO ๋ WebSocket๊ณผ ์ ์ฌํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉด์๋, broadcasting, volatile ๋ฉ์์ง์ ํธ๋ฆฌํ๊ฒ ๊ตฌํํ ์ ์๋ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
WebSocket์
WebSocket ํ๋กํ ์ฝ์ ์ฌ์ฉํ๋๋ฐ ์์ง ์์ฑ๋ ํ๋กํ ์ฝ์ด ์๋๋ผ์ ๋ธ๋ผ์ฐ์ ๋ง๋ค ์ง์์ฌ๋ถ์๋ ์ฐจ์ด๊ฐ ์๋ค๋ ๋ฌธ์ ๊ฐ
์์ต๋๋ค. Socket IO๋ฅผ ์ด์ฉํ ๊ฒฝ์ฐ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋๋ฐ, Socket IO๋ WebSocket์ ์ง์ํ์ง ์๋
๋ธ๋ผ์ฐ์ ์ ๊ฒฝ์ฐ์ ๊ฐ ๋ธ๋ผ์ฐ์ ๋ณ๋ก ๋ค์ํ ๋ฐฉ๋ฒ์ ํตํด ๋ด๋ถ์ ์ผ๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ์ ์๋ค๊ณ ํฉ๋๋ค.
๏ก A minimal Socket.IO application that pushes the serverโs time to connected clients
๏ก A Socket.IO application that triggers page refreshes when CSS files are edited
13.1.1 ์ด๊ฐ๋จ Socket.IO ์ ํ๋ฆฌ์ผ์ด์
๋ง๋ค๊ธฐ
<< ๊ฐ๋จํ Socket IO clock-server ํ๋ก๊ทธ๋จ >> ( ์๊ฐ์ด ํ์๊ฐ ์๋๋๋ฐ ์ด์ ๋ฅผ ๋ชจ๋ฅด๊ฒ ์ ;;;; )
13.1.2 Socket.IO๋ฅผ ์ด์ฉํ ํ์ด์ง์ CSS reloading ํ๊ธฐ
์นํ์ด์ง ๋์์ธ์ ํ ๋ ์ผ๋ฐ์ ์ธ ์์
1 Open the web page in multiple browsers.
2 Look for styling on the page that needs adjusting.
3 Make changes to one or more stylesheets.
4 Manually reload all the web browsers.
5 Go back to step 2.
<< ์ 4๋ฒ ๊ณผ์ ์ ์ฝ๊ฒ ๋ง๋ค์ด์ฃผ๋ ํ๋ก๊ทธ๋จ ์์ >> ( ์ด๋๋ ์ ๋๋ก ๋์์ ํ์ง ์์...;;;)
13.1.3 Socket.IO์ ๋ ๋ค๋ฅธ ์ฌ์ฉ๋ฒ
Socket.IO๋ ํ๋ก๊ทธ๋ ์ค ๋ฐ๋ฅผ ๊ณ์ ์
๋ฐ์ดํธํด์ ์์น๊ฐ ์ฌ๋ผ๊ฐ๋ ๊ฒ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ์ ์ ํฉํจ
13.2 TCP/IP ๋คํธ์ํน
๋
ธ๋๋ ๋คํธ์ํน ์ ํ๋ฆฌ์ผ์ด์
์ ๋งค์ฐ ์ ํฉ. ๋คํธ์ํน์ ๋ง์ I/O๋ฅผ ์๊ตฌํ๊ธฐ ๋๋ฌธ.
๏ก Working with buffers and binary data
๏ก Creating a TCP server
๏ก Creating a TCP client
13.2.1 Buffers์ Binary Data ๋ค๋ฃจ๊ธฐ
Buffer ๋ฐ์ดํ ํ์
์ ๋
ธ๋์์ ์ ๊ณตํ๋ ํน๋ณํ ๋ฐ์ดํ ํ์
์ด๋ค.
๊ณ ์ ๊ธธ์ด์ raw binary data์ฒ๋ผ ๋์ํ๋ฉฐ, C์์์ malloc()์ด๋ C++, JAVA์์์ new ํค์๋๋ผ๊ณ ์๊ฐํด๋ ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก Stream ํด๋์ค์ ์ํด ๋ฐ์ดํ ์ด๋ฒคํธ ๋ด์ ๋ฐํ๋๋ค.
Buffer๋ ์ซ์ 0~ 255๊น์ง๋ง ์ ์ฅํ ์ ์๋ non-resizable ๋ฐฐ์ด์ด๋ค.
TEXT DATA VS. BINARY DATA
1. -----------------------------------
var b = new Buffer("121234869");
console.log(b.length);
9
console.log(b);
<Buffer 31 32 31 32 33 34 38 36 39>
2. -----------------------------------
var b = new Buffer(4);
b.writeInt32LE(121234869, 0);
console.log(b.length);
4
console.log(b);
<Buffer b5 e5 39 07>
-----------------------------------
13.2.2 TCP ์๋ฒ ๋ง๋ค๊ธฐ
Socket ํด๋์ค๋ client์ server ์์ชฝ์์ ๋ชจ๋ ์ฌ์ฉ๋จ
Itโs a Stream subclass thatโs both readable and writable (bidirectional).
That is, it emits data events when input data has been read from the socket,
and it has write() and end() functions for sending output data.
WRITING DATA
var net = require('net');
net.createServer(function (socket) {
socket.write('Hello World!\r\n');
socket.end();
}).listen(1337);
console.log('listening on port 1337');
$ telnet localhost 1337
READING DATA
socket.on('data', function (data) {
console.log('got "data"', data);
});
data ์ธ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก Buffer์ธ์คํด์ค์ด๋ค.
setEncoding()์ ์ด์ฉํด์ decoded String์ ์ธ์๋ก ๋๊ธธ ์๋ ์๋ค.
socket.on('end', function () {
console.log('socket has ended');
});
end ์ด๋ฒคํธ๋ฅผ ๋ฆฌ์ค๋ํจ์ผ๋ก์จ ๋ถํ์ํ ๋ฐ์ดํฐ ์ ์ก์ ํ์ง ์์ ์ ์๋ค.
SAMPLE TEST
var net = require('net');
var socket = net.connect({ host: process.argv[2], port: 22 });
socket.setEncoding('utf8');
socket.once('data', function (chunk) {
console.log('SSH server version: %j', chunk.trim());
socket.end();
});
$ node client.js github.com
SOCKET.PIPE() ์ ์ฌ์ฉํ์ฌ ๋ ๊ฐ์ ์คํธ๋ฆผ ์ฐ๊ฒฐํ๊ธฐ
The pipe()
ํจ์๋ readable ์คํธ๋ฆผ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์์ ์ฐ๊ธฐ๊ฐ๋ฅํ ์คํธ๋ฆผ์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๋ ์ญํ ์ ํฉ๋๋ค.
๋น์ ์ ์ฐ๊ฒฐ๋๊น ํธ๋ค๋งํ๊ธฐ
ํด๋ผ์ด์ธํธ๊ฐ netcat์ ์ผ์ ๋ Ctrl-D ๋์ Ctrl-C๋ก ์ปค๋ฅ์
์ ์ข
๋ฃ์ํค๋ฉด ์๋ฒ์ชฝ ์์ผ์ด ๊น๋ํ๊ฒ ์ข
๋ฃ๊ฐ ๋์ง ์๋๋ฐ, ์ด ๋ถ๋ถ์ ๋ํ ๋ท์ฒ๋ฆฌ๋ฅผ ํ๋ ค๋ฉด ์๋์ฒ๋ผ close ์ด๋ฒคํธ๋ฅผ ๋ฆฌ์ค๋ํ๋ฉด ๋๋ค.
socket.on('close', function () {
console.log('client disconnected');
});
FINAL TEST APP
server
var net = require('net');
net.createServer(function (socket) {
console.log('socket connected!');
socket.on('data', function (data) {
console.log('"data" event', data);
});
socket.on('end', function () {
console.log('"end" event');
});
socket.on('close', function () {
console.log('"close" event');
});
socket.on('error', function (e) {
console.log('"error" event', e);
});
socket.pipe(socket);
}).listen(1337);
client
var net = require('net');
var host = process.argv[2];
var port = Number(process.argv[3]);
var socket = net.connect(port, host);
socket.on('connect', function () {
process.stdin.pipe(socket);
socket.pipe(process.stdout);
process.stdin.resume();
});
socket.on('end', function () {
process.stdin.pause();
});
13.3 Tools for interacting with the operating system
๏ก The global process objectโContains information about the current process, such
as the arguments given to it and the environment variables that are currently set
๏ก The fs moduleโContains the high-level ReadStream and WriteStream classes
that youโre familiar with by now, but also houses low-level functions that weโll
look at
๏ก The child_process moduleโContains both low-level and high-level interfaces
for spawning child processes, as well as a special way to spawn node instances
with a two-way message-passing channel
13.3.1 The process global singleton
Every Node process has a single global process object that every module shares access
to. Useful information about the process and the context itโs running in can be found
in this object.
the most interesting feature of the process object is that itโs an EventEmitter instance, which emits very special events,
such as exit and uncaughtException.
USING PROCESS.ENV TO GET AND SET ENVIRONMENT VARIABLES
SPECIAL EVENTS EMITTED BY PROCESS
๏ก exit gets emitted right before the process exits.
process.on('exit', function (code) {
console.log('Exiting...');
});
๏ก uncaughtException gets emitted any time an unhandled error is thrown.
process.on('uncaughtException', function (err) {
console.error('got uncaught exception:', err.message);
process.exit(1);
});
throw new Error('an uncaught exception');
CATCHING SIGNALS SENT TO THE PROCESS
three signals that Node handles by default
๏ก SIGINTโSent by your shell when you press Ctrl-C. Nodeโs default behavior is to
kill the process, but this can be overridden with a single listener for SIGINT on
process.
๏ก SIGUSR1โWhen this signal is received, Node will enter its built-in debugger.
๏ก SIGWINCHโSent by your shell when the terminal is resized. Node resets
process.stdout.rows and process.stdout.columns and emits a resize event
when this is received.
13.3.2 Using the filesystem module
MOVING A FILE
fs.rename()
์๊ฒฉ์ผ๋ก ์ด๋์ํค๋ ค๋ฉด stream์ ์ด์ฉํด์ ๋ณต์ฌํด์ผ ํจ. rename์ ์๊ฒฉ์ง๋ก ์ด๋ํ๋ ๊ฒ์ ์ง์ํ์ง ์์.
WATCHING A DIRECTORY OR FILE FOR CHANGES
fs.watch() - ํ๋ซํผ์ ๋ค์ดํฐ๋ธ ํ์ผ ๋ณ๊ฒฝ ์๋ฆผ API๋ฅผ ์ด์ฉํจ. (ํ๋ซํผ ์ฐจ์ด๋ก ์ธํด unreliable ํจ)
fs.watchFile()
USING COMMUNITY MODULES: FSTREAM AND FILED
fstream์ ์ด์ฉํ๋ฉด cp -rp srcDir destDir ๋ช
๋ น์ด๋ฅผ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค.
filed ์ธ์คํด์ค๋ req, res ๊ฐ์ฒด์ ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
http.createServer(function (req, res) {
req.pipe(filed('path/to/static/files')).pipe(res);
});
์ ์ฝ๋๋ ํ์ผ์ด ์บ์ฌ๋์์ ๋ 304 Not Modified ์ค๋ฅ๋ฅผ ๋ฑ์ด๋ด๊ณ ํ์ผ์ ๋์คํฌ์์ ์ด๊ฑฐ๋ ์ฝ๋ ํ์๋ ํ์ง ์๋๋ค.
13.3.3 Spawning external processes
๏ก cp.exec()โA high-level API for spawning commands and buffering the result
in a callback
๏ก cp.spawn()โA low-level API for spawning single commands into a Child-
Process object
๏ก cp.fork()โA special way to spawn additional Node processes with a built-in
IPC channel
์์ ํ๋ก์ธ์ค์ ์ฅ๋จ์ (PROS AND CONS TO CHILD PROCESSES)
cons : child process ๋ก ์คํ๋๋ ์ ํ๋ฆฌ์ผ์ด์
์ด ์ด๋ฏธ ํด๋ผ์ด์ธํธ์ ์ค์น๊ฐ ๋์ด์์ด์ผ ํ๋ค.
pros : ๋ค๋ฅธ ์ธ์ด๋ก ์ฐ์ฌ์ง ์ ํ๋ฆฌ์ผ์์
์ ์ด์ฉํด์ ์ข ๋ richํ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์ด ๊ฐ๋ฅํ๋ค.
cp.exec()๋ก ๋ช
๋ น์ด ๊ฒฐ๊ณผ ๋ฒํผ๋งํ๊ธฐ(BUFFERING COMMAND RESULTS USING CP.EXEC())
cp.exec(), is useful for when you want to invoke a command, and you only care about the final result. This API allows you to enter full sequences of commands, including multiple processes piped to one another.
SPAWNING COMMANDS WITH A STREAM INTERFACE USING CP.SPAWN()
cp.spawn() returns a ChildProcess object that you can interact with.
ex)
var child = cp.spawn('ls', [ '-l' ]);
// stdout is a regular Stream instance, which emits 'data',
// 'end', etc.
child.stdout.pipe(fs.createWriteStream('ls-result.txt'));
child.on('exit', function (code, signal) {
// emitted when the child process exits
});
DISTRIBUTING THE WORKLOAD USING CP.FORK()
Like cp.spawn(), cp.fork() returns a ChildProcess object.
The major difference is the API added by the IPC channel: the child process now has a child.send (message) function, and the script being invoked by fork() can listen for process.on('message') events.
ํผ๋ณด๋์น ์์ด ๊ณ์ฐ ์์
13.4 ์ปค๋งจ๋๋ผ์ธ ํด ๊ฐ๋ฐํ๊ธฐ(Developing command-line tools )
๏ก Parsing command-line arguments
๏ก Working with stdin and stdout streams
๏ก Adding pretty colors to the output using ansi.js
13.4.1 Parsing command-line arguments
Node provides you with the process.argv property, which is an array of strings, which are the arguments that were used when Node was invoked.
The first entry of the array is the Node executable, and the second entry is the name of your script.
ex)
var args = process.argv.slice(2);
console.log(args);
$ node args.js
[]
$ node args.js hello world
[ 'hello', 'world' ]
$ node args.js "tobi is a ferret"
[ 'tobi is a ferret' ]
์ด๋ค ์ต์
์ด ๋ค์ด์๋๋์ ๋ฐ๋ผ usageํ๋ฆฐํธํ๋ ์์
13.4.2 stdin, stdout ๊ฐ์ง๊ณ ๋๊ธฐ (Working with stdin and stdout)
๏ก process.stdinโA ReadStream to read input data from
๏ก process.stdoutโA WriteStream to write output data to
WRITING OUTPUT DATA WITH PROCESS.STDOUT
console.log() ๋ด์์ process.stdout.write()์ด ์ฌ์ฉ๋จ.
(์ดํด๋ฆฝ์ค์์ argument ์ค์ ํด์ฃผ๊ณ ์คํํ๋ค๊ณ ๊ฐ์ )
var target = process.argv[2];
process.stdout.write('Entered value is : ' + target);
PROCESS.STDIN ๋ก ์
๋ ฅ๊ฐ ์ฝ์ด์ค๊ธฐ (READING INPUT DATA WITH PROCESS.STDIN )
Before you can read from stdin, you must call process.stdin.resume() to indicate that your script is interested in data from stdin.
After that, stdin acts like any other readable stream, emitting data events as data is received from the output of another process, or as the user enters keystrokes into the terminal window.
๋์ด ๊ฒ์ฆํ๋ ์์
DIAGNOSTIC LOGGING WITH PROCESS.STDERR
process.stderr์ ์ง์ ์ฌ์ฉํ์ง๋ง๊ณ console.error()๋ฅผ ์ฌ์ฉํ์.
13.4.3 ์ถ๋ ฅ์ ์ ์
ํ๊ธฐ (Adding colored output)
ANSI ์ด์ค์ผ์ดํ ์ฝ๋ ์์ฑํ๊ธฐ (CREATING AND WRITING ANSI ESCAPE CODES )
(cmd ์ฐฝ์์ ansi.js ์คํ)
console.log('\033[43m\033[35mhello\033[39m\033[49m');
var ansi = require('ansi');
var cursor = ansi(process.stdout);
cursor
.fg.green()
.write('This should be green.')
.fg.reset()
.write('\n');