検索できないストリーム(事前サイズが不明)を結合して再度分離できるプログラムはありますか?

検索できないストリーム(事前サイズが不明)を結合して再度分離できるプログラムはありますか?

複数の入力ファイル/ストリームを単一のストリーム(仮想コマンドを使用stream-cat)に接続し、そのストリームをリモートホストにパイプした後、この例のようにリモートsshホスト()から別のファイル/ストリームに再び分離しようとしています。stream-sep目的のみ:

stream-cat <( zfs send tank/vm@snapshot ) somefile.txt | ssh user@host "stream-sep >( zfs receive tank/vm@snapshot ) somefile.txt"

説明 例:zfs sendサイズがあらかじめ分からない大きな文字列のデータを出力します (そのためtar処理できません)。このデータストリームは通常のファイルの内容に関連付けられていますsomefile.txt。結果のストリームはパイプで接続され、ssh再び分離されます。最初のストリームはにパイプされ、zfs receive2番目のストリームは通常のファイルに書き込まれます。

これらのプログラムは、検索できないストリームをチャンクに読み込み、常にチャンクサイズを書き込んでから、ストリームの終わりに達するまでデータを記録して実装しやすくする必要があります。オーバーヘッドは最小化されます。

そのようなプログラムはすでに存在していますか?

答え1

あなたが説明するもの再利用;何かが必要規約(つまり、データ処理方法の公式仕様)

これを達成する方法はいくつかあります。たとえば、コンピュータが同じサーバーでもHTTP経由で複数のファイルを同時に完全にダウンロードできることがわかります。この機能は、異なるストリームを送信して受信側で「分離」できるトランスポートプロトコルとして機能するTCPによって最初に導入されました。

したがって、TCPはすでにこの機能を提供しているので、2つの同時SSH接続を開始して使用するだけです!

zfs send | zstd -10 | ssh user@host 'zstd -d | zfs receive tank/vm@snapshot' &
# ^         ^    ^     ^             ^     ^   ^                             ^
# |         |    |     |             |     |   |                             |
# |         |    |     |             |     |   |     Tell your own shell to run
# |         |    |     |             |     |   |     this in the background and
# |         |    |     |             |     |   |     not block
# |         |    |     |             |     |   |                         
# |         |    |     |             |     |   |                            
# |         |    |     |             |     |   \---- Program to receive in the end
# |         |    |     |             |     |
# |         |    |     |             \-----+-------- use zstd to decompress
# |         |    |     |                             received data
# |         |    |     |            
# |         |    |     |
# |         |    |     \---------------------------- our first ssh invocaton
# |         |    |
# |         \----+---------------------------------- use zstd to compress at medium
# |                                                  high compression level (10)
# |
# \------------------------------------------------- the first program whose output
#                                                    we send

cat somefile.txt | ssh user@host 'cat > somefile.txt'
#                                                    Second SSH connection

もちろん、少し優雅なものではなくcat somefile.txt | ssh … > somefile.txt直接使用することもできますscp somefile.txt user@host:somefile.txt(内部的にはSSHを使用しますが、シェル接続を実行する代わりにSSHに組み込まれているSCPレイヤーを使用してファイルをコピーします)。

ファイルに以下を追加すると、2番目の接続をすばやく作成できます~/.ssh/config

ControlMaster auto
ControlPath /tmp/.ssh-socket-%h_%p_%r

これは、SSHがSSHセッションを再利用し、複数の暗号化ストリームを同時に送信するように指示します(これはおよびscpすべての組み合わせで機能します)。ssh

答え2

stream-catおおよその実装は次のようstream-sepに簡単に書くことができますperl

stream-cat() {
  perl -ne 'BEGIN{$/ = \0x7fff}
            print pack("n", $c|length()<<1), $_;
            $c = !eof' -- "$@"
}
stream-sep() {
  perl -e 'while($/ = \2, $_ = <STDIN>) {
             $n = unpack "n";
             open OUT, shift@ARGV unless $n & 1;
             if ($n>>=1) {$/ = \$n; $_ = <STDIN>; print OUT}
           }' -- "$@"
}

または関数の#! /bin/sh -代わりにスクリプトと同じです。sh

(エラー処理は、読者の皆さんの練習問題として残しました:-).

stream-catネットワークエンコーディング(ビッグエンディアン)短い形式が先頭に32767バイトのレコードを送信します。nこれらのうち最も低いビットは新しいストリーム(0)の開始か連続かを示し、残りのビットはサイズです。

次に、例えば次のようになります。

$ cat a
test
$ stream-cat 'seq 10|' a | stream-sep '|wc -l' '>b'
10
$ cat b
test

あなたの場合は次のとおりです。

stream-cat 'zfs send tank/vm@snapshot|' somefile.txt |
  ssh user@host 'stream-sep "|zfs receive tank/vm@snapshot" ">somefile.txt"'

まれに安全でない形式open(ここでは<>asとasとしても使用されます-n)が実際に役に立ち、ファイルを読み取り専用または書き込み専用モードで開くか、コマンドにパイプするか、コマンド<fileからパイプすることができます。>file|cmdcmd|

これを使用する方が|cmd/あなたよりも優れています/cmd|一度に1つだけ開いているので、問題なく数千の別々のストリームを送信できます。<(cmd)>(cmd)

関連情報