Comment garantir lecture () envoie en fait 100% des données envoyées par write () à travers des tuyaux nommés

StackOverflow https://stackoverflow.com/questions/904866

  •  05-09-2019
  •  | 
  •  

Question

J'ai les deux programmes, l'un agissant en tant que lecteur et l'autre comme un écrivain suivant. L'écrivain semble envoyer seulement 3/4 des données correctement pour être lues par le lecteur. Est-il possible de garantir que toutes les données sont envoyées? Je pense que je l'ai mis en place afin qu'il lit et écrit de manière fiable, mais il semble encore manquer un quart des données.

Heres la source de l'auteur

#define pipe "/tmp/testPipe"

using namespace std;

queue<string> sproutFeed;


ssize_t r_write(int fd, char *buf, size_t size) {
   char *bufp;
   size_t bytestowrite;
   ssize_t byteswritten;
   size_t totalbytes;

   for (bufp = buf, bytestowrite = size, totalbytes = 0;
        bytestowrite > 0;
        bufp += byteswritten, bytestowrite -= byteswritten) {
      byteswritten = write(fd, bufp, bytestowrite);
            if(errno == EPIPE)
            {
            signal(SIGPIPE,SIG_IGN);
            }
      if ((byteswritten) == -1 && (errno != EINTR))
         return -1;
      if (byteswritten == -1)
         byteswritten = 0;
      totalbytes += byteswritten;
   }
   return totalbytes;
}


void* sendData(void *thread_arg)
{

int fd, ret_val, count, numread;
string word;
char bufpipe[5];


ret_val = mkfifo(pipe, 0777); //make the sprout pipe

if (( ret_val == -1) && (errno != EEXIST)) 
{
    perror("Error creating named pipe");
    exit(1);
}   
while(1)
{
    if(!sproutFeed.empty())
    {
        string s;
        s.clear();
        s = sproutFeed.front();
        int sizeOfData = s.length();
        snprintf(bufpipe, 5, "%04d\0", sizeOfData); 
        char stringToSend[strlen(bufpipe) + sizeOfData +1];
        bzero(stringToSend, sizeof(stringToSend));                  
        strncpy(stringToSend,bufpipe, strlen(bufpipe));         
        strncat(stringToSend,s.c_str(),strlen(s.c_str()));
        strncat(stringToSend, "\0", strlen("\0"));                  
        int fullSize = strlen(stringToSend);            
        signal(SIGPIPE,SIG_IGN);

        fd = open(pipe,O_WRONLY);
        int numWrite = r_write(fd, stringToSend, strlen(stringToSend) );
        cout << errno << endl;
        if(errno == EPIPE)
        {
        signal(SIGPIPE,SIG_IGN);
        }

        if(numWrite != fullSize )
        {               
            signal(SIGPIPE,SIG_IGN);
            bzero(bufpipe, strlen(bufpipe));
            bzero(stringToSend, strlen(stringToSend));
            close(fd);
        }
        else
        {
            signal(SIGPIPE,SIG_IGN);
            sproutFeed.pop();
            close(fd);
            bzero(bufpipe, strlen(bufpipe));
            bzero(stringToSend, strlen(stringToSend));
        }                   
    }
    else
    {
        if(usleep(.0002) == -1)
        {
            perror("sleeping error\n");
        }
    }
}

}

int main(int argc, char *argv[])
{
    signal(SIGPIPE,SIG_IGN);
    int x;
    for(x = 0; x < 100; x++)
    {
        sproutFeed.push("All ships in the sea sink except for that blue one over there, that one never sinks. Most likley because it\'s blue and thats the mightiest colour of ship. Interesting huh?");
    }
    int rc, i , status;
    pthread_t threads[1];       
    printf("Starting Threads...\n");
    pthread_create(&threads[0], NULL, sendData, NULL);
    rc = pthread_join(threads[0], (void **) &status);

}

Heres la source du lecteur

#define pipe "/tmp/testPipe"

char dataString[50000];
using namespace std;
char *getSproutItem();

void* readItem(void *thread_arg)
{
    while(1)
    {
        x++;
        char *s = getSproutItem();
        if(s != NULL)
        {
            cout << "READ IN: " << s << endl;
        }
    }
}


