2012-10-16 3 views
1

de situation simple:Comment déterminer la fin d'un transfert de fichiers (données) du client vers le serveur (Socket)

Le client sur un Socket envoie une pièces (par exemple, 256 octets) du fichier (données) au format byte [] au serveur. Le serveur reçoit les données de manière asynchrone. Comment déterminer quand un fichier (données) est transmis complètement? (Côté serveur)

Voici le code sur le serveur côté responsable de la réception des données

public static void ReadCallback(IAsyncResult ar) 
{ 
     String content = String.Empty; 

     // Retrieve the state object and the handler socket 
     // from the asynchronous state object. 
     StateObject state = (StateObject)ar.AsyncState; 
     Socket handler = state.workSocket; 


     // Read data from the client socket. 
     int bytesRead = handler.EndReceive(ar); 

     if (bytesRead > 0) 
     { 

      BinaryWriter writer = new BinaryWriter(File.Open(@"D:\test.png", FileMode.Append)); 

      writer.Write(state.buffer, 0, bytesRead); 
      writer.Close(); 

      // All the data has been read from the 
      // client. Display it on the console. 
      Console.WriteLine("Read {0} bytes from socket!", 
       bytesRead); 

      handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
       new AsyncCallback(ReadCallback), state); 
     } 
} 

Y at-il une méthode qui permet de faire les quelques-uns qui suit?

if (bytesRead > 0) 
{ 

    .... 
    if(state.buffer!=end of receive) 
    { 
    handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
     new AsyncCallback(ReadCallback), state); 
    } 

} 

Ou, je peux essayer d'ajouter des informations à cet objet byte[] (par exemple, une chaîne de caractères avec étiquette <EOF>) mais je dois analyser cette information sur chaque étape. Puis-je faire cette vérification plus simple et comment? Ou utilisez une autre manière ...

+4

Envoyer la taille du fichier avant d'envoyer le fichier. –

+0

Je voudrais faire toutes les actions en une étape, si possible – chromigo

Répondre

0

La seule façon de le faire est d'envoyer un en-tête (de taille spécifique) devant chaque message. Ainsi, chaque message devrait être composé d'en-tête et de corps. Le flux de données devrait ressembler à ceci:

[HEADER] [CORPS] [HEADER] [QUELQUES BIGGER CORPS] [HEADER] [QUELQUES EXTRA GRAND CORPS]

Comme je l'ai dit, l'en-tête doit être de taille spécifique et devrait contenir quelques champs de service personnalisés incluant la taille du corps du message en octets. Dans votre cas, l'en-tête ne peut contenir que la taille du corps, c'est-à-dire la valeur int (4 octets). Le processus de réception doit ressembler à ceci:

  1. Recevoir 4 octets (en-tête);
  2. Récupère la taille du corps de l'en-tête (il suffit de convertir l'en-tête en entier);
  3. Recevoir le nombre d'octets spécifié dans l'en-tête (c'est-à-dire recevoir le corps du message);
  4. Gérer le corps du message;
  5. Aller à 1.

Je sais, il peut sembler compliqué pour vous, mais il est la façon courante de le faire. Mais vous pouvez simplifier le code en utilisant Rx library. Après la mise en œuvre des méthodes d'extensions pour socket (WhenReadExact, la mise en œuvre pourrait être facilement trouvé sur Internet, par exemple here), le code ressemblera à ceci:

var whenFileReceived = from header in socket.WhenReadExact(4) 
         let bodySize = BitConverter.ToInt32(header) 
         from body in socket.WhenReadExact(bodySize) 
         select body; 

whenFileReceived.Subscribe(
    file => 
    { 
     // Handle file here 
    }); 
Questions connexes