送信者と受信者は要求に応じて ssh 経由でファイルを転送しますか?
-
21-08-2019 - |
質問
多数のファイルを反復処理し、それらの一部を呼び出すプログラムを作成しました。
scp <file> user@host:<remotefile>
ただし、私の場合、転送する必要がある小さなファイルが数千ある可能性があり、scp はそれらのファイルごとに新しい ssh 接続を開くため、かなりのオーバーヘッドが発生します。
接続を維持する1つのプロセスを実行し続け、単一のファイルをコピーするための「リクエスト」を送信できる解決策はないのかと疑問に思っていました。
理想的には、最初に単一のプロセス (1) を開始できるような、送信側プログラムと受信側プログラムの組み合わせを探しています。
ssh user@host receiverprogram
そして、ファイルごとにコマンド (2) を呼び出します。
senderprogram <file> <remotefile>
(2) の出力を (1) の入力にパイプすると、ファイルが転送されます。最終的には、プロセス (1) に終了するためのシグナルを送信するだけです。
送信側および受信側プログラムは、Unix 用のオープンソース C プログラムであることが好ましい。パイプの代わりにソケットを使用したり、その他の創造的なソリューションを使用して通信することもできます。
ただし、それは 重要な制約 各ファイルは反復処理した瞬間に転送されることがわかります。ファイルのリストを収集してから、次のインスタンスを 1 つ呼び出すことは受け入れられません。 scp
最後にすべてのファイルを一度に転送します。また、受信ホストへの単純なシェル アクセスしかありません。
アップデート: SSH の多重化機能を使用して、接続オーバーヘッドの問題の解決策を見つけました。以下の私自身の回答を参照してください。それでも、ここで説明する送信者/受信者プログラムが存在するかどうか知りたいので、報奨金制度を開始しています。使用できるものが存在するはずです。xモデム/yモデム/zモデム?
解決
この方法はうまくいきますし、他のことについては、この一般的なアプローチが多かれ少なかれ正しいです。
(
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 サポート セッション多重化:1 つの接続で複数のログイン セッションやファイル転送セッションを実行できます。これにより、接続ごとのセットアップ コストが回避されます。
質問の場合、まずコントロール マスターを設定して接続を開くことができます (-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
制御ソケットが使用できなくなった場合 (例:マスターを強制終了したため)、これは通常の接続に戻ります。詳細については、以下を参照してください。 この記事.
scp の代わりに sftp を使用し、バッチ モードにすると機能する可能性があります。バッチ コマンド ファイルをパイプまたは UNIX ドメイン ソケットにして、実行したいときにコマンドをそれに送り込みます。
これに関するセキュリティは、クライアント側では少し注意が必要な場合があります。
やってみました sshfs
?あなたは出来る:
sshfs remote_user@remote_host:/remote_dir /mnt/local_dir
どこ
/remote_dir
ssh しているシステム上のファイルの送信先ディレクトリでした/mnt/local_dir
ローカルのマウント場所でした
この設定でできることは、 cp
ファイルを local_dir
そしてそれは送られるでしょう sftp
に remote_host
その中で remote_dir
接続が 1 つであるため、オーバーヘッドがほとんどないことに注意してください。
フラグを使用する必要がある場合があります -o ServerAliveInterval=15
を維持する 無限のつながり
必要となるのは、 fuse
ローカルにインストールされ、SSH サーバーがサポートされている (および構成されている) sftp
あなたはこれを探しているかもしれません:ZSSH
zssh (Zmodem SSH) は、セキュア シェル (ssh) を使用してリモート マシンに対話的にファイルを転送するためのプログラムです。これは scp の便利な代替手段となることを目的としており、別のセッションを開いて自分自身を再認証することなくファイルを転送できるようにします。
送信するすべてのファイルを 1 つのディレクトリ (またはディレクトリ階層) に収集できる場合は、ssh 経由の rsync を使用します。
すべてのファイルが 1 か所にない場合は、何を達成したいのか、およびすべてのファイルを 1 つのアーカイブにパックして送信できない理由について、さらに情報を提供してください。各ファイルをすぐに送信することがなぜそれほど重要なのでしょうか?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
コマンド。送信コードを信頼するので、受信側が単純にシェルを呼び出すように構造化するのがおそらく最も簡単です。 eval
各行に次のようなものを送信します
print filename='"'"$remotename"'"' > $FIFO
print "read_and_copy_bytes " '$filename' "$size" > $FIFO
そしてローカル関数を定義します read_and_copy_bytes
. 。引用を正しく行うのは大変ですが、それ以外は簡単なはずです。
もちろん、これらはどれもテストされていません。しかし、いくつかの有益なアイデアが得られることを願っています。
タールの仕事のようですか?その出力を ssh にパイプ接続し、反対側で ssh 出力を tar にパイプ接続します。
GNOME デスクトップは、SFTP (SSH) 経由で共有にアクセスするときに単一の SSH 接続を使用すると思います。この方法でリモート共有にアクセスすると単一の SSH プロセスが表示されるため、これが起こっていることだと思います。したがって、これが本当であれば、この目的に同じプログラムを使用できるはずです。
新しいバージョンの GNOME では GVFS が使用されました。 GIO さまざまなバックエンドを通じてあらゆる種類の I/O を実行するため。Ubuntu パッケージ gvfs-bin は、コマンド ラインからバックエンドを操作できるさまざまなコマンド ライン ユーティリティを提供します。
まず、SSH フォルダーをマウントする必要があります。
gvfs-mount sftp://user@host/
その後、gvfs-copy を使用してファイルをコピーできます。すべてのファイル転送は単一の SSH プロセスを通じて実行されると思います。ps を使用して、どのプロセスが使用されているかを確認することもできます。
もっと冒険したい場合は、GIO に API を提供する C またはその他の高級言語で独自のプログラムを作成することもできます。
ありました 非常によく似た質問がここにあります 数週間前。の 受け入れられた回答 リモート マシンに ssh 接続するときにトンネルを開き、そのトンネルを scp 転送に使用することを提案しました。
おそらく カールFTPFS あなたにとって有効な解決策になるかもしれません。
外部コンピュータのフォルダを SFTP 経由でコンピュータにマウントするだけのようです。それが完了すると、通常の cp
コマンドなどすべてが安全に行われます。
残念ながら私自身でテストすることはできませんでしたが、うまくいくかどうか教えてください。
編集1: ダウンロードしてテストすることができました。心配したように、クライアントに FTP サーバーが必要です。 しかし, あなたが探しているものとまったく同じコンセプトを持つ別のプログラムを見つけました。 sshfs
を使用すると、特別なサーバーを必要とせずにクライアント コンピューターに接続できます。フォルダーの 1 つをマウントしたら、通常のフォルダーを使用できます。 cp
必要なファイルをさらに移動するコマンド。それが終わったら、あとは笑顔で済むはずです umount /path/to/mounted/folder
. 。これがどのように機能するのか教えてください。
rsync -avlzp user@remotemachine:/path/to/files /path/to/this/folder
これにより、SSH を使用して、低速ではない方法でファイルが転送されます。
シンプルにして、次のようなことを行う小さなラッパー スクリプトを作成します。
- ファイルをtarする
- tar ファイルを送信する
- 反対側でアンター
このようなもの:
- tar -cvzf test.tgz ファイル ....
- scp test.tgz user@other.site.com:。
- ssh user@other.site.com tar -xzvf test.tgz
/ヨハン