ssize_t r_read(int fd, char *buf, size_t size) {
   ssize_t retval;
   while (retval = read(fd, buf, size), retval == -1 && errno == EINTR) ;
   return retval;
}


char * getSproutItem()
{
    cout << "Getting item" << endl;
    char stringSize[4];
    bzero(stringSize, sizeof(stringSize));
    int fd = open(pipe,O_RDONLY);
    cout << "Reading" << endl;

    int numread = r_read(fd,stringSize, sizeof(stringSize));


    if(errno == EPIPE)
    {
        signal(SIGPIPE,SIG_IGN);

    }
    cout << "Read Complete" << endl;

    if(numread > 1)
    {

        stringSize[numread] = '\0'; 
        int length = atoi(stringSize);
        char recievedString[length];
        bzero(recievedString, sizeof(recievedString));
        int numread1 = r_read(fd, recievedString, sizeof(recievedString));
        if(errno == EPIPE)
        {


signal(SIGPIPE,SIG_IGN);
    }       
    if(numread1 > 1)
    {
        recievedString[numread1] = '\0';
        cout << "DATA RECIEVED: " << recievedString << endl;
        bzero(dataString, sizeof(dataString));
        strncpy(dataString, recievedString, strlen(recievedString));
        strncat(dataString, "\0", strlen("\0"));
        close(fd);  
        return dataString;
    }
    else
    {
        return NULL;
    }

}
else
{
    return NULL;
}

close(fd);

}

int main(int argc, char *argv[])
{
        int rc, i , status;
        pthread_t threads[1];       
        printf("Starting Threads...\n");
        pthread_create(&threads[0], NULL, readItem, NULL);
        rc = pthread_join(threads[0], (void **) &status); 

}
Était-ce utile?

La solution

Vous utilisez certainement des signaux dans le mauvais sens. Les threads sont complètement inutiles ici - au moins dans le code fourni. calculs de cordes sont simplement étranges. Obtenez ce livre et ne touchez pas le clavier jusqu'à ce que vous avez terminé la lecture:)

Autres conseils

La méthode générale utilisée pour envoyer des données à travers des canaux nommés est de virer de bord sur un en-tête avec la longueur de la charge utile. Ensuite, vous lisez (fd, header_len); lecture (RD, data_len); Notez la dernière lecture () devra être fait dans une boucle jusqu'à ce que data_len est lu ou EOF. Notez également si vous avez plusieurs écrivains à un tube nommé alors les écritures sont atomiques (aussi longtemps que d'une taille raisonnable) I.E. plusieurs auteurs ne seront pas de cas des messages partiels dans les tampons du noyau.

Il est difficile de dire ce qui se passe ici. Peut-être que vous avez trouvé une erreur renvoyée d'un de vos appels système? Etes-vous sûr que vous envoyez avec succès toutes les données?

Vous semblez aussi avoir un code invalide ici:

    int length = atoi(stringSize);
    char recievedString[length];

Ceci est une erreur de syntaxe, puisque vous ne pouvez pas créer un tableau sur la pile en utilisant une expression non constanct pour la taille. Peut-être que vous utilisez un code différent dans votre version réelle?

Avez-vous besoin de lire les données dans une boucle? Parfois, une fonction renvoie une partie des données disponibles et vous avez besoin d'appeler plusieurs fois jusqu'à ce que toutes les données a disparu.

Certains appels système Unix peut également revenir EAGAIN si l'appel système est interrompu -. Vous manipulez pas ce cas par les regards des choses

Vous êtes peut-être piqué par une sémantique de gestion du signal de fil posix thread principal du lecteur. La norme POSIX permet un fil POSIX pour recevoir le signal, pas nécessairement le fil que vous attendez. signaux de bloc où pas voulu. signal(SIG_PIPE,SIG_IGN) est votre ami. Ajouter un à principal lecteur.

sémantique POSIX de manipulation de fil, mettre le point de vente dans POSIX. (Mais il ne le rendre plus facile à mettre en œuvre des threads POSIX.)

Examinez le tuyau dans / tmp avec ls? est-il pas vide?

scroll top