0

シナリオ:STDOUT SSH を介して非同期で実行されるコマンドを取得する関数が必要でした。これには、SSH を介したファイルの読み取り (そして最も重要なこと) など、さまざまな用途があります。この関数の重要な機能は非同期であるため、サーバーから返された出力を表示できます (または、ファイルのダウンロードの進行状況を推定できます)。ssh_move()これは、 を使用してファイルをダウンロードする一般的なアプローチとは異なります。

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:pass@host/';
$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 root@host:/bigfile.zip ./、最大 1 mb/s の速度が得られますが、このスクリプトは 70 kb/s に制限されているようです。原因と改善方法を教えていただきたいです。

編集:$BUFFER_SIZEまた、どのように/もし違いがあるか知りたいです。

4

1 に答える 1