1. 程式人生 > >[朝花夕拾]關於nodejs中child_process之中spawn和exec的區別

[朝花夕拾]關於nodejs中child_process之中spawn和exec的區別

近日整理以前的node專案時發現一個檔案同時聲明瞭spawn和exec兩種方法。最後只是用了spawn方法,所以查了一下這兩者的區別。

Nodejs基於事件驅動來處理併發,本身是單執行緒模式執行的。Nodejs通過使用child_process模組來生成多個子程序來處理其他事物。主要包括4個非同步程序函式(spawn,exec,execFile,fork)和3個同步程序函式(spawnSync,execFileSync,execSync)。以非同步函式中spawn是最基本的建立子程序的函式,其他三個非同步函式都是對spawn不同程度的封裝。spawn只能執行指定的程式,引數需要在列表中給出,而exec可以直接運行復雜的命令。

比如要執行 du -sh /disk1 命令, 使用spawn函式需要寫成spawn(‘du‘, [‘-sh ‘, ‘/disk1’]),而使用exec函式時,可以直接寫成exec(‘du -sh /disk1’)。exec是會先進行Shell語法解析,因此用exec函式可以更方便的使用複雜的Shell命令,包括管道、重定向等。

一,var exec =require('child_process').exec;

exec在子程序輸出結果將放入buffer中,在結果返回完全之後,再將輸出一次性地以回撥函式引數的形式返回。如果exec的buffer體積設定的不夠大,它將會以一個“maxBuffer exceeded”錯誤失敗告終。另外,exec函式是對spawn的一種友好封裝,增加Shell命令解析,可以直接嵌入複雜的命令

a)        語法:child_process.exec(command[, options], callback)

b)        例項:

// 使用wget下載檔案的函式

vardownload_file_wget = function(file_url) {

  // 提取檔名

  var file_name =url.parse(file_url).pathname.split('/').pop();

  // 組合wget命令

  var wget = 'wget -P ' + DOWNLOAD_DIR + ' ' +file_url;

  // 使用exec執行wget命令

  var child = exec(wget, function(err, stdout,stderr) {

    if (err) throw err;

    else console.log(file_name + ' downloadedto ' + DOWNLOAD_DIR);

  });

};

//執行cat統計檔案

varchildProcess = require('child_process');

var ls =childProcess.exec('cat *.js | wc', function (error, stdout, stderr) {

   if (error) {

     console.log(error.stack);

     console.log('Error code: '+error.code);

   }

   console.log('Child Process STDOUT:'+stdout);

});

二,var spawn =require('child_process').spawn;

spawn在子執行緒開始執行後,就開始不斷將資料從子程序返回給主程序。從語法中我們可以發現與exec的一個區別是spawn是不支援callback函式的,它通過流的方式發資料傳給主程序,從而實現了多程序之間的資料交換。這個功能的直接用應用場景就是“系統監控”。在Linux下,我們有很多命令列工具,可以實時監控CPU,記憶體,IO,網路等資料,那麼用Node的child_process模組可以很容易地把這些資料採集的我們自己的應用中。

a)        語法:child_process.spawn(command[, args][, options])

b)        例項:

//這個例項就是所做的專案中nodejs實現堡壘機中生成子執行緒遠端登入的方法

Var worker = spawn('telnet', ['202.198.0.123']);

            client.telnet = worker.stdin;

            worker.on('close', function (code){

                client.fileWriteStream.end();

                //client.status = 2;

                client.socket.write('\n\r');

               client.socket.write('[Common]');

               client.socket.write('[INFO] :Connection to Device has closed!\n\r');

                closeSocket(client.socket,client);

                                      client.socket.destroy();

            });

            worker.stdout.on('data', function(data) {

                data = data.toString();

                if(client.status == 3){

                    return;

                }

                if((data.indexOf('nmslogin')>=0)&&(client.isLogin==0)){

                    client.secret = 1;

                    client.telnet.write('username\n');

                }elseif((data.indexOf('Password')>=0)&&(client.isLogin==0)){

                    client.telnet.write('password\n');

                    client.isLogin = 1;

                }elseif(data.indexOf('Password')>=0&& client.status == 4){

                     client.notChange= 1;

                     client.fileWriteStream.write(data);

                    client.socket.write(data);

                    client.datas =client.datas+data.toString();

                            }else {

                    client.fileWriteStream.write(data);

                    client.socket.write(data);

                    client.datas =client.datas+data.toString();

                }

            });

            worker.on('error',function(error){

                client.fileWriteStream.end();

                client.status = 2;

               client.socket.write('[ERR2]  :Anerror occured!')

               client.socket.write('[INFO] :Connection to Device has closed!\n\r');

               //client.socket.write('>>>>Input Device IP:');

                closeSocket(client.socket,client);

            });

擴充套件閱讀:

JavaScript 執行機制詳解:再談Event Loop

Node.js軟肋之回撥大坑

Node.js的執行緒和程序

Linux下同步模式、非同步模式、阻塞呼叫、非阻塞呼叫總結