7
votes

Mettre fin à un fil en toute sécurité lorsque vous utilisez UDP Recevoir

Je crée un fil qui exécute un client UDP qui reçoit un message, après avoir reçu le message, je souhaite fermer le client UDP, puis mettre fin au fil, mais je ne sais pas comment mettre fin à la fin du fil depuis "recevoir" fonctionne toujours jusqu'à ce qu'il obtienne une réponse.

Ceci est mon code jusqu'à présent: xxx

La ligne importante est client.receive (REF ROISTIP); < p> Voici comment je démarre mon fil: xxx


1 commentaires

Donc, ais la question que vous voulez qu'il tient de temps en temps? Sinon, une fois que cela reçoit les données, le thread va quitter proprement.


5 Réponses :


2
votes

au lieu de recevoir () , vous pouvez utiliser beginReceive () / endreceive () - c'est une alternative asynchrone.

Voir MSDN: http: // msdn .microsoft.com / fr-US / US / Bibliothèque / system.net.sockets.udpclient.beginreceive.aspx

Ces méthodes utilisent un APM commun (modèle de programmation asynchrone) de .NET.


0 commentaires

7
votes

client.receive code> retournera un octet vide vide [] code> lorsque la connexion est fermée. Vous devriez simplement devoir fermer la connexion et modifier le code fourni sur:

private void RecieveChallenge()
{
    UdpClient client = new UdpClient(26000);
    IPEndPoint remoteIp = new IPEndPoint(IPAddress.Any, 0);

    Byte[] receivedBytes = client.Receive(ref remoteIp);
    if (receivedBytes == null || receivedBytes.Length == 0)
        return;
    string ipAddress = Encoding.ASCII.GetString(receivedBytes);
}


16 commentaires

Où dit-il qu'il retournera NULL? Une socketException ou ObjectDisposedException sera lancée si elle est fermée tout en essayant de recevoir.


@Brad - ce serait vrai si vous essayez de lire à partir d'une prise déjà disposée (alors qu'elle est disposée), bien que si vous attendez déjà une réponse, je pense que cela retournera un octet vide [] < / code>. Je sais que cela est vrai pour la classe sous-jacente au moins.


@ M.Babcok Je suis presque positif, il sera lancé une exception comme il bloque jusqu'à ce qu'il reçoive des données. Par conséquent, le thread fonctionnera que si vous tuez le fil ou la prise, qui sera ensuite lancé une exception.


Ceci n'est pas sûr. Il n'y a aucune garantie qu'il est prudent de fermer le point final dans un fil tandis qu'un autre point final est sur le point de l'utiliser. (Au moins, personne que je connaisse.)


@Brad - Comme je l'ai dit dans mon précédent commentaire, je sais que cela fonctionne de cette façon dans la classe sous-jacente classe. Je ne peux pas commenter directement sur le comportement du udpclient . Vous pourriez avoir raison cependant.


@ M.Babcock udpclient est juste une enveloppe autour de la prise. Ceci est basé sur la source de référence ( référencesSource.microsoft.com/netframework.aspx ).


@Davidschwartz - J'en ai utilisé plusieurs fois dans diverses applications de production à l'aide de la classe avec succès. Je ne peux pas commenter directement le comportement udpclient cependant. Si vous avez une alternative plus sûre, n'hésitez pas à partager.


@Brad - Je suis au courant de la façon dont la hiérarchie fonctionne. Cela ne signifie pas que le comportement de cette situation serait différent cependant.


Il y a beaucoup d'autres moyens. Un moyen simple est de définir un drapeau "arrêt" que le fil vérifie après chaque appel retenu à recevoir. Ensuite, vous définissez le drapeau d'arrêt et envoyez un datagramme UDP à vous-même. (Que cela fonctionne avec succès lorsque vous avez essayé, cela n'a pas de sens. Cela pourrait échouer sur la prochaine version du compilateur, du système d'exploitation, de la bibliothèque TCP / IP, ou même de la CPU pour tout ce que nous savons. "Cela fait fonctionner quand je l'ai testé" nous peu importe la correction ou la fiabilité du code.)


@Davidschwartz - Je voulais les proposer à l'OP. N'hésitez pas à prendre la réponse si vous en avez un meilleur.


Bien que j'ai suggéré de commencer à botterreceive / endreceive dans ma réponse, je dois dire que cette solution de M.Babcock me semble correcte. Un objet de socket sous-jacent +1 est accessible à partir d'autres threads à tout moment, il est donc légal de le fermer à partir d'un autre fil, et cela obligera en fait la méthode de recueillir bloquée à la fin. Et cette approche est propre.


Ce code fonctionne bien, le seul problème que je vois est que si je ne reçois pas un message, le thread continuera de fonctionner même si j'ai fermé mon programme. Comment allais-je aller à ce sujet si je ne reçois pas de message?


@Dumpen - vous avez quelques options différentes. La voie sale (qui ne tuera pas votre fil gracieusement) serait de régler le fil comme un fil de premier plan ( thread.isbackground = false ) ou le moyen de nettoyage, mettez le recevoir dans une boucle et ajoutez un délai de réception ( .SetsocktOption (SocketOptionVelvel.socket, SocketOptionName.RecefetimeTout, 5000); ). Vous devrez également ajouter un essai / attraper sur le recevoir pour attraper l'exception du délai d'attente si vous allez avec la voie propre. Voici un fil sur celui-ci: social.msdn.microsoft.com/forums/en-us/netfxnetcom/thread/...


@ M.babcock alors quelque chose comme ça? Pastebin.com/sfwq7Jcu (désolé pour le lien Pastebin, mais il y a beaucoup de code)


@Dumpen - pas exactement. Le retour de la capture entraînera le retour du thread après la première poussée d'inactivité (lorsqu'il n'y a aucun message n'est reçu). Vous voudrez changer cela en un continuer (ou ne rien faire dans la capture du tout - même effet). Puis au lieu de la evil tandis que (vrai) vous souhaitez vérifier un drapeau qui ne doit être défini que sur true lorsque le programme ferme .


@Dumpen - C'est beaucoup mieux, mais il y a encore quelques défauts potentiels. Voici votre code à nouveau avec quelques suggestions commentées: Pastebin.com/m7jjkl3n



2
votes

Si vous souhaitez attendre qu'il soit terminé avant de continuer sur votre thread actuel, vous pouvez utiliser

recieveDataThread.Abort(); 


0 commentaires

1
votes

Je cherchais une bonne réponse et je remercie des conseils de collègue que j'ai faits suite à la solution suivante (semble fonctionner correctement) xxx

pour arrêter de régler _monitoringTheadisRunning sur false. Cela fonctionne sans aucune exception.


0 commentaires

0
votes

Une amélioration de la solution ci-dessus de JACEK utilise une seconde boucle; Ce faisant un délai ne jette pas un datagramme éventuel reçu à l'heure actuelle un incendie de délai (le code d'origine appelle à un autre reçu à chaque fois-éteignant en ignorant toute réception en cours):

while (_monitoringThreadIsRunning {        
    var receiveTask = _udpClient.ReceiveAsync();                
    while (_monitoringThreadIsRunning {        
        var timeoutTask = Task.Delay(ReceiveTimeout);
        if (timeoutTask == await Task.WhenAny(timeoutTask, receiveTask))
            continue;
        UdpReceiveResult udpReceiveResult = await receiveTask;
        // handle udpReceiveResult.Buffer
        break; // return to outer loop, launching another Receive
    }
}


0 commentaires