2009-06-18 2 views
4

Je développe une application simple pour envoyer des fichiers sur TCP en utilisant les classes TCPListener et TCPClient. Voici le code qui envoie le fichier.Comment envoyer des fichiers sur TCP avec TcpListener/Client? Problème SocketException

Stop est un booléen volatile qui aide à arrêter le processus à tout moment et WRITE_BUFFER_SIZE pourrait être modifié dans l'exécution (autre volatile)

while (remaining > 0 && !stop) 
{ 
    DateTime current = DateTime.Now; 
    int bufferSize = WRITTE_BUFFER_SIZE; 
    buffer = new byte[bufferSize]; 
    int readed = fileStream.Read(buffer, 0, bufferSize); 
    stream.Write(buffer, 0, readed); 
    stream.Flush(); 
    remaining -= readed; 
    // Wait in order to guarantee send speed 
    TimeSpan difference = DateTime.Now.Subtract(current); 
    double seconds = (bufferSize/Speed); 
    int wait = (int)Math.Floor(seconds * 1000); 
    wait -= difference.Milliseconds; 
    if (wait > 10) 
    Thread.Sleep(wait); 
}     
stream.Close(); 

ce qui est le code qui gère le côté récepteur:

do 
{ 
    readed = stream.Read(buffer, 0, READ_BUFFER_SIZE); 
    // write to .part file and flush to disk 
    outputStream.Write(buffer, 0, readed); 
    outputStream.Flush(); 
    offset += readed; 
} while (!stop && readed > 0); 

Maintenant, lorsque la vitesse est faible (environ 5 Kbits/s), tout fonctionne bien mais, à mesure que j'augmente la vitesse, la taille du récepteur devient plus encline à déclencher une exception SocketException lors de la lecture du flux. Je suppose que cela a à voir avec le socket distant étant fermé avant que toutes les données peuvent être lues, mais quelle est la bonne façon de faire cela? Quand dois-je fermer le client expéditeur?

Je n'ai pas trouvé de bons exemples de transmission de fichiers sur google, et ceux que j'ai trouvés ont une implémentation similaire de ce que je fais donc je suppose que je manque quelque chose.

Modifier: Je reçois cette erreur "Impossible de lire les données de la connexion de transport". C'est une exception IOException dont l'exception interne est une exception SocketException. J'ai ajouté ceci dans la fonction d'expéditeur, j'obtiens toujours la même erreur, le code n'atteint jamais le stream.close() et bien sûr le tcpclient ne se ferme jamais vraiment ... donc je suis complètement perdu maintenant .

buffer = new byte[1]; 
client.Client.Receive(buffer); 
stream.Close(); 
+0

L'expéditeur est-il le client? – grieve

+0

En fait, l'application est à la fois client et serveur. Actuellement, je transfère de l'application à elle-même, alors oui, le client est l'expéditeur. –

Répondre

1

Généralement, vous souhaitez définir l'option LINGER sur le socket. Sous C++, ce serait SO_LINGER, mais sous Windows cela ne fonctionne pas comme prévu. Vous voulez vraiment faire ceci:

  • Terminer l'envoi de données.
  • arrêt d'appel() avec le paramètre comment à 1.
  • boucle sur recv() jusqu'à ce qu'il retourne 0.
  • Appel closesocket().

Extrait de: http://tangentsoft.net/wskfaq/newbie.html#howclose

C# peut avoir corrigé cette forte dans ses bibliothèques, mais je en doute, car ils sont construits au-dessus de l'API Winsock.

Edit:

En regardant votre code plus en détail. Je vois que vous n'envoyez aucun en-tête, donc du côté réception, vous n'avez aucune idée du nombre d'octets que vous êtes censé lire. Connaître le nombre d'octets à lire de la socket rend ce problème beaucoup plus facile à déboguer. Gardez à l'esprit que l'arrêt de la socket peut encore couper le dernier bit de données si vous ne le fermez pas correctement. De plus, le fait que votre taille de buffer soit volatile n'est pas sûr pour les threads et ne vous achètera vraiment rien. Utiliser stop comme volatile est sûr, mais ne vous attendez pas à ce qu'il soit instantané. En d'autres termes, la boucle peut s'exécuter plusieurs fois avant d'obtenir la valeur d'arrêt actualisée. Cela est particulièrement vrai sur les machines multiprocesseurs.

Edit_02:

Pour la TCPClientClass vous voulez faire ce qui suit (pour autant que je peux dire sans avoir accès à un C# pour le moment).

// write all the bytes 
// Then do the following 

client.client.Shutdown(Shutdown.Send) // This assumes you have access to this protected member 
while (stream.read(buffer, 0, READ_BUFFER_SIZE) != 0); 
client.close() 
+0

LingerState ne fonctionne pas, j'ai essayé ... :(Je vais essayer le reste des suggestions ... –

+0

Il y a des informations d'en-tête envoyées, je l'ai pris pour la question Arrêter fonctionne car je ne m'inquiète pas si je boucle 3 ou 4 fois avant de quitter la boucle, il est là pour permettre au thread principal de signaler aux threads en cours d'exécution d'arrêter l'envoi ou la réception. –

Questions connexes