Il y a un tl;dr à la fin.
Dans mon commentaire, je vous ai proposé mmap()
le /dev/null
dispositif. Cependant, il semble que l'appareil ne soit pas mappable sur ma machine (err 19
:No such device
). Il ressemble à /dev/zero
est cependant cartographiable. Une autre question/réponse suggère que cela équivaut à MAP_ANONYMOUS
ce qui fait le fd
argument et son open()
associé inutile a priori. Découvrez un exemple :
#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;
}
Dans l'exemple ci-dessus, vous pouvez voir que je crée un privé (les écritures ne seront plus visibles par les enfants après fork()
) mappage mémoire anonyme (non sauvegardé par un fichier) de 4 Ko (une seule taille de page sur la plupart des systèmes). Il est ensuite utilisé deux fois pour fournir une destination d'écriture pour deux entiers -- le dernier int écrasant le précédent.
Ce n'est pas exactement résoudre votre question:comment ignorer les octets. Puisque vous utilisez readv()
, j'ai examiné sa fonction sœur, preadv()
qui, à première vue, semble faire ce que vous voulez qu'il fasse :sauter des octets. Cependant, il semble que ce ne soit pas pris en charge sur les descripteurs de fichiers socket. Le code suivant donne 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;
}
Il ressemble donc même à preadv()
utilise seek()
sous le capot ce qui n'est bien sûr pas autorisé sur une prise. Je ne sais pas s'il existe (encore?) Un moyen de dire au système d'exploitation d'ignorer/d'abandonner les octets reçus dans un flux établi. Je suppose que c'est parce que @geza a raison :le coût d'écriture vers la destination finale (ignorée) est extrêmement insignifiant pour la plupart des situations que j'ai rencontrées. Et, dans les situations où le coût des octets ignorés n'est pas trivial, vous devriez sérieusement envisager d'utiliser de meilleures options, implémentations ou protocoles.
tl;dr :
La création d'un mappage de mémoire privée anonyme de 4 Ko est effectivement impossible à distinguer des conteneurs d'allocation contiguës (il existe des différences subtiles qui ne sont probablement pas importantes pour une charge de travail en dehors des performances très élevées). L'utilisation d'un conteneur standard est également beaucoup moins sujette aux bogues d'allocation :fuites de mémoire, pointeurs sauvages, etc. Alors je dirais KISS et fais ça au lieu d'approuver tout du code que j'ai écrit ci-dessus. Par exemple :std::array<char, 4096> ignored;
ou std::vector<char> ignored{4096};
et définissez simplement iovec.iov_base = ignored.data();
et définissez le .iov_len
à la taille que vous devez ignorer (dans la longueur du conteneur).