?
このドキュメントでは、 php中國語ネットマニュアル リリース
穩(wěn)定性: 3 - 穩(wěn)定
Node 通過 child_process
模塊提供了 popen(3)
數(shù)據(jù)流。
它能在非阻塞的方式中,通過 stdin
, stdout
, 和 stderr
傳遞數(shù)據(jù)。 (請注意,某些程序使用內(nèi)部線性緩沖 I/O, 它并不妨礙 node.js,只是你發(fā)送給子進程的數(shù)據(jù)不會被立即消。)
使用 require('child_process').spawn()
或 require('child_process').fork()
創(chuàng)建一個子進程。這兩種方法有區(qū)別,底下會解釋 below.
開發(fā)過程中查看synchronous counterparts 效率會更高。
ChildProcess
是一個 EventEmitter。
子進程有三個相關(guān)的流 child.stdin
,child.stdout
, 和 child.stderr
。他們可能和會父進程的 stdio
streams 共享, 也可作為獨立的對象。
不能直接調(diào)用 ChildProcess 類,使用spawn()
, exec()
, execFile()
, 或 fork()
方法來創(chuàng)建子進程的實例。
err
{Error Object} 錯誤。
發(fā)生于:
無法創(chuàng)建進程。
無法殺死進程。
無論什么原因?qū)е陆o子進程發(fā)送消息失敗。
注意,exit
事件有可能在錯誤發(fā)生后調(diào)用,也可能不調(diào)用,所以如果你監(jiān)聽這兩個事件來觸發(fā)函數(shù),記得預防函數(shù)會被調(diào)用2次。
參考 ChildProcess#kill()
和ChildProcess#send()
。
code
{Number} 退出代碼, 正常退出時才有效。
signal
{String} 如果是被父進程殺死,則它為傳遞給子進程的信號
子進程結(jié)束的時候觸發(fā)這個事件。如果子進程正常終止,則 code
為最終的退出代碼,否則為 null
。如果是由 signal
引起的終止,則 signal
為字符串,否則為 null
。
注意,子進程的 stdio 流可能仍為開啟模式。
注意,node 為 'SIGINT'
和 'SIGTERM
' 建立句柄,所以當信號來臨的時候,他們不會終止而是退出。
參見 waitpid(2)
。
code
{Number} 退出代碼, 正常退出時才有效。
signal
{String} 如果是被父進程殺死,則它為傳遞給子進程的信號。
子進程里所有 stdio 流都關(guān)閉時觸發(fā)這個事件。要和 'exit' 區(qū)分開, 因為多進程可以共享一個 stdio 流。
父進程或子進程中調(diào)用.disconnect()
方法后觸發(fā)這個事件。 斷開后不會在互發(fā)消息,并且 .connected
屬性值為 false。
message
{Object} 一個解析過的 JSON 對象,或者一個原始值
sendHandle
{Handle object} 一個 Socket 或 Server 對象
通過 .send(message, [sendHandle])
傳遞消息。
{Stream object}
子進程的 stdin
是 Writable Stream
(可寫流)。
如果子進程在等待輸入,它就會暫停直到通過調(diào)用 end()
來關(guān)閉。
child.stdin
是 child.stdio[0]
的縮寫。這兩個都指向同一個對象,或者 null。
{Stream object}
子進程的 stdout
是 Readable Stream
(可讀流)。
child.stdout
是 child.stdio[1]
的縮寫。 這兩個都指向同一個對象,或者 null。
{Stream object}
子進程的 stderr
是 Readable Stream
(可寫流)。
child.stderr
是 child.stdio[2]
縮寫。 這兩個都指向同一個對象,或者 null。
{Array}
子進程的管道數(shù)組和 spawn 的 stdio 里設(shè)置為 'pipe'
的內(nèi)容次序相對應。
注意,流[0-2]也能分別用 ChildProcess.stdin,ChildProcess.stdout, 和 ChildProcess.stderrNote 來表示。
在下面的例子里,只有子進程的 fd 1
設(shè)置為 pipe管道,所以父進程的 child.stdio[1]
是流(stream), 數(shù)組里其他值為null
。
child = child_process.spawn("ls", { stdio: [ 0, // use parents stdin for child 'pipe', // pipe child's stdout to parent fs.openSync("err.out", "w") // direct child's stderr to a file ] }); assert.equal(child.stdio[0], null); assert.equal(child.stdio[0], child.stdin); assert(child.stdout); assert.equal(child.stdio[1], child.stdout); assert.equal(child.stdio[2], null); assert.equal(child.stdio[2], child.stderr);
{Integer}
子進程的 PID。
例子:
var spawn = require('child_process').spawn, grep = spawn('grep', ['ssh']); console.log('Spawned child pid: ' + grep.pid); grep.stdin.end();
{Boolean} 調(diào)用 `.disconnect' 后設(shè)置為 false
如果 .connected
為 false, 消息不再可用。
signal
{String}
發(fā)送信號給子進程。如果沒有參數(shù),會發(fā)送 'SIGTERM'
,參見 signal(7)
里的可用的信號列表。
var spawn = require('child_process').spawn, grep = spawn('grep', ['ssh']); grep.on('close', function (code, signal) { console.log('child process terminated due to receipt of signal '+signal); }); // send SIGHUP to process grep.kill('SIGHUP');
當信號無法傳遞的時候會觸發(fā) 'error'
事件。給已經(jīng)終止的進程發(fā)送信號不會觸發(fā) 'error'
事件,但是可以能引起不可預知的后果: 因為有可能 PID (進程 ID) 已經(jīng)重新分配給其他進程, 信號就會被發(fā)送到新的進程里,無法想象這樣會引發(fā)什么樣的事情。
注意,當函數(shù)調(diào)用 kill
信號的時候,它實際并并不會殺死進程,只是發(fā)送信號給進程。
參見 kill(2)
message
{Object}
sendHandle
{Handle object}
使用 child_process.fork()
的時候,你能用 child.send(message, [sendHandle])
給子進程寫數(shù)據(jù),子進程通過 'message'
接收消息。
例如:
var cp = require('child_process'); var n = cp.fork(__dirname + '/sub.js'); n.on('message', function(m) { console.log('PARENT got message:', m); }); n.send({ hello: 'world' });
子進程的代碼 'sub.js'
:
process.on('message', function(m) { console.log('CHILD got message:', m); }); process.send({ foo: 'bar' });
子進程代碼里的 process
對象擁有 send()
方法,當它通過信道接收到信息時會觸發(fā),并返回對象。
注意,父進程和子進程 send()
是同步的,不要用來發(fā)送大塊的數(shù)據(jù)(可以用管道來代替,參見child_process.spawn
)。
不過發(fā)送 {cmd: 'NODE_foo'}
消息是特殊情況。所有包含 NODE_
前綴的消息都不會被觸發(fā),因為它們是 node 的內(nèi)部的核心消息,它們會在 internalMessage
事件里觸發(fā),盡量避免使用這個特性。
child.send()
里的 sendHandle
屬性用來發(fā)送 TCP 服務(wù)或 socket 對象給其他的進程,子進程會用接收到的對象作為 message
事件的第二個參數(shù)。
如果不能發(fā)出消息會觸發(fā) 'error'
事件,比如子進程已經(jīng)退出。
以下是例子:
var child = require('child_process').fork('child.js'); // Open up the server object and send the handle. var server = require('net').createServer(); server.on('connection', function (socket) { socket.end('handled by parent'); }); server.listen(1337, function() { child.send('server', server); });
子進程將會收到這個 server 對象:
process.on('message', function(m, server) { if (m === 'server') { server.on('connection', function (socket) { socket.end('handled by child'); }); } });
注意,現(xiàn)在父子進程共享了server,某些連接會被父進程處理,某些會被子進程處理。
dgram
服務(wù)器,工作流程是一樣的,監(jiān)聽的是 message
事件,而不是 connection
,使用 server.bind
而不是 server.listen
。(目前僅支持 UNIX 平臺)
以下是發(fā)送 socket 對象的例子。 他將會創(chuàng)建 2 個子線程,并且同時處理連接,一個將遠程地址 74.125.127.100
當做 VIP 發(fā)送到一個特殊的子進程,另外一個發(fā)送到正常進程。
var normal = require('child_process').fork('child.js', ['normal']);
var special = require('child_process').fork('child.js', ['special']);
// Open up the server and send sockets to child var server = require('net').createServer(); server.on('connection', function (socket) { // if this is a VIP if (socket.remoteAddress === '74.125.127.100') { special.send('socket', socket); return; } // just the usual dudes normal.send('socket', socket); }); server.listen(1337);
child.js
代碼如下:
process.on('message', function(m, socket) { if (m === 'socket') { socket.end('You were handled as a ' + process.argv[2] + ' person'); } });
注意,當 socket 發(fā)送給子進程后,如果這個 socket 被銷毀,父進程不再跟蹤它,相應的 .connections
屬性會變?yōu)?null
。這種情況下,不建議使用 .maxConnections
。
關(guān)閉父子進程間的所有 IPC 通道,能讓子進程優(yōu)雅的退出。調(diào)用這個方法后,父子進程里的.connected
標志會變?yōu)?false
,之后不能再發(fā)送消息。
當進程里沒有消息需要處理的時候,會觸發(fā) 'disconnect' 事件。
注意,在子進程還有 IPC 通道的情況下(如 fork()
),也可以調(diào)用 process.disconnect()
來關(guān)閉它。
這些方法遵從常用的異步處理模式(比如回調(diào),或者返回一個事件處理)。
command
{String} 要運行的命令
args
{Array} 字符串參數(shù)表
options
{Object}
cwd
{String} 子進程的工作目錄
env
{Object} 環(huán)境
stdio
{Array|String} 子進程的 stdio 配置。 (見below)
customFds
{Array} Deprecated 作為子進程 stdio 使用的 文件標示符。(見 below)
detached
{Boolean} 子進程將會變成一個進程組的領(lǐng)導者。(參見below)
uid
{Number} 設(shè)置用戶進程的ID。 (參見 setuid(2))
gid
{Number} 設(shè)置進程組的ID。 (參見 setgid(2))
返回: {ChildProcess object}
用指定的 command
發(fā)布一個子進程, args
是命令行參數(shù)。如果忽略, args
是空數(shù)組。
第三個參數(shù)用來指定附加設(shè)置,默認值:
{ cwd: undefined, env: process.env }
創(chuàng)建的子進程里使用 cwd
指定工作目錄,如果沒有指定,默認繼承自當前的工作目錄。
使用 env
來指定新進程可見的環(huán)境變量。默認是 process.env
。
例如,運行 ls -lh /usr
, 獲取 stdout
, stderr
, 和退出代碼:
var spawn = require('child_process').spawn, ls = spawn('ls', ['-lh', '/usr']); ls.stdout.on('data', function (data) { console.log('stdout: ' + data); }); ls.stderr.on('data', function (data) { console.log('stderr: ' + data); }); ls.on('close', function (code) { console.log('child process exited with code ' + code); });
例如: 一個非常精巧的方法執(zhí)行 'ps ax | grep ssh'
var spawn = require('child_process').spawn, ps = spawn('ps', ['ax']), grep = spawn('grep', ['ssh']); ps.stdout.on('data', function (data) { grep.stdin.write(data); }); ps.stderr.on('data', function (data) { console.log('ps stderr: ' + data); }); ps.on('close', function (code) { if (code !== 0) { console.log('ps process exited with code ' + code); } grep.stdin.end(); }); grep.stdout.on('data', function (data) { console.log('' + data); }); grep.stderr.on('data', function (data) { console.log('grep stderr: ' + data); }); grep.on('close', function (code) { if (code !== 0) { console.log('grep process exited with code ' + code); } });
stdio
可能是以下幾個參數(shù)之一:
'pipe'
- ['pipe', 'pipe', 'pipe']
, 默認值
'ignore'
- ['ignore', 'ignore', 'ignore']
'inherit'
- [process.stdin, process.stdout, process.stderr]
或 [0,1,2]
child_process.spawn()
里的 'stdio' 參數(shù)是一個數(shù)組,它和子進程的 fd 相對應,它的值如下:
'pipe'
- 創(chuàng)建在父進程和子進程間的 pipe。管道的父進程端以 child_process
的屬性形式暴露給父進程,例如 ChildProcess.stdio[fd]
。為 fds 0 - 2 創(chuàng)建的管道也可以通過 ChildProcess.stdin, ChildProcess.stdout 和 ChildProcess.stderr 來獨立的訪問。
'ipc'
- 在父進程和子進程間創(chuàng)建一個 IPC 通道來傳遞消息/文件描述符。 一個子進程最多有1個 IPC stdio 文件標識。設(shè)置這個選項會激活 ChildProcess.send() 方法。如果子進程向此文件標識寫入 JSON 消息,則會觸發(fā) ChildProcess.on('message') 。如果子進程是 Node.js 程序,那么 IPC 通道會激活 process.send() 和 process.on('message')。
'ignore'
- 在子進程里不要設(shè)置這個文件標識,注意,Node 總會為其 spawn 的進程打開 fd 0-2。如果任何一個被 ignored,node 將會打開 /dev/null
并賦給子進程的 fd。
Stream
對象 - 共享一個tty, file, socket, 或刷(pipe)可讀或可寫流給子進程。該流底層(underlying)的文件標識在子進程中被復制給stdio數(shù)組索引對應的文件標識(fd)。
正數(shù) - 這個整數(shù)被理解為一個在父進程中打開的文件標識,它和子進程共享,就和共享 Stream
對象類似。
null
, undefined
- 使用默認值。 對于 stdio fds 0, 1 and 2 (換句話說, stdin, stdout, and stderr) ,pipe管道被建立。 對于 fd 3 及之后, 默認是 'ignore'
。
例如:
var spawn = require('child_process').spawn; // Child will use parent's stdios spawn('prg', [], { stdio: 'inherit' }); // Spawn child sharing only stderr spawn('prg', [], { stdio: ['pipe', 'pipe', process.stderr] }); // Open an extra fd=4, to interact with programs present a // startd-style interface. spawn('prg', [], { stdio: ['pipe', null, null, null, 'pipe'] });
如果設(shè)置了 detached
選項, 子進程將會被作為新進程組的leader,這使得子進程可以在父進程退出后繼續(xù)運行。
缺省情況下父進程會等 detached 的子進程退出。要阻止父進程等待一個這樣的子進程,調(diào)用 child.unref() 方法,則父進程的事件循環(huán)引用計數(shù)中將不會包含這個子進程。
detaching 一個長期運行的進程,并重新將輸出指向文件:
var fs = require('fs'), spawn = require('child_process').spawn, out = fs.openSync('./out.log', 'a'), err = fs.openSync('./out.log', 'a'); var child = spawn('prg', [], { detached: true, stdio: [ 'ignore', out, err ] }); child.unref();
使用 detached
選項來啟動一個長時間運行的進程時,進程不會在后臺保持運行,除非他提供了一個不連接到父進程的stdio
。如果繼承了父進程的 stdio
,則子進程會繼續(xù)控制終端。
已廢棄, customFds
允許指定特定文件描述符作為子進程的 stdio
。該 API 無法移植到所有平臺,因此被廢棄。使用 customFds
可以將新進程的 [stdin
, stdout
, stderr
] 鉤到已有流上;-1 表示創(chuàng)建新流。自己承擔使用風險。
參見: child_process.exec()
and child_process.fork()
command
{String} 要執(zhí)行的命令,空格分割
options
{Object}
cwd
{String} 子進程的當前工作目錄
env
{Object} 環(huán)境變量
encoding
{String} (默認: 'utf8')
shell
{String} 運行命令的 shell
(默認: '/bin/sh' UNIX, 'cmd.exe' Windows, 該 shell 必須接收 UNIX上的 -c
開關(guān) ,或者 Windows上的/s /c
開關(guān) 。Windows 上,命令解析必須兼容 cmd.exe
。)
timeout
{Number} (默認: 0)
maxBuffer
{Number} (默認: 200*1024
)
killSignal
{String} (默認: 'SIGTERM')
uid
{Number} 設(shè)置進程里的用戶標識。 (見 setuid(2)。)
gid
{Number} 設(shè)置進程里的群組標識。(見 setgid(2)。)
callback
{Function} 進程終止的時候調(diào)用
error
{Error}
stdout
{Buffer}
stderr
{Buffer}
返回: ChildProcess 對象
在 shell 里執(zhí)行命令,并緩沖輸出。
var exec = require('child_process').exec, child; child = exec('cat *.js bad_file | wc -l', function (error, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (error !== null) { console.log('exec error: ' + error); } });
回調(diào)參數(shù)是 (error, stdout, stderr)
。 如果成功 , error
值為 null
。 如果失敗, error
變?yōu)?Error
的實例, error.code
等于子進程退出碼, 并且 error.signal
會被設(shè)置為結(jié)束進程的信號名。
第二個參數(shù)可以設(shè)置一些選項。 缺省是:
{ encoding: 'utf8', timeout: 0, maxBuffer: 200*1024, killSignal: 'SIGTERM', cwd: null, env: null }
如果 timeout
大于 0, 子進程運行時間超過 timeout
時會被終止。 killSignal
(默認: 'SIGTERM'
) 能殺死子進程。 maxBuffer
設(shè)定了 stdout 或 stderr 的最大數(shù)據(jù)量,如果子進程的數(shù)量量超過了,將會被殺死。
file
{String} 要運行的程序的文件名
args
{Array} 參數(shù)列表
options
{Object}
cwd
{String} 子進程的工作目錄
env
{Object} 環(huán)境
encoding
{String} (默認: 'utf8')
timeout
{Number} (默認: 0)
maxBuffer
{Number} (默認: 200*1024)
killSignal
{String} (默認: 'SIGTERM')
uid
{Number} 設(shè)置進程里的用戶標識。 (見 setuid(2)。)
gid
{Number} 設(shè)置進程里的群組標識。(見 setgid(2)。)
callback
{Function} 進程終止的時候調(diào)用
error
{Error}
stdout
{Buffer}
stderr
{Buffer}
返回: ChildProcess 對象
和 child_process.exec()
類似,不同之處在于這是執(zhí)行一個指定的文件,因此它比child_process.exec
精簡些,參數(shù)相同。
modulePath
{String} 子進程里運行的模塊
args
{Array} 參數(shù)列表
options
{Object}
cwd
{String} 子進程的工作目錄
env
{Object} 環(huán)境
execPath
{String} 執(zhí)行文件路徑
execArgv
{Array} 執(zhí)行參數(shù)
(默認: process.execArgv
)
silent
{Boolean} 如果是 true ,子進程將會用父進程的 stdin, stdout, and stderr ,否則,將會繼承自父進程, 更多細節(jié),參見 spawn()
的 stdio
參數(shù)里的 "pipe" 和 "inherit" 選項(默認 false)
uid
{Number} 設(shè)置進程里的用戶標識。 (見 setuid(2)。)
gid
{Number} 設(shè)置進程里的群組標識。 (見 setgid(2)。)
返回: ChildProcess 對象
這是 spawn()
的特殊例子,用于派生 Node 進程。除了擁有子進程的所有方法,它的返回對象還擁有內(nèi)置通訊通道。參見 child.send(message, [sendHandle])
。
這些 Nodes 是全新的 V8 實例化,假設(shè)每個 Node 最少需要 30ms 的啟動時間,10mb 的存儲空間,可想而知,創(chuàng)建幾千個 Node 是不太現(xiàn)實的。
options
對象中的 execPath
屬性可以用于執(zhí)行文件(非當前 node
)創(chuàng)建子進程。這需要小心使用,缺省情況下 fd 表示子進程的 NODE_CHANNEL_FD
環(huán)境變量。該 fa 的輸入和輸出是以行分割的 JSON 對象。
以下這些方法是同步的,意味著他會阻塞事件循環(huán),并暫停執(zhí)行代碼,直到 spawned 的進程退出。
同步方法簡化了任務(wù)進程,比如大為簡化在應用初始化加載/處理過程。
command
{String} 要執(zhí)行的命令
args
{Array} 參數(shù)列表
options
{Object}
cwd
{String} 子進程的當前工作目錄
input
{String|Buffer} 傳遞給spawned 進程的值,這個值將會重寫 stdio[0]
stdio
{Array} 子進程的 stdio 配置。
env
{Object} 環(huán)境變量
uid
{Number} 設(shè)置用戶進程的ID。 (參見 setuid(2)。)
gid
{Number} 設(shè)置進程組的ID。 (參見 setgid(2)。)
timeout
{Number} 子進程運行最大毫秒數(shù)。 (默認: undefined)
killSignal
{String} 用來終止子進程的信號。 (默認: 'SIGTERM')
maxBuffer
{Number}
encoding
{String} stdio 輸入和輸出的編碼方式。 (默認: 'buffer')
返回: {Object}
pid
{Number} 子進程的 pid
output
{Array} stdio 輸出的結(jié)果數(shù)組
stdout
{Buffer|String} output[1]
的內(nèi)容
stderr
{Buffer|String} output[2]
的內(nèi)容
status
{Number} 子進程的退出代碼
signal
{String} 用來殺死子進程的信號
error
{Error} 子進程錯誤或超時的錯誤代碼
spawnSync
直到子進程關(guān)閉才會返回。超時或者收到 killSignal
信號,也不會返回,直到進程完全退出。進程處理完 SIGTERM
信號后并不會結(jié)束,直到子進程完全退出。
command
{String} 要執(zhí)行的命令
args
{Array} 參數(shù)列表
options
{Object}
stderr
默認情況下會輸出給父進程的' stderr 除非指定了 stdio
cwd
{String} 子進程的當前工作目錄
input
{String|Buffer}傳遞給spawned 進程的值,這個值將會重寫 stdio[0]
stdio
{Array}子進程的 stdio 配置。 (默認: 'pipe')
env
{Object} 環(huán)境變量
uid
{Number} 設(shè)置用戶進程的ID。 (參見 setuid(2)。)
gid
{Number} 設(shè)置進程組的ID。 (參見 setgid(2)。)
timeout
{Number} 進程運行最大毫秒數(shù)。 (默認: undefined)
killSignal
{String} 用來終止子進程的信號。 (默認: 'SIGTERM')
maxBuffer
{Number}
encoding
{String} stdio 輸入和輸出的編碼方式。 (默認: 'buffer')
返回: {Buffer|String} 來自命令的 stdout
直到子進程完全退出,execFileSync
才會返回。超時或者收到 killSignal
信號,也不會返回,直到進程完全退出。進程處理完 SIGTERM
信號后并不會結(jié)束,直到子進程完全退出。
如果進程超時,或者非正常退出,這個方法將會拋出異常。Error
會包含整個 child_process.spawnSync
結(jié)果。
command
{String} 要執(zhí)行的命令
options
{Object}
stderr
默認情況下會輸出給父進程的' stderr 除非指定了 stdio
cwd
{String} 子進程的當前工作目錄
input
{String|Buffer} 傳遞給spawned 進程的值,這個值將會重寫 stdio[0]
stdio
{Array} 子進程的 stdio 配置。 (默認: 'pipe')
env
{Object} 環(huán)境變量
uid
{Number} 設(shè)置用戶進程的ID。 (參見 setuid(2)。)
gid
{Number} 設(shè)置進程組的ID。 (參見 setgid(2)。)
timeout
{Number} 進程運行最大毫秒數(shù)。 (默認: undefined)
killSignal
{String} 用來終止子進程的信號。 (默認: 'SIGTERM')
maxBuffer
{Number}
encoding
{String} stdio 輸入和輸出的編碼方式。 (默認: 'buffer')
返回: {Buffer|String} 來自命令的 stdout
直到子進程完全退出,execSync
才會返回。超時或者收到 killSignal
信號,也不會返回,直到進程完全退出。進程處理完 SIGTERM
信號后并不會結(jié)束,直到子進程完全退出。
如果進程超時,或者非正常退出,這個方法將會拋出異常。Error
會包含整個child_process.spawnSync
結(jié)果。