11

私は楽しみのために 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 を実行しています)。

4

2 に答える 2

8

これはどのカーネルバージョンですか?Linux は 2.6.25 (commit 9c55e01c0 ) から TCP ソケットからのスプライシングをサポートしているため、以前のバージョンを使用している場合は運が悪いです。

于 2009-05-19T20:58:52.310 に答える
2

単一のスプライス from toを実行するたびに、 splice_allfrom pipes[0]toする必要があります(これは、最後の単一のスプライスによって読み取られたばかりのバイト数です)。理由: パイプは有限のカーネル メモリ バッファを表します。したがって、バイト数がそれを超える場合は、 で永久にブロックされます。tofrompipes[1]splice_allsplice_all(from, pipes[1], bytes)

于 2010-12-28T00:24:11.050 に答える