2017-04-03 1 views
-1

J'ai trouvé beaucoup de fils ici demandant comment il est possible de rincer un tuyau après l'avoir écrit sans le fermer. Dans chaque thread, je pouvais voir différentes suggestions, mais je ne pouvais pas trouver une solution définitive.Tuyau de rinçage sans fermeture en C

Voici un résumé rapide:

  1. La meilleure façon d'éviter le blocage de lire sur le tuyau serait d'écrire le nombre exact d'octets qui est en train de lire. Il pourrait également être fait en utilisant ptmx au lieu d'un tuyau, mais les gens ont dit que cela pourrait être beaucoup.

Note: Il est impossible d'utiliser fsync avec des tuyaux

Y at-il d'autres solutions plus efficaces?

Edit:

La chasse serait pratique lorsque l'expéditeur veut écrire des caractères n mais le client lit les caractères m (où m> n). Le client bloquera l'attente d'autres caractères m-n. Si l'expéditeur veut communiquer à nouveau avec le client, il ne peut plus fermer le tube et envoyer juste le nombre exact d'octets pourrait être une bonne source de bugs.

Le récepteur fonctionne comme celui-ci et il ne peut pas être modifié:

while((n=read(0, buf, 100)>0){ 
    process(buf) 

si l'expéditeur veut faire traiter: « fichier1 » et « fichier2 » pour qui devra:

write(pipe[1], "file1\0*95", 100); 
write(pipe[1], "file2\0*95", 100); 

ce que je cherche est un moyen de faire quelque chose comme ça (sans être nécessaire d'utiliser le \ n comme le délimiteur):

write(pipe[1], "file1\nfile2", 11); //it would have worked if it was ptmx 

(Utilisation de lecture et d'écriture)

+2

Cela ressemble beaucoup à un [problème X-Y] (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). D'une manière générale, il n'y a pas besoin de vider une pipe, alors quel est le vrai problème? –

+0

Et que voulez-vous dire par "pts"? –

+0

@John: Je parlais de pseudoterminal maître/esclave.J'ai mis à jour le message original. –

Répondre

1

Le rinçage au sens de fflush() n'est pas pertinent pour les tubes, car ils ne sont pas représentés comme des flux C. Il n'y a donc pas de tampon utilisateur à vider. De même, fsync() est également sans importance pour les tuyaux, car il n'y a pas de stockage back-end pour les données. Les données écrites avec succès dans un canal existent dans le noyau et seulement dans le noyau jusqu'à ce qu'elles soient lues avec succès, donc il n'y a pas de travail à faire pour fsync(). Dans l'ensemble, le rinçage/la synchronisation n'est applicable que lorsqu'il y a un stockage intermédiaire impliqué, ce qui n'est pas le cas avec les tuyaux. Avec la clarification, votre question semble être d'établir des limites de message pour la communication via un tuyau. Vous avez raison de dire que la fermeture de l'extrémité d'écriture du tuyau indiquera une limite - pas seulement d'un message, mais de tout le flux de communication - mais bien sûr c'est définitif. Vous avez également raison de dire qu'il n'y a pas de limites inhérentes au message. Cependant, vous semblez travailler à partir d'au moins un peu d'une idée fausse ici:

La meilleure façon d'éviter le blocage lire sur la conduite serait d'écrire le nombre exact d'octets qui est en train de lire.

[...]]

Le vidage serait pratique lorsque l'expéditeur veut écrire n caractères mais le client lit m caractères (où m> n). Le client bloquera l'attente d'autres caractères m-n. Le fait que le lecteur bloquera dépend entièrement de la façon dont le lecteur est mis en œuvre.

En particulier, l'appel système read(2) ne garantit en aucun cas le transfert du nombre d'octets demandé avant le retour. Il peut et va effectuer une lecture courte dans certaines circonstances. Bien que les détails ne soient pas spécifiés, vous pouvez généralement compter sur une lecture courte quand au moins un caractère peut être transféré sans bloquer, mais pas le nombre entier demandé. La même chose s'applique à write(2). Ainsi, le moyen le plus simple d'éviter le blocage read() consiste à s'assurer que vous écrivez au moins un octet au canal pour cet appel read() à transférer. En fait, les gens abordent généralement ce problème en sens inverse: il faut être sûr de recevoir un nombre spécifique d'octets, et donc avoir à faire face au potentiel de lectures courtes comme une complication (à traiter par effectuer le read() dans une boucle). Vous devrez également prendre cela en considération, mais vous avez l'avantage que votre client ne bloquera probablement pas dans les circonstances que vous décrivez; Ce n'est pas le problème que vous croyez.

Cependant, il existe un problème inhérent de message-limite dans tout type de communication de flux, et vous devrez y faire face. Il y a plusieurs approches; parmi les plus couramment utilisés sont

  • messages de longueur fixe. Le récepteur peut alors lire jusqu'à ce qu'il transfère avec succès le nombre d'octets requis; tout blocage impliqué est approprié et nécessaire. Avec cette approche, le scénario que vous postulez ne se pose tout simplement pas, mais l'auteur peut avoir besoin de remplir ses messages.

  • Messages délimités. Le récepteur lit ensuite jusqu'à ce qu'il trouve qu'il a reçu un délimiteur de message (un saut de ligne ou un octet nul, par exemple). Dans ce cas, le récepteur devra être préparé pour la possibilité que les limites de message ne soient pas alignées avec les séquences d'octets transférées par les appels read(). Marquer la fin d'un message en fermant le canal peut être considéré comme un cas particulier de cette alternative.

  • Métadonnées de longueur de message incorporées. Cela peut prendre de nombreuses formes, mais l'une des plus simples consiste à structurer les messages en un champ de longueur de message entier de longueur fixe, suivi du nombre d'octets de données de message. Le lecteur sait alors à chaque point combien d'octets il doit lire, donc il ne bloquera pas inutilement.

Elles peuvent être utilisées individuellement ou en combinaison pour implémenter un protocole de couche d'application pour la communication entre vos processus. Naturellement, les parties à la communication doivent s'entendre sur les détails du protocole pour que la communication soit couronnée de succès.

+0

Merci pour la réponse. J'ai ajouté quelques notes à ma question initiale, mais ce que je cherche est la réponse à ceci: 'Il peut et effectuera une lecture courte dans certaines circonstances. Quelles sont ces circonstances? –

+0

@AntonisParagas, je l'ai déjà abordé cette question dans ma réponse à la mesure du possible: « Bien ** les détails ne sont pas spécifiés **, vous pouvez habituellement compter sur une courte lecture lorsqu'au moins un caractère peut être transféré sans bloquer, mais pas le nombre entier demandé. " Autrement dit, 'read()' ne bloquera normalement pas lorsqu'il peut transférer au moins un octet. –