PHP фред ssh поток значительно медленнее
Сценарий: мне нужна была функция, чтобы получить 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)
- Принимает URI SSH и возвращает дескриптор соединения SSH.bytes_to_human($bytes)
- Преобразует количество байтов в удобочитаемый формат (например, 6 ГБ)debugo($message)
- Такой же какdebug()
но перезаписывает последнюю строку.
Примечание 2: параметр $size_est
используется в индикаторе прогресса; обычно вы сначала получаете размер файла, а затем пытаетесь загрузить его (как в моем примере). Это необязательно, поэтому его можно игнорировать, когда вы просто хотите запустить команду SSH.
Проблема: запуск той же операции загрузки через scp root@host:/bigfile.zip ./
Я получаю скорость до 1 Мбит / с, тогда как этот сценарий, кажется, ограничивается до 70 Кбит / с. Я хотел бы знать, почему и как это улучшить.
Изменить: Кроме того, я хотел бы знать, как / если $BUFFER_SIZE
делает любую разницу.
1 ответ
Вы должны быть в состоянии использовать phpseclib, чистую реализацию PHP SSH, чтобы сделать это. например.
$ssh->exec('cat bigfile.zip', false);
while (true) {
$temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
if (is_bool($temp)) {
break;
}
echo $temp;
}