2013-05-02 93 views
0

場景:我需要一個函數來獲取通過SSH異步運行的命令的STDOUT。這有很多用途,包括(最重要的)通過SSH讀取文件。 這個函數的一個重要特性是它是異步的,因此我可以顯示從服務器返回的輸出(或者估算文件下載進度)。這與使用ssh_move()下載文件的常見方法不同。PHP fread ssh流顯着慢

function ssh_exec($dsn, $cmd, $return=true, $size_est=null){ 
    $BUFFER_SIZE = $return ? (1024 * 1024) : 1; 
    debug('ssh2_exec '.$cmd); 
    $stream = ssh2_exec(ssh_open($dsn), $cmd); 
    debug('stream_set_blocking'); 
    stream_set_blocking($stream, true); 
    debug('ssh2_fetch_stream'); 
    $stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO); 
    stream_set_blocking($stream_out, true); 
    debug('stream_get_contents'); 
    $data = ''; $stime = $oldtime = microtime(true); $data_len = 0; 
    if(!$return){ 
     write_message("\033[0m".' Execution Output:'.PHP_EOL.' '); 
    } 
    while(!feof($stream_out)){ 
     $buff = fread($stream_out, $BUFFER_SIZE); 
     if($buff===false)throw new Exception('Unexpected result from fread().'); 
     if($buff===''){ 
      debug('Empty result from fread()...breaking.'); 
      break; 
     } 
     $data .= $buff; 
     if($return){ 
      $buff_len = strlen($buff); 
      $data_len += $buff_len; 
      $newtime = microtime(true); 
      debugo('stream_get_contents '.bytes_to_human($data_len) 
       .' @ '.bytes_to_human($buff_len/($newtime - $oldtime)).'/s' 
       .' ['.($size_est ? number_format($data_len/$size_est * 100, 2) : '???').'%]'); 
      $oldtime = $newtime; 
     }else{ 
      echo str_replace(PHP_EOL, PHP_EOL.' ', $buff); 
     } 
    } 
    if($return){ 
     debugo('stream_get_contents Transferred '.bytes_to_human(strlen($data)).' in '.number_format(microtime(true) - $stime, 2).'s'); 
     return $data; 
    } 
} 

用途:該功能用於像這樣:

$dsn = 'ssh2.exec://root:[email protected]/'; 
$size = ssh_size($dsn, 'bigfile.zip'); 
$zip = ssh_exec($dsn, 'cat bigfile.zip', true, $size); 

注1:的一些非標準的功能的說明:

  • debug($message) - 寫入調試消息控制檯。
  • ssh_open($dsn) - 接收SSH URI並返回SSH連接句柄。
  • bytes_to_human($bytes) - 字節到人類可讀的格式的數字轉換(例如:6GB)
  • debugo($message) - 同爲debug()但重寫最後一行。

注2:參數$size_est在進度指示器被使用;通常你首先得到文件大小,然後嘗試下載它(如我的例子)。它是可選的,因此當您只想運行SSH命令時可以忽略它。

問題:通過scp [email protected]:/bigfile.zip ./運行相同的下載操作時,我得到速度可達1Mb/s的,而這個劇本似乎限制在70KB/S。我想知道爲什麼以及如何改善這一點。

編輯:此外,我想知道如何/如果$BUFFER_SIZE有任何區別。

回答