GNU/Linux >> Belajar Linux >  >> Linux

Apakah mungkin meminta Linux untuk menghitamkan byte selama pembacaan soket?

Ada tl;dr di bagian akhir.

Dalam komentar saya, saya menyarankan Anda mmap() /dev/null perangkat. Namun tampaknya perangkat tidak dapat dipetakan di komputer saya (err 19 :No such device ). Sepertinya /dev/zero dapat dipetakan. Pertanyaan/jawaban lain menyarankan yang setara dengan MAP_ANONYMOUS yang membuat fd argumen dan open() yang terkait tidak perlu di tempat pertama. Lihat contohnya:

#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;
}

Dalam contoh di atas Anda dapat melihat bahwa saya membuat private (tulisan tidak akan terlihat oleh anak-anak setelah fork() ) pemetaan memori anonim (tidak didukung oleh file) 4KiB (satu ukuran halaman pada kebanyakan sistem). Ini kemudian digunakan dua kali untuk memberikan tujuan penulisan untuk dua int -- int selanjutnya menimpa yang sebelumnya.

Itu tidak tepat selesaikan pertanyaan Anda:bagaimana mengabaikan byte. Karena Anda menggunakan readv() , saya melihat fungsi saudaranya, preadv() yang pada pandangan pertama tampaknya melakukan apa yang Anda inginkan:lewati byte. Namun, tampaknya itu tidak didukung pada deskriptor file soket. Kode berikut memberikan 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;
}

Jadi sepertinya bahkan preadv() menggunakan seek() di bawah tudung yang, tentu saja, tidak diizinkan di soket. Saya tidak yakin apakah ada (belum?) cara untuk memberi tahu OS untuk mengabaikan/menjatuhkan byte yang diterima dalam aliran yang sudah ada. Saya curiga itu karena @geza benar:biaya untuk menulis ke tujuan akhir (diabaikan) sangat sepele untuk sebagian besar situasi yang saya temui. Dan, dalam situasi di mana biaya byte yang diabaikan tidak sepele, Anda harus serius mempertimbangkan untuk menggunakan opsi, implementasi, atau protokol yang lebih baik.

tl;dr:

Membuat pemetaan memori pribadi anonim 4KiB secara efektif tidak dapat dibedakan dari wadah alokasi bersebelahan (ada perbedaan halus yang sepertinya tidak penting untuk beban kerja apa pun di luar kinerja kelas atas). Menggunakan wadah standar juga jauh lebih rentan terhadap bug alokasi:kebocoran memori, pointer liar, dkk. Jadi saya akan mengatakan KISS dan lakukan saja alih-alih mendukung apa pun dari kode yang saya tulis di atas. Misalnya:std::array<char, 4096> ignored; atau std::vector<char> ignored{4096}; dan cukup atur iovec.iov_base = ignored.data(); dan atur .iov_len ke ukuran berapa pun yang perlu Anda abaikan (dalam panjang penampung).


Linux
  1. Izin File di Linux – Baca/Tulis/Jalankan

  2. Apakah mungkin mengembangkan aplikasi DirectX di Linux?

  3. Kemungkinan untuk membatalkan shutdown di Linux?

  1. papan klip linux baca/tulis dalam C

  2. Linux:apakah ada pembacaan atau pemulihan dari soket dengan batas waktu?

  3. periksa semua soket dibuka di OS linux

  1. Mengelola partisi di Linux dengan fdisk

  2. Berbagai Metode untuk Memasang Drive di Linux?

  3. Apakah mungkin untuk mengembangkan modul kernel linux di CLion?