私は楽しみのために Linux 上の C で TCP 経由でファイルを転送する小さなプログラムを書いています。プログラムは、ソケットからファイルを読み取り、それをファイルに書き込みます (またはその逆)。私はもともと読み取り/書き込みを使用しており、プログラムは正しく動作していましたが、スプライスについて学び、試してみたいと思いました。
私が splice で書いたコードは、標準入力 (リダイレクトされたファイル) から読み取って TCP ソケットに書き込むときには完全に機能しますが、ソケットから読み取って標準出力に書き込むときに、splice が errno を EINVAL に設定するとすぐに失敗します。マニュアルページには、どちらの記述子もパイプではない場合 (そうでない場合)、シークできないストリームにオフセットが渡された場合 (オフセットが渡されなかった場合)、またはファイルシステムがスプライシングをサポートしていない場合に EINVAL が設定されると記載されています。私の質問に: これは、TCP がパイプから接続できるが、接続できないことを意味しますか?
何か間違ったことをしたことを願って、以下のコード (エラー処理コードを除く) を含めます。これは、ウィキペディアの splice の例に大きく基づいています。
static void splice_all(int from, int to, long long bytes)
{
long long bytes_remaining;
long result;
bytes_remaining = bytes;
while (bytes_remaining > 0) {
result = splice(
from, NULL,
to, NULL,
bytes_remaining,
SPLICE_F_MOVE | SPLICE_F_MORE
);
if (result == -1)
die("splice_all: splice");
bytes_remaining -= result;
}
}
static void transfer(int from, int to, long long bytes)
{
int result;
int pipes[2];
result = pipe(pipes);
if (result == -1)
die("transfer: pipe");
splice_all(from, pipes[1], bytes);
splice_all(pipes[0], to, bytes);
close(from);
close(pipes[1]);
close(pipes[0]);
close(to);
}
splice_all
余談ですが、パイプがいっぱいになったためにファイルが十分に大きい場合(?)、上記は最初にブロックされると思います。そのため、パイプfork
から読み書きするコードのバージョンもあります。同じ時間ですが、このバージョンと同じエラーがあり、読みにくくなっています。
編集: 私のカーネルのバージョンは 2.6.22.18-co-0.7.3 です (XP で coLinux を実行しています)。