Отправитель и получатель для передачи файлов через SSH по запросу? - PullRequest
10 голосов
/ 05 февраля 2009

Я создал программу, которая перебирает кучу файлов и вызывает некоторые из них:

scp <file> user@host:<remotefile>

Однако, в моем случае, могут быть тысячи небольших файлов, которые нужно перенести, и scp открывает новое ssh-соединение для каждого из них, что требует некоторых дополнительных затрат.

Мне было интересно, не существует ли решения, в котором я поддерживаю один процесс, поддерживающий соединение, и могу ли я отправлять ему «запросы» на копирование отдельных файлов.

В идеале я ищу комбинацию некоторой программы отправителя и получателя, чтобы я мог запустить один процесс (1) в начале:

ssh user@host receiverprogram

И для каждого файла я вызываю команду (2):

senderprogram <file> <remotefile>

и передать вывод (2) на вход (1), и это приведет к передаче файла. В конце я могу просто послать процессу (1) сигнал для завершения.

Предпочтительно программы отправителя и получателя являются программами C с открытым исходным кодом для Unix. Они могут общаться, используя сокет вместо трубы или любое другое творческое решение.

Однако важное ограничение заключается в том, что каждый файл передается в момент, когда я выполняю итерацию по нему: недопустимо собирать список файлов и затем вызывать один экземпляр scp для передачи все файлы сразу в конце. Кроме того, у меня есть только простой доступ к оболочке для принимающего хоста.

Обновление: Я нашел решение проблемы издержек соединения, используя функции мультиплексирования ssh, см. Мой собственный ответ ниже. Тем не менее, я начинаю вознаграждение, потому что мне любопытно узнать, существует ли программа отправителя / получателя, как я здесь описываю. Кажется, должно быть что-то, что можно использовать, например, Xmodem / YMODEM / Zmodem?

Ответы [ 14 ]

23 голосов
/ 06 февраля 2009

Я нашел решение под другим углом. Начиная с версии 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

Если контрольный сокет больше недоступен (например, потому что вы убили мастера), это возвращается к нормальному соединению. Более подробная информация доступна в этой статье .

4 голосов
/ 16 февраля 2009

Этот способ сработает, а для других вещей этот общий подход более или менее правильный.

(
iterate over file list
  for each matching file
   echo filename
) | cpio -H newc -o | ssh remotehost cd location \&\& | cpio -H newc -imud
4 голосов
/ 16 февраля 2009

Вы пробовали 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

4 голосов
/ 05 февраля 2009

Может работать sftp вместо scp и переводить его в пакетный режим. Создайте файл командных команд в виде канала или доменного сокета UNIX и передайте ему команды так, как вы хотите, чтобы они выполнялись.

Безопасность на этом может быть немного сложнее на стороне клиента.

3 голосов
/ 13 февраля 2009

Может быть, вы ищете это: ZSSH

zssh (Zmodem SSH) - программа для интерактивной передачи файлов на удаленный компьютер при использовании защищенной оболочки (ssh). Он предназначен для удобной альтернативы scp, позволяя передавать файлы без необходимости открывать другой сеанс и повторно проходить аутентификацию.

2 голосов
/ 12 февраля 2009

Это хорошая маленькая проблема. Я не знаю о готовом решении, но вы могли бы многое сделать с помощью простых сценариев оболочки. Я бы попробовал это на приемнике:

#!/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. Поскольку вы доверяете отправляющему коду, возможно, проще всего структурировать его так, чтобы получатель просто вызывал shell eval в каждой строке, а затем отправлял что-то вроде

print filename='"'"$remotename"'"' > $FIFO
print "read_and_copy_bytes " '$filename' "$size" > $FIFO

и затем определите локальную функцию read_and_copy_bytes. Правильное цитирование - мишка, но в остальном все должно быть просто.

Конечно, ничего из этого не было проверено! Но я надеюсь, что это даст вам несколько полезных идей.

2 голосов
/ 05 февраля 2009

Используйте rsync поверх ssh, если вы можете собрать все файлы для отправки в один каталог (или иерархию каталогов).

Если у вас нет всех файлов в одном месте, пожалуйста, дайте больше информации о том, чего вы хотите достичь, и почему вы не можете упаковать все файлы в архив и отправить его заново. Почему так важно, чтобы каждый файл отправлялся немедленно? Будет ли это нормально, если файл был отправлен с небольшой задержкой (например, когда накопилось 4K данных)?

1 голос
/ 17 февраля 2009

Perhapse CurlFTPFS может быть правильным решением для вас.

Похоже, он просто подключает папку внешнего компьютера к вашему компьютеру через SFTP. Как только это будет сделано, вы сможете использовать свои обычные команды cp, и все будет сделано безопасно.

К сожалению, я не смог проверить это сам, но дайте мне знать, работает ли он для вас!

Редактировать 1: Я смог загрузить и протестировать его. Как я и опасался, для этого требуется, чтобы у клиента был FTP-сервер. Однако , я нашел другую программу, которая имеет ту же концепцию, что и вы. sshfs позволяет вам подключаться к вашему клиентскому компьютеру без какого-либо специального сервера. После того, как вы смонтировали одну из их папок, вы можете использовать обычные команды cp, чтобы переместить все нужные вам файлы. Как только вы закончите, это должно быть улыбкой umount /path/to/mounted/folder. Дайте мне знать, как это работает!

1 голос
/ 16 февраля 2009

Был очень похожий вопрос здесь пару недель назад. В принятом ответе предлагается открыть туннель при подключении ssh к удаленной машине и использовать этот туннель для передачи scp.

1 голос
/ 14 февраля 2009

Один из вариантов - Conch - это реализация клиента и сервера SSH, написанная на Python с использованием Twsited . Вы можете использовать его для написания инструмента, который принимает запросы через какой-либо другой протокол (доменные сокеты HTTP или Unix, FTP, SSH или любой другой) и запускает передачу файлов через длительное соединение SSH. На самом деле, у меня есть несколько программ, которые используют эту технику, чтобы избежать множественных установок соединения SSH.

...