UNIX/Linux CIB : Lecture à partir d'un tuyau. Comment savoir la longueur de données au moment de l'exécution?
J'ai un enfant de processus qui génère de la sortie de longueur variable et l'envoie ensuite le parent à l'aide d'un semi-duplex pipe. Dans le parent, comment puis-je utiliser le lire() la fonction?
Puisque les données peuvent être de longueur différente à chaque fois, comment puis-je au moment de l'exécution de connaître la taille des données à n'importe quel malloc() pour un tampon? Peut le fstat() fonction être utilisé sur une conduite d'un descripteur de fichier?
Je sais que la lecture() va lire un nombre spécifié d'octets, mais sera de retour 0 si la fin de fichier (pas le caractère EOF) est atteint avant que les octets demandés ont été lus.
Je suis spécifiquement Ubuntu GNU/Linux avec un 2.6.27-9 du Noyau.
Tous les exemples de Richard Stevens " Advanced Programming in the UNIX Environment avez spécifié la longueur des données lors de l'écriture dans la tuyauterie ou ont compté sur fgets() stdio.h fonction. Depuis que je suis préoccupé par la vitesse, je veux rester loin de l'aide de stdio.h autant que possible.
Ce que ce sera nécessairement plus rapide avec de la mémoire partagée?
Grâce,
-Dhruv
Je vais faire un peu d'analyse sur la collecte à la sortie. Depuis la sortie de l'outil est très bien mis en forme avec des retours à la ligne et les espaces, j'ai pu le faire beaucoup plus facilement et efficacement en parcourant la mémoire tampon à l'aide de pointeurs que le stockage intermédiaire des données dans un fichier sur le disque, puis avec de la ficelle.h des fonctions comme sscanf(). Je me demandais si en faisant successives lseek() sur le tuyau sera d'aucune aide pour obtenir la taille des données.
Veuillez lire la mise à jour de ma réponse. Il vous montrera ce que vous devez faire si vous souhaitez lire les données qu'il devient disponible.
Vous ne pouvez pas utiliser lseek() sur un tuyau. Même si elle a un descripteur de fichier et agit un peu comme un fichier, une pipe n'est pas un fichier de plus qu'un socket.
OriginalL'auteur Dhruv | 2009-07-19
Vous devez vous connecter pour publier un commentaire.
Puisqu'il semble que vous avez l'intention de faire une seule lecture de toutes les données de la pipe, je pense que la suite va vous servir mieux que séparateur+encodage ou miniheader techniques suggéré dans d'autres réponses:
De la pipe (7) page de manuel:
L'exemple suivant a été prise à partir de la pipe (2) page de manuel et inversées, de sorte que l'enfant ne l'écrit, la mère de la lecture (juste pour être sûr). J'ai également ajouté une variable de la taille de la mémoire tampon. L'enfant va dormir pendant 5 secondes. Le délai sera de s'assurer que la sortie() de l'enfant n'ont rien à voir avec pipeio (le parent doit imprimer une ligne complète avant que l'enfant ne quitte).
De votre commentaire, je vois maintenant que vous voudrez peut-être lire les données qu'il devient disponible, pour mettre à jour l'INTERFACE utilisateur ou que ce soit, afin de refléter l'état de votre système. Pour ouvrir le tuyau de non-blocage (O_NONBLOCK) mode. Lire à plusieurs reprises ce qui est disponible jusqu'à -1 est returnd et errno == EAGAIN et faire votre analyse. Répétez l'unil read retourne 0, ce qui indique que l'enfant a fermé la pipe.
D'utiliser un tampon en mémoire du Fichier* fonctions que vous pouvez utiliser fmemopen() de la bibliothèque C de GNU.
Merci; votre exemple de code a presque fonctionné pour moi, sauf qu'il ne parvient pas à zéro à la fin de read_buffer!
Oui, c'est vrai. L'appel à puts(slurpfd(...)) ne fonctionnera pas correctement car la mémoire tampon n'est pas nul/nulle terminée. Merci pour le tuyau.
OriginalL'auteur Inshallah
Depuis la rédaction de la fin peut toujours écrire plus de données sur le tuyau, il n'y a aucun moyen de savoir la taille des données. Vous pouvez avoir l'expéditeur écrire la longueur de la première, ou vous pouvez allouer une largish tampon, lire autant que vous pouvez, puis redimensionnez le tampon, s'il n'est pas assez grand.
Mémoire partagée sera plus rapide car il évite les copies et peut éviter des appels, mais le verrouillage des protocoles nécessaires pour transférer des données à travers shmem sont plus complexes et sujettes à l'erreur, il est donc généralement préférable d'éviter de mémoire partagée, sauf si vous avez absolument besoin. En outre, avec la mémoire partagée, vous devez définir une taille maximale fixe pour le transfert de données lorsque vous allouez de la mémoire tampon.
OriginalL'auteur bdonlan
Vous ne pouvez pas obtenir des informations sur la taille d'un tuyau, car il n'y a pas de taille.
Vous devez soit utiliser une taille définie, ou un délimiteur.
En d'autres termes, dans l'enfant, la sortie de la taille de la prochaine sortie comme un int, puis écrire la sortie réelle; dans le parent de vous que vous lisez la taille (c'est un int, il est donc toujours la même taille), puis de lire ce nombre d'octets.
Ou: définir un caractère de fin et jusqu'à ce que vous voyez que, supposons que vous avez besoin de continuer la lecture. Cela peut nécessiter une certaine forme d'échapper à l'/mécanisme de codage, cependant, et ne sera probablement pas aussi vite. Je pense que c'est essentiellement ce que fgets ne.
OriginalL'auteur freiheit
Pourquoi ne pas écrire la longueur dans le tube (dire) le premier " n " octets ? Puis, à l'autre extrémité, vous pouvez lire ces octets, déterminer la longueur, puis lire le nombre d'octets (c'est à dire que vous avez un très simple protocol)
Le cadrage est probablement va être moins douloureux que d'avoir votre pipe briser sur vous.
OriginalL'auteur Brian Agnew
D'autres affiches sont correctes: vous devez avoir un moyen de spécifier la longueur des paquets de vous-même. L'un de béton, moyen pratique de le faire est avec netstrings. Il est simple de créer et d'analyser, et il est pris en charge par certains cadres communs tels que Twisted.
OriginalL'auteur Chris Jester-Young
Vous pouvez essayer en utilisant l'IPC files d'attente de messages si vos messages ne sont pas trop gros.
OriginalL'auteur Tim Williscroft