GNU/Linux >> Linux の 問題 >  >> Linux

ソケットの読み取り中に Linux にブラックホール バイトを要求することは可能ですか?

最後に tl;dr があります。

私のコメントで、私はあなたに mmap() を提案しました /dev/null デバイス。しかし、私のマシンではデバイスがマッピングできないようです (err 19 :No such device )。 /dev/zero のようです ただし、マッピング可能です。別の質問/回答は、それが MAP_ANONYMOUS と同等であることを示唆しています fd になります 引数とそれに関連付けられた open() そもそも不要。例をご覧ください:

#include <iostream>
#include <cstring>
#include <cerrno>
#include <cstdlib>

extern "C" {
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
}

template <class Type>
struct iovec ignored(void *p)
{
    struct iovec iov_ = {};
    iov_.iov_base = p;
    iov_.iov_len = sizeof(Type);
    return iov_;
}

int main()
{
    auto * p = mmap(nullptr, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if ( MAP_FAILED == p ) {
        auto err = errno;
        std::cerr << "mmap(MAP_PRIVATE | MAP_ANONYMOUS): " << err << ": " << strerror(err) << std::endl;
        return EXIT_FAILURE;
    }

    int s_[2] = {-1, -1};
    int result = socketpair(AF_UNIX, SOCK_STREAM, 0, s_);
    if ( result < 0 ) {
        auto err = errno;
        std::cerr << "socketpair(): " << err << ": " << strerror(err) << std::endl;
        return EXIT_FAILURE;
    }

    int w_[3] = {1,2,3};
    ssize_t nwritten = 0;
    auto makeiov = [](int & v){
        struct iovec iov_ = {};
        iov_.iov_base = &v;
        iov_.iov_len = sizeof(v);
        return iov_;
    };
    struct iovec wv[3] = {
        makeiov(w_[0]),
        makeiov(w_[1]),
        makeiov(w_[2])
    };

    nwritten = writev(s_[0], wv, 3);
    if ( nwritten < 0 ) {
        auto err = errno;
        std::cerr << "writev(): " << err << ": " << strerror(err) << std::endl;
        return EXIT_FAILURE;
    }

    int r_ = {0};
    ssize_t nread = 0;
    struct iovec rv[3] = {
        ignored<int>(p),
        makeiov(r_),
        ignored<int>(p),
    };

    nread = readv(s_[1], rv, 3);
    if ( nread < 0 ) {
        auto err = errno;
        std::cerr << "readv(): " << err << ": " << strerror(err) << std::endl;
        return EXIT_FAILURE;
    }

    std::cout <<
        w_[0] << '\t' <<
        w_[1] << '\t' <<
        w_[2] << '\n' <<
        r_ << '\t' <<
        *(int*)p << std::endl;

    return EXIT_SUCCESS;
}

上記の例では、プライベートを作成していることがわかります (書き込みは、fork() 以降の子には表示されません) ) 4KiB の匿名 (ファイルに依存しない) メモリ マッピング (ほとんどのシステムで 1 つのページ サイズ)。次に、2 つの int の書き込み先を提供するために 2 回使用されます。後の int は前の int を上書きします。

正確ではない あなたの質問を解決してください:バイトを無視する方法。 readv() を使用しているため 、その姉妹関数 preadv() を調べました 一見すると、あなたがやりたいことをしているように見えます:バイトをスキップします。ただし、ソケット ファイル記述子ではサポートされていないようです。次のコードは preadv(): 29: Illegal seek を返します .

rv = makeiov(r_[1]);
nread = preadv(s_[1], &rv, 1, sizeof(int));
if ( nread < 0 ) {
    auto err = errno;
    std::cerr << "preadv(): " << err << ": " << strerror(err) << std::endl;
    return EXIT_FAILURE;
}

だから preadv() にも見える seek() を使用 もちろん、ソケットでは許可されていません。確立されたストリームで受信したバイトを無視/ドロップするように OS に指示する方法があるかどうか (まだ?) はわかりません。 @geza が正しいためだと思います。最終的な (無視された) 宛先に書き込むコストは、私が遭遇したほとんどの状況で非常に些細なことです。また、無視されたバイトのコストがない場合 より良いオプション、実装、またはプロトコルの使用を真剣に検討する必要があります。

tl;dr:

4KiB の匿名プライベート メモリ マッピングの作成は、実質的に連続割り当てコンテナーと見分けがつきません (非常にハイエンドなパフォーマンス以外のワークロードにとって重要ではない微妙な違いがあります)。 また、標準コンテナを使用すると、メモリ リーク、ワイルド ポインタなどの割り当てバグが発生しにくくなります。だから私はKISSと言って、それをするだけです いずれかを支持する代わりに 私が上に書いたコードの。例:std::array<char, 4096> ignored; または std::vector<char> ignored{4096}; iovec.iov_base = ignored.data(); を設定するだけです .iov_len を設定します 無視する必要がある任意のサイズ (コンテナーの長さ内)。


Linux
  1. Linuxでfdiskを使用してパーティションを管理する

  2. Linuxでドライブをマウントするさまざまな方法?

  3. 指定された文字数を読み取る Linux コマンド (cat など)

  1. Linux で .dll を使用可能

  2. LinuxからEXEバージョンを読み取るCライブラリ?

  3. Linux、ソケット、ノンブロッキング接続

  1. Linuxのchmodコマンドの概要

  2. Linux のファイル権限 – 読み取り/書き込み/実行

  3. CLion で Linux カーネルモジュールを開発することは可能ですか?