Fonctions avancées d'E / S readv et writev Struct iovec

 


Pourquoi introduire readv () et writev ()

  1. Comme read () est utilisé pour lire des données dans une mémoire discontinue et que write () est utilisé pour envoyer de la mémoire discontinue, plusieurs appels seront nécessaires pour lire et écrire.
    Si vous voulez lire une donnée continue d'un fichier vers un autre zone du processus Il existe deux solutions: ①Utilisez read () pour les lire dans un tampon plus grand à la fois, puis divisez-les en plusieurs parties et copiez-les dans différentes zones; ②Appelez read () plusieurs fois pour les lire zone de lots différents.
    De même, si vous souhaitez écrire en continu des blocs de données dans différentes zones du programme dans un fichier, un traitement similaire doit être effectué.
  2. Comment résoudre la surcharge causée par plusieurs appels système + copie?
    UNIX fournit deux autres fonctions: readv () et writev (). Ils n'ont besoin que d'un seul appel système pour transférer des données entre plusieurs tampons dans un fichier et un processus, éliminant ainsi la surcharge des appels système multiples ou de la copie de données.
  3. Comparaison des résultats temporels entre writev et d'autres technologies
    en fonctionnement Linux (Intel x86) Mac OS X (PowerPC)
    utilisateur système l'horloge utilisateur système l'horloge
    Ecrire deux fois 1,29 3,15 7,39 1,60 17,40 19,84
    Copie tampon, puis écrivez une fois 1,03 1,98 6,47 1.10 11.09 12,54
    Writev une fois 0,70  2,72 6,41 0,86 13,58 14,72


    Le programme de test que nous avons mesuré produit un en-tête de 100 octets suivi d'une donnée de 200 octets. Cela a été fait 1048576 fois, résultant en un fichier de 300M. La procédure de test comporte trois conditions distinctes - une pour chaque technique de mesure dans le tableau ci-dessus. Nous utilisons les temps (Section 8.16) pour obtenir l'heure de l'utilisateur CUP, le système CPU du système et l'heure de l'horloge murale, avant et après l'écriture. Les trois heures sont affichées en secondes. 

readv / writev

Dans un appel de fonction:
① writev rassemble les données de sortie de chaque tampon vers fd dans l'ordre iov [0], iov [1] vers iov [iovcnt-1]
② readv lit les données de fd dans le même ordre Répartis vers chaque tampon , readv remplit toujours un tampon en premier, puis remplit le suivant

#include <sys/uio.h>
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
struct iovec {
    void  *iov_base;    /* Starting address */
    size_t iov_len;     /* Number of bytes to transfer */
};

(1) Paramètres: Le premier paramètre fd de readv et writev est un descripteur de fichier, et le deuxième paramètre est un pointeur vers la structure de données iovec, où iov_base est la première adresse du tampon, iov_len est la longueur du tampon, et le paramètre iovcnt spécifie le nombre d'iovec.
(2) Valeur de retour: lorsque l'appel de la fonction réussit, il renvoie le nombre total d'octets lus et écrits. Lorsqu'il échoue, il renvoie -1 et définit le numéro d'erreur correspondant.
Insérez la description de l'image ici

Exemple de code

  1. writev: deux tampons sont spécifiés, str0 et str1, le contenu est sorti sur la sortie standard et le nombre réel d'octets en sortie est imprimé
// writevex.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/uio.h>

int main()
{
    char *str0 = "hello ";
    char *str1 = "world\n";
    struct iovec iov[2];
    ssize_t nwritten;

    iov[0].iov_base = str0;
    iov[0].iov_len = strlen(str0) + 1;
    iov[1].iov_base = str1;
    iov[1].iov_len = strlen(str1) + 1;

    nwritten = writev(STDOUT_FILENO, iov, 2);
    printf("%ld bytes written.\n", nwritten);

    exit(EXIT_SUCCESS);
}
  1. readv: lire les données de l'entrée standard, stockées dans buf1 et buf2
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/uio.h>

int main()
{
    char buf1[8] = { 0 };
    char buf2[8] = { 0 };
    struct iovec iov[2];
    ssize_t nread;

    iov[0].iov_base = buf1;
    iov[0].iov_len = sizeof(buf1);
    iov[1].iov_base = buf2;
    iov[1].iov_len = sizeof(buf2);

    nread = readv(STDIN_FILENO, iov, 2);
    printf("%ld bytes read.\n", nread);
    printf("buf1: %s\n", buf1);
    printf("buf2: %s\n", buf2);

    exit(EXIT_SUCCESS);
}
  1. Lire et écrire des fichiers
#include <stdio.h>
#include <sys/uio.h>
#include <fcntl.h>
 
int main(void){
        char buf1[5],buf2[10];
        struct iovec iov[2];
        iov[0].iov_base = buf1;
        iov[0].iov_len = 5;
        iov[1].iov_base = buf2;
        iov[1].iov_len = 10;
 
        int fd = open("a.txt",O_RDWR);
        if(fd < 0){
                perror("open");
                return -1;
        }
        int rsize = readv(fd, iov, 2);  // 从文件a.txt中读取数据,存到iov[2]中的buf1、buf2
        printf("rsize = %d\n",rsize);
 
        close(fd);
 
        fd = open("b.txt", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
        if(fd < 0){
                perror("open");
                return -1;
        }
 
        int wsize = writev(fd,iov,2);  // 将iov[2]中的buf1、buf2,写入到文件b.txt
        printf("wsize = %d\n",wsize);
 
        close(fd);
        return 0;
}

Je suppose que tu aimes

Origine blog.csdn.net/star871016/article/details/109084558
conseillé
Classement