const net = require('net');
const HOST = '127.0.0.1'
, PORT = 8080;
// Server
const server = net.createServer();
server.on('connection', function (serverSocket) {
console.log('Client connected to server at ' + serverSocket.remoteAddress + ':' + serverSocket.remotePort);
serverSocket.on('data', function (data) {
console.log('Data from client ' + serverSocket.remoteAddress + ': ' + data);
serverSocket.write('Client said: ' + data);
});
serverSocket.on('close', function () {
console.log('Client closed connection to server: ' + serverSocket.remoteAddress +' '+ serverSocket.remotePort);
});
serverSocket.on('error', function (error) {
throw error;
})
});
server.listen(PORT, HOST, function () {
console.log('Server started at ' + server.address().address + ':' + server.address().port);
});
// Client
const client = new net.Socket();
client.connect(PORT, HOST, function () {
console.log('Client established connection to: ' + HOST + ':' + PORT);
client.write('Hello');
});
client.on('data', function (data) {
console.log('Answer from server: ' + data);
console.log('Client ready to close connection. ');
client.destroy(); // kill client and close connection after server's response
});
client.on('close', function () {
console.log('Client closed his connection.');
});
понедельник, 11 сентября 2017 г.
пятница, 8 сентября 2017 г.
Использование child_process exec(), execFile(), spawn(), fork() в Node.js.
В Node.js модуль child_process предлагает 4 метода для выполнения внешних программ:
- exec()
- execFile()
- spawn()
- fork()
Все 4 метода выполняются асинхронно.
Каждый метод возвращает объект, которые является экземпляром класса ChildProcess.
--------------------------
child_process.exec()
child_process.execFile()
child_process.spawn()
child_process.fork()
--------------------------
|
----------------------
ChildProcess object
----------------------
|
-----------------
ChildProcess
-----------------
- close <Event>
- exit <Event>
- error <Event>
-----------------
- stdin <Stream | String>
- stdout <Stream | String>
- stderr <Stream | String>
- stdio <Array>
-----------------
|
----------------------
extends EventEmitter
----------------------
Описание методов.
1. child_process.exec()
Что делает?
Создает отдельную оболочку терминала, внутри которой выполняет внешнюю программу и буферизирует возвращаемые в результате её выполнения данные.
Принимает путь до файла, набор необязательных опций, описывающих окружение, в котором будет выполняться внешняя программа и функцию callback, в которую передаётся набор значений о результате выполнения внешней программы.
Возвращает объект класса <ChildProcess>.
По сравнению с execFile() и spawn(), метод exec() не имеет массив аргументов argsArray, в который передаётся в исполняемый файл внешней программы, поскольку метод exec() позволяет выполняться несколько команд подряд внутри оболочки терминала.
Если необходимо в метод exec() передать аргументы, то их просто записывают, как часть команды или пути до исполняемого файла внешней программы.
В каких случаях необходимо использовать метод exec?
Метод exec() используется, когда необходимо выполнить внешнюю команду у получить доступ ко всей функциональности оболочки терминала, такой как pipe, redirect, backgrounding и тому подобное.
Метод exec() выполняет команду в оболочке терминала "/bin/sh" в Linux и "cmd.exe" в Windows.
Использование метода exec() в командной оболочке может нести в себе опасность shell injection exploit.
Поэтому везде, где возможно, стоит взамен использовать метод execFile(), для которого неправильная передача аргументов приведёт к возникновению ошибке, а не взлому.
Как пользоваться?
const child_process = require('child_process');
child_process.exec('dir /D', {shell: true, encoding: 'utf8'}, function (error, stdout, stderr) {
if (error) {throw error;}
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
});
Когда внешняя команда запускается в окне оболочке терминала, мы получаем доступ ко всей функциональности оболочки терминала.
В данном примере мы запускаем отдельную подоболочку терминала и выполняем в ней команду 'dir /D'.
Какие передаются аргументы?
child_process.exec(filePathOrCommandsWithArguments, optionsObject, callbackFunction);
- filePathOrCommandsWithArguments <String> - путь до исполняемого файла внешней программы, просто её имя или команда для консоли терминала вместе с набором аргументов для этой программы, отделенных друг от друга пробелами.
Откуда Node.js узнаёт, где искать исполняемый файл внешней программы?
Node.js использует переменную окружения PATH из операционной системы, в которой содержится набор директорий расположения исполняемых программ.
Если путь до внешней программы, которую надо выполнить, содержится в переменной PATH, то она может быть обнаружена без указания абсолютного или относительного пути до неё.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- encoding <String> - кодировка (по умолчанию: 'utf8').
--- shell <String> - внешняя программа будет запущена внутри оболочки терминала "cmd.exe". По умолчанию в качестве терминала используется программа "/bin/sh" на UNIX и "cmd.exe" на Windows. На Windows оболочка терминала должна быть совместима с "cmd.exe".
--- timeout <Number> - время ожидания до начала выполнения внешней программы (по умолчанию: 0).
--- maxBuffer <Number> - максимальный объём данных в байтах, поступающих из внешней программы, допустимый для передачи в stdout или stderr. Если допустимый объём переданных данных будет превышен, то процесс выполнения внешней программы будет убит (по умолчанию: 200 *1024).
--- killSignal <String> - сигнал для убийства процесса выполнения внешней программы (по умолчанию: 'SIGTERM').
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней программы(смотри setgid(2)).
- callbackFunction <Function> - функция обратного вызова, которая вызывается после завершения выполнения внешней программы, в неё поступаютс следующие значения:
--- error <Error> - аргумент, хранящий в себе сообщение об ошибке в случае её возникновения в процессе запуска внешней программы.
--- stdout <String> | <Buffer> - результат выполнения внешней программы в виде поступивших от неё данных.
--- stderr <String> | <Buffer> - результат ошибки во время выполнения внешней программы в виде поступивших от неё данных об ошибке.
2. child_process.execFile()
Что делает?
Выполняет любой исполняемый файл внешней программы.
Принимает путь до файла, набор необязательных аргументов, набор опций, описывающих окружение, в котором будет выполняться внешняя программа и функцию callback, в которую передаётся набор значений о результате выполнения внешней программы.
Возвращает объект класса <ChildProcess>.
В каких случаях необходимо использовать метод execFile?
Метод execFile() используется, когда необходимо выполнить внешнюю программу и получить только вывод результата её выполнения.
Например, мы можем использовать метод execFile() для запуска программы "ImageMagick", которая конвертирует картинку из формата PNG в формат JPG и нам необходимо только знать завершился ли процесс конвертации успешно или нет.
Не следует использовать метода execFile(), когда внешняя выполняемая программа возвращает огромный объём данных, которые надо обработать в режиме реального времени. Для этого случая используйте метод spawn().
Как пользоваться?
const child_process = require('child_process');
const child = child_process.execFile('node.exe', ['--version'], {cwd: process.cwd(), encoding: 'utf8'}, function (error, stdout, stderr) {
if (error) {
console.error('stderr: ' + Buffer.isBuffer(stderr) ? stderr.toString() : stderr);
throw error;
}
console.log('stdout: ' + Buffer.isBuffer(stdout) ? stdout.toString() : stdout);
});
Внешняя программа "node.exe" вызывается с аргументом "--version".
После того, как она завершит своё выполнение, будет вызвана callback функция.
В callback функцию передаются значения "stdout" и "stderr" с результатами выполнения программы "node.exe".
Значения "stdout" и "stderr" могут передаваться в виде буфер или строки.
Какие передаются аргументы?
child_process.execFile(filePath, argsArray, optionsObject, callbackFunction);
- filePath <String> - путь до исполняемого файла внешней программы или просто её имя.
Откуда Node.js узнаёт, где искать исполняемый файл внешней программы?
Node.js использует переменную окружения PATH из операционной системы, в которой содержится набор директорий расположения исполняемых программ.
Если путь до внешней программы, которую надо выполнить, содержится в переменной PATH, то она может быть обнаружена без указания абсолютного или относительного пути до неё.
- argsArray <Array> - массив аргументов, которые передаются в исполняемый файл внешней программы.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- encoding <String> - кодировка (по умолчанию: 'utf8').
--- timeout <Number> - время ожидания до начала выполнения внешней программы (по умолчанию: 0).
--- maxBuffer <Number> - максимальный объём данных в байтах, поступающих из внешней программы, допустимый для передачи в stdout или stderr. Если допустимый объём переданных данных будет превышен, то процесс выполнения внешней программы будет убит (по умолчанию: 200 *1024).
--- killSignal <String> - сигнал для убийства процесса выполнения внешней программы (по умолчанию: 'SIGTERM').
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней программы(смотри setgid(2)).
- callbackFunction <Function> - функция обратного вызова, которая вызывается после завершения выполнения внешней программы, в неё поступаютс следующие значения:
--- error <Error> - аргумент, хранящий в себе сообщение об ошибке в случае её возникновения в процессе запуска внешней программы.
--- stdout <String> | <Buffer> - результат выполнения внешней программы в виде поступивших от неё данных.
--- stderr <String> | <Buffer> - результат ошибки во время выполнения внешней программы в виде поступивших от неё данных об ошибке.
3. child_process.spawn()
Что делает?
Выполняет внешнюю программу в отдельном процессе и возвращает интерфейс ввода-вывода для передачи данных от внешней программы в потоке stream.
Принимает путь до файла, набор необязательных аргументов, набор опций, описывающих окружение, в котором будет выполняться внешняя программа и возвращает объект типа stream, для управления потоком данных, поступающих из внешней программы.
Возвращает объект класса <ChildProcess>.
В каких случаях необходимо использовать метод spawn?
Метод spawn() возвращает объект stream для управления потоком чтения и записи внешней выполняемой программы, поэтому он хорош для выполнения внешней программы, которая возвращает большие объёмы данных.
Как пользоваться?
Пример 1.
const child_process = require('child_process');
const spawnProcess = child_process.spawn('dir', ['/D'], {shell: true});
spawnProcess.on('error', function (error) {throw error;});
spawnProcess.stdout.on('data', function (data) {console.log('stdout: ' + data);});
spawnProcess.stderr.on('data', function (data) {console.log('stderr: ' + data);});
spawnProcess.on('close', function (code, signal) {console.log('Child process exited with code ' + code);});
spawnProcess.on('exit', function (code, signal) {console.log('Child exited with code ' + code);});
spawnProcess.stdin.write('data');
spawnProcess.stdin.end();
console.log(spawnProcess.pid);
Пример 2.
const fs = require('fs');
const child_process = require('child_process');
const spawnImageProcess = child_process.spawn('convert.exe', [
"-", // use stdin
"-resize", "640x", // resize width to 640
"-resize", "x360<", // resize height if it's smaller than 360
"-gravity", "center", // sets the offset to the center
"-crop", "640x360+0+0", // crop
"-" // output to stdout
], {shell: false});
const readImageStream = fs.createReadStream('./path/to/image.jpg');
readImageStream.pipe(spawnImageProcess.stdin);
spawnImageProcess.stdout.pipe(serverResponseStream);
Представим, что у нас есть сервис для преобразования картинок (imagemagick.org).
В данном примере создаётся поток чтения кода картинки из файла, который передается во входной поток внешней программы "convert.exe", которая преобразует картинку.
Затем преобразованные данные картинки передаются в поток ответа от сервера к браузеру.
До тех пор пока процесс spawnImageProcess производит преобразования данных картинки, они передаются в поток ответа от сервера к браузеру и пользователь сайта немедленно начинает получать результат обработки картинки без необходимости ожидать завершения всего процесса сразу.
Какие передаются аргументы?
const spawnProcess = child_process.spawn(filePathOrTerminalCommand, argsArray, optionsObject);
- filePathOrTerminalCommand <String> - путь до исполняемого файла внешней программы, просто её имя или команда для консоли терминала.
Откуда Node.js узнает где искать исполняемый файл внешней программы?
Node.js использует переменную окружения PATH из операционной системы, в которой содержится набор директорий расположения исполняемых программ.
Если путь до внешней программы, которую надо выполнить, содержится в переменной PATH, то она может быть обнаружена без указания абсолютного или относительного пути до неё.
- argsArray <Array> - массив аргументов, которые передаются в исполняемый файл внешней программы.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- stdio <Array> | <String> конфигурация stdio для дочернего процесса (смотри options.stdio).
--- detached <Boolean> - заупскать и выполнять ли внешнюю программу независимо от выполнения вызвавшего его родительского процесса Node.js. Особенности выполнения зависят от платформы (смотри options.detached).
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней программы (смотри setgid(2)).
--- shell <Boolean> | <String> - если равно true, то внешняя программа будет запущена внутри оболочки терминала "cmd.exe". По умолчанию в качестве терминала используется программа "/bin/sh" на UNIX и "cmd.exe" на Windows. Другая оболочка терминала, в которой будет выполнена внешняя программа, может быть задана в виде строки. Оболочка терминала должна понимать команду -c switch на UNIX и /s /c на Windows. По умолчанию равно false, что означает не запускать внешнюю программу внутри оболочки терминала.
4. child_process.fork()
Что делает?
Метод fork() является частным случаем метода spawn().
Он используется для создания отдельно Node.js процесса, в котором выполняется файл внешней JavaScript-программы.
Как и метод spawn(), метод fork() возвращает объект класса <ChildProcess>.
Возвращенный объект класса <ChildProcess> из метода fork() имеет дополнительный канал коммуникации для передачи сообщений между родительской программой и дочерним процессом внешней программы.
Таким образом, метод fork() открывате IPC канал, которые позволяет передавать сообщения между двумя программами Node.js:
- со стороны дочернего процесса внешней программы для получения и посыла сообщений могут быть использованы методы process.on('message', function (dataFromParent) {}) и process.send('message to parent').
- со стороны родительского процесса, который запустил внешнюю программу, для получения и посыла сообщений могут быть использованы методы forkedChild.on('message', function (dataFromChild) {}) и forkedChild.send('message to child').
Канал обмена сообщений открыт до тех пор, пока внешняя исполняемая JavaScript-программа не завершит своего выполнения.
Процесс каждой программы имеет свою собственную память и запущенный экземпляр движка V8.
В каких случаях необходимо использовать метод fork?
Поскольку Node.js выполняет все операции в одном потоке, то долго выполняемые операции могут тормозить основной процесс.
Поэтому метод fork() используется, когда необходимо выполнить длительные JavaScript-операции. В этом случае запускается отдельная Node.js программа, которая общается с родительской программой с помощью передачи друг другу сообщений, что позволяет родительской программе быть доступной для выполнения других операций.
Как использовать?
Файл родительской программы parent.js:
const child_process = require('child_process');
const forkedChild = child_process.fork(__dirname + '/child.js', ['build']);
forkedChild.on('message', function (message) {
console.log('PARENT got message from child: ' + message.foo + ' | '+ message.arg);
});
forkedChild.send({hello: 'world'});
Файл дочерней внешней программы child.js:
process.on('message', function (message) {
console.log('CHILD got message: ' + message.hello);
process.exit();
});
process.send({foo: 'bar', arg: process.argv[2]});
Какие передаются аргументы?
child_process.fork(jsFilePath, argsArray, optionsObject);
- jsFilePath <String> - путь до исполняемого файла внешней JavaScript-программы.
- argsArray <Array> - массив аргументов, которые передаются в исполняемый файл внешней JavaScript-программы.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя JavaScript-программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней JavaScript-программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- execPath <String> - путь до исполняемого файла, используемого для создания дочернего процесса внешней JavaScript-программы.
--- execArgv <Array> - массив строк аргументов, которые передаются в исполняемый файл, используемый для создания дочернего процесса внешней JavaScript-программы (по умолчанию: process.execArgv).
--- silent <Boolean> - если равно true, то stdin, stdout, stderr дочерней внешней JavaScript-программы будут связаны (pipe) с родительским процессом, в противном случае они будут наследованы от родительского процесса (смотри опции "pipe" и "inherit" метода child_process.spawn()) (по умолчанию: false).
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней JavaScript-программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней JavaScript-программы(смотри setgid(2)).
- exec()
- execFile()
- spawn()
- fork()
Все 4 метода выполняются асинхронно.
Каждый метод возвращает объект, которые является экземпляром класса ChildProcess.
--------------------------
child_process.exec()
child_process.execFile()
child_process.spawn()
child_process.fork()
--------------------------
|
----------------------
ChildProcess object
----------------------
|
-----------------
ChildProcess
-----------------
- close <Event>
- exit <Event>
- error <Event>
-----------------
- stdin <Stream | String>
- stdout <Stream | String>
- stderr <Stream | String>
- stdio <Array>
-----------------
|
----------------------
extends EventEmitter
----------------------
Описание методов.
1. child_process.exec()
Что делает?
Создает отдельную оболочку терминала, внутри которой выполняет внешнюю программу и буферизирует возвращаемые в результате её выполнения данные.
Принимает путь до файла, набор необязательных опций, описывающих окружение, в котором будет выполняться внешняя программа и функцию callback, в которую передаётся набор значений о результате выполнения внешней программы.
Возвращает объект класса <ChildProcess>.
По сравнению с execFile() и spawn(), метод exec() не имеет массив аргументов argsArray, в который передаётся в исполняемый файл внешней программы, поскольку метод exec() позволяет выполняться несколько команд подряд внутри оболочки терминала.
Если необходимо в метод exec() передать аргументы, то их просто записывают, как часть команды или пути до исполняемого файла внешней программы.
В каких случаях необходимо использовать метод exec?
Метод exec() используется, когда необходимо выполнить внешнюю команду у получить доступ ко всей функциональности оболочки терминала, такой как pipe, redirect, backgrounding и тому подобное.
Метод exec() выполняет команду в оболочке терминала "/bin/sh" в Linux и "cmd.exe" в Windows.
Использование метода exec() в командной оболочке может нести в себе опасность shell injection exploit.
Поэтому везде, где возможно, стоит взамен использовать метод execFile(), для которого неправильная передача аргументов приведёт к возникновению ошибке, а не взлому.
Как пользоваться?
const child_process = require('child_process');
child_process.exec('dir /D', {shell: true, encoding: 'utf8'}, function (error, stdout, stderr) {
if (error) {throw error;}
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
});
Когда внешняя команда запускается в окне оболочке терминала, мы получаем доступ ко всей функциональности оболочки терминала.
В данном примере мы запускаем отдельную подоболочку терминала и выполняем в ней команду 'dir /D'.
Какие передаются аргументы?
child_process.exec(filePathOrCommandsWithArguments, optionsObject, callbackFunction);
- filePathOrCommandsWithArguments <String> - путь до исполняемого файла внешней программы, просто её имя или команда для консоли терминала вместе с набором аргументов для этой программы, отделенных друг от друга пробелами.
Откуда Node.js узнаёт, где искать исполняемый файл внешней программы?
Node.js использует переменную окружения PATH из операционной системы, в которой содержится набор директорий расположения исполняемых программ.
Если путь до внешней программы, которую надо выполнить, содержится в переменной PATH, то она может быть обнаружена без указания абсолютного или относительного пути до неё.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- encoding <String> - кодировка (по умолчанию: 'utf8').
--- shell <String> - внешняя программа будет запущена внутри оболочки терминала "cmd.exe". По умолчанию в качестве терминала используется программа "/bin/sh" на UNIX и "cmd.exe" на Windows. На Windows оболочка терминала должна быть совместима с "cmd.exe".
--- timeout <Number> - время ожидания до начала выполнения внешней программы (по умолчанию: 0).
--- maxBuffer <Number> - максимальный объём данных в байтах, поступающих из внешней программы, допустимый для передачи в stdout или stderr. Если допустимый объём переданных данных будет превышен, то процесс выполнения внешней программы будет убит (по умолчанию: 200 *1024).
--- killSignal <String> - сигнал для убийства процесса выполнения внешней программы (по умолчанию: 'SIGTERM').
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней программы(смотри setgid(2)).
- callbackFunction <Function> - функция обратного вызова, которая вызывается после завершения выполнения внешней программы, в неё поступаютс следующие значения:
--- error <Error> - аргумент, хранящий в себе сообщение об ошибке в случае её возникновения в процессе запуска внешней программы.
--- stdout <String> | <Buffer> - результат выполнения внешней программы в виде поступивших от неё данных.
--- stderr <String> | <Buffer> - результат ошибки во время выполнения внешней программы в виде поступивших от неё данных об ошибке.
2. child_process.execFile()
Что делает?
Выполняет любой исполняемый файл внешней программы.
Принимает путь до файла, набор необязательных аргументов, набор опций, описывающих окружение, в котором будет выполняться внешняя программа и функцию callback, в которую передаётся набор значений о результате выполнения внешней программы.
Возвращает объект класса <ChildProcess>.
В каких случаях необходимо использовать метод execFile?
Метод execFile() используется, когда необходимо выполнить внешнюю программу и получить только вывод результата её выполнения.
Например, мы можем использовать метод execFile() для запуска программы "ImageMagick", которая конвертирует картинку из формата PNG в формат JPG и нам необходимо только знать завершился ли процесс конвертации успешно или нет.
Не следует использовать метода execFile(), когда внешняя выполняемая программа возвращает огромный объём данных, которые надо обработать в режиме реального времени. Для этого случая используйте метод spawn().
Как пользоваться?
const child_process = require('child_process');
const child = child_process.execFile('node.exe', ['--version'], {cwd: process.cwd(), encoding: 'utf8'}, function (error, stdout, stderr) {
if (error) {
console.error('stderr: ' + Buffer.isBuffer(stderr) ? stderr.toString() : stderr);
throw error;
}
console.log('stdout: ' + Buffer.isBuffer(stdout) ? stdout.toString() : stdout);
});
Внешняя программа "node.exe" вызывается с аргументом "--version".
После того, как она завершит своё выполнение, будет вызвана callback функция.
В callback функцию передаются значения "stdout" и "stderr" с результатами выполнения программы "node.exe".
Значения "stdout" и "stderr" могут передаваться в виде буфер или строки.
Какие передаются аргументы?
child_process.execFile(filePath, argsArray, optionsObject, callbackFunction);
- filePath <String> - путь до исполняемого файла внешней программы или просто её имя.
Откуда Node.js узнаёт, где искать исполняемый файл внешней программы?
Node.js использует переменную окружения PATH из операционной системы, в которой содержится набор директорий расположения исполняемых программ.
Если путь до внешней программы, которую надо выполнить, содержится в переменной PATH, то она может быть обнаружена без указания абсолютного или относительного пути до неё.
- argsArray <Array> - массив аргументов, которые передаются в исполняемый файл внешней программы.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- encoding <String> - кодировка (по умолчанию: 'utf8').
--- timeout <Number> - время ожидания до начала выполнения внешней программы (по умолчанию: 0).
--- maxBuffer <Number> - максимальный объём данных в байтах, поступающих из внешней программы, допустимый для передачи в stdout или stderr. Если допустимый объём переданных данных будет превышен, то процесс выполнения внешней программы будет убит (по умолчанию: 200 *1024).
--- killSignal <String> - сигнал для убийства процесса выполнения внешней программы (по умолчанию: 'SIGTERM').
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней программы(смотри setgid(2)).
- callbackFunction <Function> - функция обратного вызова, которая вызывается после завершения выполнения внешней программы, в неё поступаютс следующие значения:
--- error <Error> - аргумент, хранящий в себе сообщение об ошибке в случае её возникновения в процессе запуска внешней программы.
--- stdout <String> | <Buffer> - результат выполнения внешней программы в виде поступивших от неё данных.
--- stderr <String> | <Buffer> - результат ошибки во время выполнения внешней программы в виде поступивших от неё данных об ошибке.
3. child_process.spawn()
Что делает?
Выполняет внешнюю программу в отдельном процессе и возвращает интерфейс ввода-вывода для передачи данных от внешней программы в потоке stream.
Принимает путь до файла, набор необязательных аргументов, набор опций, описывающих окружение, в котором будет выполняться внешняя программа и возвращает объект типа stream, для управления потоком данных, поступающих из внешней программы.
Возвращает объект класса <ChildProcess>.
В каких случаях необходимо использовать метод spawn?
Метод spawn() возвращает объект stream для управления потоком чтения и записи внешней выполняемой программы, поэтому он хорош для выполнения внешней программы, которая возвращает большие объёмы данных.
Как пользоваться?
Пример 1.
const child_process = require('child_process');
const spawnProcess = child_process.spawn('dir', ['/D'], {shell: true});
spawnProcess.on('error', function (error) {throw error;});
spawnProcess.stdout.on('data', function (data) {console.log('stdout: ' + data);});
spawnProcess.stderr.on('data', function (data) {console.log('stderr: ' + data);});
spawnProcess.on('close', function (code, signal) {console.log('Child process exited with code ' + code);});
spawnProcess.on('exit', function (code, signal) {console.log('Child exited with code ' + code);});
spawnProcess.stdin.write('data');
spawnProcess.stdin.end();
console.log(spawnProcess.pid);
Пример 2.
const fs = require('fs');
const child_process = require('child_process');
const spawnImageProcess = child_process.spawn('convert.exe', [
"-", // use stdin
"-resize", "640x", // resize width to 640
"-resize", "x360<", // resize height if it's smaller than 360
"-gravity", "center", // sets the offset to the center
"-crop", "640x360+0+0", // crop
"-" // output to stdout
], {shell: false});
const readImageStream = fs.createReadStream('./path/to/image.jpg');
readImageStream.pipe(spawnImageProcess.stdin);
spawnImageProcess.stdout.pipe(serverResponseStream);
Представим, что у нас есть сервис для преобразования картинок (imagemagick.org).
В данном примере создаётся поток чтения кода картинки из файла, который передается во входной поток внешней программы "convert.exe", которая преобразует картинку.
Затем преобразованные данные картинки передаются в поток ответа от сервера к браузеру.
До тех пор пока процесс spawnImageProcess производит преобразования данных картинки, они передаются в поток ответа от сервера к браузеру и пользователь сайта немедленно начинает получать результат обработки картинки без необходимости ожидать завершения всего процесса сразу.
Какие передаются аргументы?
const spawnProcess = child_process.spawn(filePathOrTerminalCommand, argsArray, optionsObject);
- filePathOrTerminalCommand <String> - путь до исполняемого файла внешней программы, просто её имя или команда для консоли терминала.
Откуда Node.js узнает где искать исполняемый файл внешней программы?
Node.js использует переменную окружения PATH из операционной системы, в которой содержится набор директорий расположения исполняемых программ.
Если путь до внешней программы, которую надо выполнить, содержится в переменной PATH, то она может быть обнаружена без указания абсолютного или относительного пути до неё.
- argsArray <Array> - массив аргументов, которые передаются в исполняемый файл внешней программы.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- stdio <Array> | <String> конфигурация stdio для дочернего процесса (смотри options.stdio).
--- detached <Boolean> - заупскать и выполнять ли внешнюю программу независимо от выполнения вызвавшего его родительского процесса Node.js. Особенности выполнения зависят от платформы (смотри options.detached).
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней программы (смотри setgid(2)).
--- shell <Boolean> | <String> - если равно true, то внешняя программа будет запущена внутри оболочки терминала "cmd.exe". По умолчанию в качестве терминала используется программа "/bin/sh" на UNIX и "cmd.exe" на Windows. Другая оболочка терминала, в которой будет выполнена внешняя программа, может быть задана в виде строки. Оболочка терминала должна понимать команду -c switch на UNIX и /s /c на Windows. По умолчанию равно false, что означает не запускать внешнюю программу внутри оболочки терминала.
4. child_process.fork()
Что делает?
Метод fork() является частным случаем метода spawn().
Он используется для создания отдельно Node.js процесса, в котором выполняется файл внешней JavaScript-программы.
Как и метод spawn(), метод fork() возвращает объект класса <ChildProcess>.
Возвращенный объект класса <ChildProcess> из метода fork() имеет дополнительный канал коммуникации для передачи сообщений между родительской программой и дочерним процессом внешней программы.
Таким образом, метод fork() открывате IPC канал, которые позволяет передавать сообщения между двумя программами Node.js:
- со стороны дочернего процесса внешней программы для получения и посыла сообщений могут быть использованы методы process.on('message', function (dataFromParent) {}) и process.send('message to parent').
- со стороны родительского процесса, который запустил внешнюю программу, для получения и посыла сообщений могут быть использованы методы forkedChild.on('message', function (dataFromChild) {}) и forkedChild.send('message to child').
Канал обмена сообщений открыт до тех пор, пока внешняя исполняемая JavaScript-программа не завершит своего выполнения.
Процесс каждой программы имеет свою собственную память и запущенный экземпляр движка V8.
В каких случаях необходимо использовать метод fork?
Поскольку Node.js выполняет все операции в одном потоке, то долго выполняемые операции могут тормозить основной процесс.
Поэтому метод fork() используется, когда необходимо выполнить длительные JavaScript-операции. В этом случае запускается отдельная Node.js программа, которая общается с родительской программой с помощью передачи друг другу сообщений, что позволяет родительской программе быть доступной для выполнения других операций.
Как использовать?
Файл родительской программы parent.js:
const child_process = require('child_process');
const forkedChild = child_process.fork(__dirname + '/child.js', ['build']);
forkedChild.on('message', function (message) {
console.log('PARENT got message from child: ' + message.foo + ' | '+ message.arg);
});
forkedChild.send({hello: 'world'});
Файл дочерней внешней программы child.js:
process.on('message', function (message) {
console.log('CHILD got message: ' + message.hello);
process.exit();
});
process.send({foo: 'bar', arg: process.argv[2]});
Какие передаются аргументы?
child_process.fork(jsFilePath, argsArray, optionsObject);
- jsFilePath <String> - путь до исполняемого файла внешней JavaScript-программы.
- argsArray <Array> - массив аргументов, которые передаются в исполняемый файл внешней JavaScript-программы.
- optionsObject <Object> - набор опций, описывающих окружение, в котором будет выполняться внешняя JavaScript-программа:
--- cwd <String> - текущая рабочая директория, относительно которой будет выполняться файл внешней JavaScript-программы.
--- env <Object> - пары key-value, описывающее рабочее окружение.
--- execPath <String> - путь до исполняемого файла, используемого для создания дочернего процесса внешней JavaScript-программы.
--- execArgv <Array> - массив строк аргументов, которые передаются в исполняемый файл, используемый для создания дочернего процесса внешней JavaScript-программы (по умолчанию: process.execArgv).
--- silent <Boolean> - если равно true, то stdin, stdout, stderr дочерней внешней JavaScript-программы будут связаны (pipe) с родительским процессом, в противном случае они будут наследованы от родительского процесса (смотри опции "pipe" и "inherit" метода child_process.spawn()) (по умолчанию: false).
--- uid <Number> - устанавливает идентификатор пользователя для процесса выполнения внешней JavaScript-программы (смотри setuid(2)).
--- gid <Number> - устанавливает идентификатор группы для процесса выполнения внешней JavaScript-программы(смотри setgid(2)).
среда, 6 сентября 2017 г.
TCP proxy server
client --> proxy --> remote --> proxy --> client
Файл proxy.js
var net = require('net');
var LOCAL_PORT = 8080
, LOCAL_ADDR = '127.0.0.1'
, REMOTE_PORT = 80
, REMOTE_ADDR = 'google.com';
var server = net.createServer(function (socket) {
socket.on('data', function (data) {
console.log('------- START -------');
console.log('<< From client to proxy ', data.toString());
var serviceSocket = new net.Socket();
serviceSocket.connect(REMOTE_PORT, REMOTE_ADDR, function () {
console.log('>> From proxy to remote', data.toString());
serviceSocket.write(data);
});
serviceSocket.on('data', function (data) {
console.log('<< From remote to proxy', data.toString());
socket.write(data);
console.log('>> From proxy to client', data.toString());
});
serviceSocket.on('error', function () {throw error;});
});
});
server.listen(LOCAL_PORT, LOCAL_ADDR, function () {
console.log('TCP server accepting connection on port: ' + LOCAL_ADDR + ':' + LOCAL_PORT);
});
Файл proxy.js
var net = require('net');
var LOCAL_PORT = 8080
, LOCAL_ADDR = '127.0.0.1'
, REMOTE_PORT = 80
, REMOTE_ADDR = 'google.com';
var server = net.createServer(function (socket) {
socket.on('data', function (data) {
console.log('------- START -------');
console.log('<< From client to proxy ', data.toString());
var serviceSocket = new net.Socket();
serviceSocket.connect(REMOTE_PORT, REMOTE_ADDR, function () {
console.log('>> From proxy to remote', data.toString());
serviceSocket.write(data);
});
serviceSocket.on('data', function (data) {
console.log('<< From remote to proxy', data.toString());
socket.write(data);
console.log('>> From proxy to client', data.toString());
});
serviceSocket.on('error', function () {throw error;});
});
});
server.listen(LOCAL_PORT, LOCAL_ADDR, function () {
console.log('TCP server accepting connection on port: ' + LOCAL_ADDR + ':' + LOCAL_PORT);
});
Node.js Spawn NPM install dependecies
Файл install.js
var child_process = require('child_process')
, package = require('./package');
var dependencies = []
, preinstall;
if (package.hasOwnProperty('dependencies')) {
for (var key in package.dependencies) {
if (package.dependencies.hasOwnProperty(key)) {
dependencies.push(key + '@' + package.dependencies[key]);
}
}
}
if (package.hasOwnProperty('devDependencies')) {
for (var key in package.devDependencies) {
if (package.devDependencies.hasOwnProperty(key)) {
dependencies.push(key + '@' + package.devDependencies[key]);
}
}
}
if (package.hasOwnProperty('scripts') && package.scripts.hasOwnProperty('preinstall')) {
preinstall = package.scripts.preinstall;
if (preinstall.indexOf('npm i ') === 0) {
preinstall = preinstall.slice(6);
}
}
dependencies.sort();
installNextDependency(dependencies);
function installNextDependency (dependencies) {
var dependency = dependencies.pop()
, parameters;
if (typeof dependency === 'string') {
parameters = ['install', dependency];
} else if (typeof dependency === 'undefined' && typeof preinstall === 'string') {
parameters = ['install', preinstall];
preinstall = undefined;
} else {
console.log('The end. Dependencies array and scripts preinstall are empty.');
return;
}
var spawnProcess = child_process.spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', parameters, {stdio: 'inherit', shell: true});
spawnProcess.on('exit', function (code) {
if (code === 0) {
console.log('Dependency ' + parameters[1] + ' installed.');
installNextDependency(dependencies);
} else {
console.log('Error in dependency: ' + parameters[1] + '.');
console.log('Error. Exited with code: ' + code + '.');
}
});
spawnProcess.on('error', function (error) {
console.log('Error in dependency: ' + parameters[1] + '.');
throw error;
});
}
/*
// Test NPM
var child_process = require('child_process');
var spawnProcess = child_process.spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['--version'], {stdio: 'inherit', shell: true});
spawnProcess.on('exit', function (code) {
if (code === 0) {
console.log('Done');
} else {
console.log('Error. Exited with code: ' + code);
}
});
spawnProcess.on('error', function (error) {
throw error;
});
*/
var child_process = require('child_process')
, package = require('./package');
var dependencies = []
, preinstall;
if (package.hasOwnProperty('dependencies')) {
for (var key in package.dependencies) {
if (package.dependencies.hasOwnProperty(key)) {
dependencies.push(key + '@' + package.dependencies[key]);
}
}
}
if (package.hasOwnProperty('devDependencies')) {
for (var key in package.devDependencies) {
if (package.devDependencies.hasOwnProperty(key)) {
dependencies.push(key + '@' + package.devDependencies[key]);
}
}
}
if (package.hasOwnProperty('scripts') && package.scripts.hasOwnProperty('preinstall')) {
preinstall = package.scripts.preinstall;
if (preinstall.indexOf('npm i ') === 0) {
preinstall = preinstall.slice(6);
}
}
dependencies.sort();
installNextDependency(dependencies);
function installNextDependency (dependencies) {
var dependency = dependencies.pop()
, parameters;
if (typeof dependency === 'string') {
parameters = ['install', dependency];
} else if (typeof dependency === 'undefined' && typeof preinstall === 'string') {
parameters = ['install', preinstall];
preinstall = undefined;
} else {
console.log('The end. Dependencies array and scripts preinstall are empty.');
return;
}
var spawnProcess = child_process.spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', parameters, {stdio: 'inherit', shell: true});
spawnProcess.on('exit', function (code) {
if (code === 0) {
console.log('Dependency ' + parameters[1] + ' installed.');
installNextDependency(dependencies);
} else {
console.log('Error in dependency: ' + parameters[1] + '.');
console.log('Error. Exited with code: ' + code + '.');
}
});
spawnProcess.on('error', function (error) {
console.log('Error in dependency: ' + parameters[1] + '.');
throw error;
});
}
/*
// Test NPM
var child_process = require('child_process');
var spawnProcess = child_process.spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['--version'], {stdio: 'inherit', shell: true});
spawnProcess.on('exit', function (code) {
if (code === 0) {
console.log('Done');
} else {
console.log('Error. Exited with code: ' + code);
}
});
spawnProcess.on('error', function (error) {
throw error;
});
*/
пятница, 25 августа 2017 г.
Node.js Net Socket Client request
var net = require('net');
var options = {
host: 'google.com',
port: 80
}
var client = net.connect(options, function () {
console.log('client connected');
client.end(
'GET / HTTP/1.0\r\n' +
'Host: google.com\r\n' +
'\r\n'
);
});
client.on('data', function (chunk) {
console.log(chunk.toString());
});
client.on('end', function () {
console.log('client disconnected');
});
client.on('error', function (error) {
console.log(error);
});
client.on('timeout', function () {
console.log('Timeout');
});
var options = {
host: 'google.com',
port: 80
}
var client = net.connect(options, function () {
console.log('client connected');
client.end(
'GET / HTTP/1.0\r\n' +
'Host: google.com\r\n' +
'\r\n'
);
});
client.on('data', function (chunk) {
console.log(chunk.toString());
});
client.on('end', function () {
console.log('client disconnected');
});
client.on('error', function (error) {
console.log(error);
});
client.on('timeout', function () {
console.log('Timeout');
});
вторник, 22 августа 2017 г.
Net Socket Server and Net Socket Client
var net = require('net');
var HOST = '127.0.0.1';
var PORT = 6969;
// TCP Socket Server
// Create a server instance, and chain the listen function to it
// The function passed to net.createServer() becomes the event handler for the 'connection' event
// The sock object the callback function receives UNIQUE for each connection
var server = net.createServer();
server.on('connection', function(sock) {
// We have a connection - a socket object is assigned to the connection automatically
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
// Add a 'data' event handler to this instance of socket
sock.on('data', function(data) {
console.log('DATA ' + sock.remoteAddress + ': ' + data);
// Write the data back to the socket, the client will receive it as data from the server
sock.write('You said "' + data + '"');
});
// Add a 'close' event handler to this instance of socket
sock.on('close', function(data) {
console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
});
});
server.listen(PORT, HOST);
console.log('Server listening on ' + HOST +':'+ PORT);
// TCP Socket Client
var client = new net.Socket();
// Add a 'data' event handler for the client socket
// data is what the server sent to this socket
client.on('data', function(data) {
console.log('DATA: ' + data);
// Close the client socket completely
client.destroy();
});
// Add a 'close' event handler for the client socket
client.on('close', function() {
console.log('Connection closed');
});
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
// Write a message to the socket as soon as the client is connected, the server will receive it as message from the client
client.write('I am Chuck Norris!');
});
var HOST = '127.0.0.1';
var PORT = 6969;
// TCP Socket Server
// Create a server instance, and chain the listen function to it
// The function passed to net.createServer() becomes the event handler for the 'connection' event
// The sock object the callback function receives UNIQUE for each connection
var server = net.createServer();
server.on('connection', function(sock) {
// We have a connection - a socket object is assigned to the connection automatically
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
// Add a 'data' event handler to this instance of socket
sock.on('data', function(data) {
console.log('DATA ' + sock.remoteAddress + ': ' + data);
// Write the data back to the socket, the client will receive it as data from the server
sock.write('You said "' + data + '"');
});
// Add a 'close' event handler to this instance of socket
sock.on('close', function(data) {
console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
});
});
server.listen(PORT, HOST);
console.log('Server listening on ' + HOST +':'+ PORT);
// TCP Socket Client
var client = new net.Socket();
// Add a 'data' event handler for the client socket
// data is what the server sent to this socket
client.on('data', function(data) {
console.log('DATA: ' + data);
// Close the client socket completely
client.destroy();
});
// Add a 'close' event handler for the client socket
client.on('close', function() {
console.log('Connection closed');
});
client.connect(PORT, HOST, function() {
console.log('CONNECTED TO: ' + HOST + ':' + PORT);
// Write a message to the socket as soon as the client is connected, the server will receive it as message from the client
client.write('I am Chuck Norris!');
});
Простой Socket Server для Чата
Файл chatServer.js
// Load the TCP Library
var net = require('net');
// Keep track of the chat clients
var clients = [];
// Start a TCP Server
net.createServer(function (socket) {
// Identify this client
socket.name = socket.remoteAddress + ':' + socket.remotePort;
// Put this new client in the list
clients.push(socket);
// Send a nice welcome message and announce
socket.write('Welcome ' + socket.name + '\n');
broadcast(socket.name + ' joined the chat\n', socket);
// Handle incoming messages from clients.
socket.on('data', function (data) {
broadcast(socket.name + '> ' + data, socket);
});
// Remove the client from the list when it leaves
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast(socket.name + ' left the chat.\n');
});
// Send a message to all clients
function broadcast(message, sender) {
clients.forEach(function (client) {
// Don't want to send it to sender
if (client === sender) {return;}
client.write(message);
});
// Log it to the server output too
process.stdout.write(message)
}
}).listen(5000);
// Put a friendly message on the terminal of the server.
console.log('Chat server running at port 5000');
// Load the TCP Library
var net = require('net');
// Keep track of the chat clients
var clients = [];
// Start a TCP Server
net.createServer(function (socket) {
// Identify this client
socket.name = socket.remoteAddress + ':' + socket.remotePort;
// Put this new client in the list
clients.push(socket);
// Send a nice welcome message and announce
socket.write('Welcome ' + socket.name + '\n');
broadcast(socket.name + ' joined the chat\n', socket);
// Handle incoming messages from clients.
socket.on('data', function (data) {
broadcast(socket.name + '> ' + data, socket);
});
// Remove the client from the list when it leaves
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast(socket.name + ' left the chat.\n');
});
// Send a message to all clients
function broadcast(message, sender) {
clients.forEach(function (client) {
// Don't want to send it to sender
if (client === sender) {return;}
client.write(message);
});
// Log it to the server output too
process.stdout.write(message)
}
}).listen(5000);
// Put a friendly message on the terminal of the server.
console.log('Chat server running at port 5000');
Подписаться на:
Сообщения (Atom)
