C'è un tl;dr alla fine.
Nel mio commento, ti ho suggerito mmap()
il /dev/null
dispositivo. Tuttavia sembra che il dispositivo non sia mappabile sulla mia macchina (err 19
:No such device
). Sembra /dev/zero
è mappabile però. Un'altra domanda/risposta suggerisce che è equivalente a MAP_ANONYMOUS
che fa il fd
argomento e il relativo open()
associato inutile in primo luogo. Guarda un esempio:
#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;
}
Nell'esempio sopra puoi vedere che creo un privato (le scritture non saranno visibili dai bambini dopo fork()
) mappatura della memoria anonima (non supportata da un file) di 4 KiB (una singola dimensione di pagina sulla maggior parte dei sistemi). Viene quindi utilizzato due volte per fornire una destinazione di scrittura per due int:l'int successivo sovrascrive quello precedente.
Questo non esattamente risolvi la tua domanda:come ignorare i byte. Dato che stai usando readv()
, ho esaminato la sua funzione gemella, preadv()
che a prima vista sembra fare quello che vuoi che faccia:saltare i byte. Tuttavia, sembra che non sia supportato sui descrittori di file socket. Il codice seguente restituisce 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;
}
Quindi sembra anche preadv()
utilizza seek()
sotto il cofano che, ovviamente, non è consentito su una presa. Non sono sicuro che esista (ancora?) Un modo per dire al sistema operativo di ignorare/eliminare i byte ricevuti in un flusso stabilito. Sospetto che sia perché @geza ha ragione:il costo per scrivere alla destinazione finale (ignorata) è estremamente banale per la maggior parte delle situazioni che ho incontrato. E, nelle situazioni in cui il costo dei byte ignorati non banale, dovresti prendere seriamente in considerazione l'utilizzo di opzioni, implementazioni o protocolli migliori.
tl;dr:
La creazione di una mappatura della memoria privata anonima di 4 KiB è effettivamente indistinguibile dai contenitori di allocazione contigua (ci sono sottili differenze che probabilmente non sono importanti per qualsiasi carico di lavoro al di fuori delle prestazioni di fascia alta). L'utilizzo di un contenitore standard è anche molto meno soggetto a bug di allocazione:perdite di memoria, puntatori jolly e così via. Quindi direi KISS e lo farei invece di approvare qualsiasi del codice che ho scritto sopra. Ad esempio:std::array<char, 4096> ignored;
o std::vector<char> ignored{4096};
e basta impostare iovec.iov_base = ignored.data();
e imposta .iov_len
a qualsiasi dimensione tu debba ignorare (entro la lunghezza del contenitore).