Comment déterminer s'il n'y a plus de données à lire dans un flux réseau?

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

  •  02-07-2019
  •  | 
  •  

Question

J'ai une application Web qui se connecte à un serveur à l'aide d'une connexion TCP et lit un document binaire qu'il écrit ensuite dans son objet de réponse. En d’autres termes, il transfère un fichier depuis un serveur principal en utilisant un protocole personnalisé et le renvoie à son client via HTTP.

Le serveur envoie un code d'état et un type mime, que j'ai lu avec succès, puis écrit le contenu du fichier et ferme le socket. Cela semble bien fonctionner.

Le client (une application Web C #) lit les données:

     private NetworkStream stream_;

     public void WriteDocument(HttpResponse response)
     {
        while (stream_.DataAvailable)
        {
           const int bufsize = 4 * 1024;
           byte[] buffer = new byte[bufsize];
           int nbytes = stream_.Read(buffer, 0, bufsize);
           if (nbytes > 0)
           {
              if (nbytes < bufsize)
                 Array.Resize<byte>(ref buffer, nbytes);
              response.BinaryWrite(buffer);
           }
        }
        response.End();
     }

Cela semble toujours quitter la boucle de lecture avant que toutes les données soient arrivées. Qu'est-ce que je fais mal?

Était-ce utile?

La solution

Je voudrais utiliser OutputStream directement avec une fonction polyvalente. Avec Stream , vous pouvez contrôler Flush .

    public void WriteDocument(HttpResponse response) {
        StreamCopy(response.OutputStream, stream_);
        response.End();
    }

    public static void StreamCopy(Stream dest, Stream src) {
        byte[] buffer = new byte[4 * 1024];
        int n = 1;
        while (n > 0) {
            n = src.Read(buffer, 0, buffer.Length);
            dest.Write(buffer, 0, n);
        }
        dest.Flush();
    }

Autres conseils

Voici ce que je fais. Habituellement, la longueur du contenu est souhaitée pour savoir quand mettre fin à la boucle de stockage de données. Si votre protocole n'envoie pas la quantité de données attendue comme en-tête, il doit alors envoyer un marqueur pour signaler la fin de la transmission.

La propriété DataAvailable indique simplement s’il ya des données à lire à partir du socket MAINTENANT, elle ne sait pas (et ne peut pas) savoir s’il ya plus de données à envoyer ou non. Pour vérifier que le socket est toujours ouvert, vous pouvez tester stream_.Socket.Connected & amp; & amp; stream_.Socket.Readable

    public static byte[] doFetchBinaryUrl(string url)
    {
        BinaryReader rdr;
        HttpWebResponse res;
        try
        {
            res = fetch(url);
            rdr = new BinaryReader(res.GetResponseStream());
        }
        catch (NullReferenceException nre)
        {
            return new byte[] { };
        }
        int len = int.Parse(res.GetResponseHeader("Content-Length"));
        byte[] rv = new byte[len];
        for (int i = 0; i < len - 1; i++)
        {
            rv[i] = rdr.ReadByte();
        }
        res.Close();
        return rv;
    }

Je ne sais pas comment les choses fonctionnent dans .Net, mais dans la plupart des environnements dans lesquels j'ai travaillé, Read () renvoie 0 octet lorsque la connexion est fermée. Donc, vous feriez quelque chose comme:

char buffer[4096];
int num_read;

while ( num_read = src.Read(sizeof(buffer)) > 0 )
{
   dst.Write(buffer, num_read);
}

La racine de votre problème est cette ligne:

while (stream_.DataAvailable)

DataAvailable signifie simplement qu'il y a des données dans la mémoire tampon de flux prêtes à être lues et traitées. Il ne fait aucune garantie quant à la «fin» du flux ayant été atteinte. En particulier, DataAvailable peut être false s'il y a une pause dans la transmission ou si votre expéditeur est plus lent que votre lecteur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top