Отправитель и получатель для передачи файлов по ssh по запросу?
Я создал программу, которая перебирает кучу файлов и вызывает для некоторых из них:
scp <file> user@host:<remotefile>
Однако в моем случае могут существовать тысячи небольших файлов, которые необходимо перенести, и scp открывает новое ssh-соединение для каждого из них, что имеет довольно большие накладные расходы.
Мне было интересно, нет ли решения, где я держу один запущенный процесс, который поддерживает соединение, и я могу отправлять ему "запросы" на копирование по отдельным файлам.
В идеале, я ищу комбинация некоторой программы отправителя и получателя, так что я могу запустить один процесс (1) в начале:
ssh user@host receiverprogram
И для каждого файла я вызываю команду (2):
senderprogram <file> <remotefile>
И соедините выходные данные (2) с входными данными (1), и это приведет к передаче файла. В конце концов, я могу просто послать процессу (1)некоторый сигнал для завершения.
Предпочтительно, чтобы отправитель и получатель были программами с открытым исходным кодом для Unix. Они могут общаться, используя сокет вместо труба, или любое другое творческое решение.
Однако, это важное ограничение, что каждый файл передается в момент, когда я повторяю его: недопустимо собирать список файлов, а затем вызывать один экземпляр scp
, чтобы передать все файлы сразу в конце. Кроме того, у меня есть только простой доступ оболочки к принимающему хосту.
Update: я нашел решение проблемы накладных расходов на подключение, используя мультиплексирующие функции ssh, см. Мой собственный ответ ниже. Тем не менее, я начинаю щедрость, потому что мне любопытно узнать, существует ли программа отправителя/получателя, как я описываю здесь. Кажется, должно существовать что-то, что можно использовать, например xmodem/ymodem/zmodem?
14 ответов:
Этот способ будет работать, и для других вещей этот общий подход более или менее прав.
( iterate over file list for each matching file echo filename ) | cpio -H newc -o | ssh remotehost cd location \&\& | cpio -H newc -imud
Я нашел решение с другой стороны. Начиная с версии 3.9 , OpenSSH поддерживает мультиплексирование сеансов: одно соединение может выполнять несколько сеансов входа в систему или передачи файлов. Это позволяет избежать затрат на установку одного соединения.
В случае вопроса я могу сначала открыть соединение с настройками мастера управления (
-M
) с сокетом (-S
) в определенном месте. Мне не нужен сеанс (-N
).ssh user@host -M -S /tmp/%r@%h:%p -N
Далее, я могу вызвать
scp
для каждого файла и проинструктируйте его использовать тот же сокет:scp -o 'ControlPath /tmp/%r@%h:%p' <file> user@host:<remotefile>
Эта команда начинает копирование почти мгновенно!
Вы также можете использовать управляющий сокет для обычных ssh-соединений, которые затем немедленно откроются:
ssh user@host -S /tmp/%r@%h:%p
Если управляющий сокет больше не доступен (например, потому, что вы убили мастера), это возвращается к обычному соединению. Более подробная информация доступна в этой статье.
Можно использовать sftp вместо scp и перевести его в пакетный режим. Сделайте командный файл пакета каналом или доменным сокетом UNIX и подавайте в него команды по мере их выполнения.
Безопасность в этом случае может быть немного сложнее на клиентском конце.
Вы пробовали
sshfs
? Вы могли бы:sshfs remote_user@remote_host:/remote_dir /mnt/local_dir
Где
/remote_dir
был каталог, в который вы хотите отправить файлы в системе, в которую вы входите/mnt/local_dir
было локальное расположение горыС помощью этой настройки вы можете просто
cp
файл вlocal_dir
, и он будет отправлен поsftp
вremote_host
в егоremote_dir
Обратите внимание, что существует одно соединение, поэтому существует мало на пути накладных расходов
Возможно, вам потребуется использовать флаг
-o ServerAliveInterval=15
для поддержания неопределенного соединенияВам нужно будет иметь
fuse
установлен локально и сервер SSH, поддерживающий (и настроенный для)sftp
Может быть, вы ищете это: ZSSH
Zssh (Zmodem SSH) - это программа для интерактивной передачи файлов на удаленную машину при использовании secure shell (ssh). Он призван стать удобной альтернативой scp, позволяющей передавать файлы без необходимости открывать еще один сеанс и повторно аутентифицировать себя.
Используйте rsync по ssh, если вы можете собрать все файлы для отправки в одном каталоге (или иерархии каталогов).
Если у вас нет всех файлов в одном месте, пожалуйста, дайте дополнительную информацию о том, чего вы хотите достичь и почему вы не можете упаковать все файлы в архив и отправить его. Почему так важно, чтобы каждый файл отправлялся немедленно? Было бы нормально, если бы файл был отправлен с небольшой задержкой (например, когда накопилось 4K данных)?
Это хорошая маленькая проблема. Я не знаю о готовом решении, но вы могли бы многое сделать с простыми сценариями оболочки. Я бы попробовал это в приемнике:
#!/bin/ksh # this is receiverprogram while true do typeset -i length read filename # read filename sent by sender below read size # read size of file sent read -N $size contents # read all the bytes of the file print -n "$contents" > "$filename" done
На стороне отправителя я бы создал именованный канал и читал из него, например,
mkfifo $HOME/my-connection ssh remotehost receiver-script < $HOME/my-connection
Затем, чтобы отправить файл, я бы попробовал этот скрипт
#!/bin/ksh # this is senderprogram FIFO=$HOME/my-connection localname="$1" remotename="$2" print "$remotename" > $FIFO size=$(stat -c %s "$localname") print "$size" > $FIFO cat "$localname" > $FIFO
Если размер файла большой, вы, вероятно, не хотите читать его на одном дыхании, поэтому что-то в порядке
BUFSIZ=8192 rm -f "$filename" while ((size >= BUFSIZ)); do read -N $BUFSIZE buffer print -n "$buffer" >> "$filename" size=$((size - BUFSIZ)) done read -N $size buffer print -n "$contents" >> "$filename"
В конце концов вы захотите расширить сценарий, чтобы вы можете пройти через команды
chmod
иchgrp
. Поскольку Вы доверяете отправляющему коду, вероятно, проще всего структурировать его так, чтобы получатель просто вызывал shelleval
на каждой строке, а затем отправлял такие вещи, какprint filename='"'"$remotename"'"' > $FIFO print "read_and_copy_bytes " '$filename' "$size" > $FIFO
И затем определить локальную функцию
Конечно, ничего из этого не было проверено! Но я надеюсь, что это даст вам несколько полезных идей.read_and_copy_bytes
. Правильное цитирование-это медведь, но в остальном оно должно быть простым.
Похоже на работу для тара? Передайте его выходные данные в ssh, а с другой стороны передайте выходные данные ssh обратно в tar.
Я думаю, что рабочий стол GNOME использует одно SSH-соединение при доступе к общему ресурсу через SFTP (SSH). Я предполагаю, что это то, что происходит, потому что я вижу один процесс SSH, когда я получаю доступ к удаленному общему ресурсу таким образом. Так что, если это правда, вы должны быть в состоянии использовать ту же программу для этой цели.
Новая версия GNOME использовала GVFS через GIO для выполнения всех видов ввода-вывода через различные бэкэнды. Пакет Ubuntu gvfs-bin предоставляет различные командные строки утилиты, которые позволяют управлять бэкэндами из командной строки.
Сначала вам нужно будет смонтировать папку SSH:
GVFS-mount sftp://user@host/
А затем вы можете использовать gvfs-copy для копирования ваших файлов. Я думаю, что все передачи файлов будут выполняться через один SSH-процесс. Вы даже можете использовать ps, чтобы увидеть, какой процесс используется.
Если вы чувствуете себя более предприимчивым, вы можете даже написать свою собственную программу на C или на каком-либо другом языке высокого уровня, который предоставляет API для GIO.
Одним из вариантов является Conch - это реализация SSH-клиента и сервера, написанная на Python с использованием платформы Twsited . Вы можете использовать его для написания инструмента, который принимает запросы через какой-то другой протокол (HTTP или Unix доменные сокеты, FTP, SSH или что-то еще) и запускает передачу файлов по длительному SSH-соединению. На самом деле, у меня есть несколько программ в производстве, которые используют эту технику, чтобы избежать нескольких установок SSH-соединения.
Былочень похожий вопрос здесь пару недель назад. В принятом ответе предлагалось открыть туннель при передаче ssh на удаленную машину и использовать этот туннель для передачи scp.
Perhapse CurlFTPFS может быть правильным решением для вас.
Похоже, что он просто монтирует папку внешнего компьютера на ваш компьютер через SFTP. Как только это будет сделано, вы сможете использовать свои обычные команды
cp
, и все будет сделано надежно.К сожалению, я не смог проверить это сам, но дайте мне знать, если это работает для вас!
Edit 1: я смог загрузить и протестировать его. Как я и опасался, это действительно требует, чтобы клиент есть FTP-сервер. Однако я нашел другую программу, которая имеет точно такую же концепцию, как и то, что вы ищете.
sshfs
позволяет подключаться к клиентскому компьютеру без необходимости использования специального сервера. После того, как вы смонтировали одну из их папок, вы можете использовать свои обычные командыcp
для перемещения любых файлов, которые вам нужны. Как только вы закончите, это должно быть вопросом улыбкиumount /path/to/mounted/folder
. Дайте мне знать, как это работает!