web-dev-qa-db-fra.com

Comment abandonner BeginReceive () du socket?

Naturellement, BeginReceive() ne se terminera jamais s'il n'y a pas de données. MSDN suggère que l'appel de Close() annulerait BeginReceive().

Cependant, l'appel de Close() sur le socket exécute également une Dispose(), comme indiqué dans ce grand ansewr , et par conséquent EndReceive() lève une exception car l'objet est déjà disposé (et c'est le cas!).

Comment dois-je procéder?

39
Day_Dreamer

Il semble que ce soit par la conception (le très stupide). Vous devez avoir cette exception lancée et capturée dans votre code. 

MSDN semble silencieux à ce sujet, mais si vous consultez la documentation d'une autre méthode de socket asynchrone, BeginConnect () , voici ce que nous trouvons:

Pour annuler un appel en attente de la méthode BeginConnect (), fermez le socket . Lorsque la méthode Close () est appelée Alors qu'une opération asynchrone Est en cours, le rappel fourni À la méthode BeginConnect () est appelé . Un appel ultérieur à la méthode EndConnect (IAsyncResult) lançera une exception ObjectDisposedException sur Indiquant que l'opération a été annulée.

Si c’est la bonne façon de procéder pour BeginConnect, il en va probablement de même pour BeginReceive. Ceci est certainement une mauvaise conception de la part de l'API asynchrone de Microsoft, car le fait de forcer l'utilisateur à lancer et à saisir une exception comme faisant partie d'un flux normal gênerait le débogueur. Vous n'avez vraiment aucun moyen "d'attendre" jusqu'à la fin de l'opération, parce que Close () est ce qui la complète en premier lieu.

47
Pavel Radzivilovsky

Je suis surpris que personne n'ait recommandé d'utiliser SocketOptions.

Une fois que la pile est en mode d'envoi ou de réception, elle est liée aux options de socket du socket. 

Utilisez un petit délai d’envoi ou de réception et utilisez-le avant l’opération afin de ne pas vous soucier de le modifier au cours de la même opération. 

Cela provoquera plus de changement de contexte mais ne nécessitera pas la fermeture du socket sous aucun protocole. 

Par exemple:

1) Définir un petit délai d'attente

2) Effectuer des opérations

3) Définir le délai d'attente plus grand

Ceci est similaire à l'utilisation de Blocking = false mais avec un délai automatique que vous spécifiez. 

2
Jay

Vous pouvez lire ma solution de ce problème ici (en utilisant le commentaire de Pavel Radzivilovsky ici): UdpClient.ReceiveAsync résiliation précoce correcte

0
EgoPingvina

Pour TCP connexions de socket, vous pouvez utiliser la propriété Connected pour déterminer l'état du socket avant de tenter d'accéder aux méthodes supprimées. Par MSDN:

"La propriété Connected obtient l'état de connexion du Socket à partir de la dernière opération d'E/S. Lorsqu'il renvoie false, le Socket n'a jamais été connecté ou n'est plus connecté."

Puisqu'il dit "n'est plus connecté", cela implique qu'un Close () a déjà été appelé sur le socket. Si vous vérifiez si le socket est connecté au début du rappel de réception, il n'y aura pas d'exception.

0
geekus42