Comment une socket TCP déconnectée peut-elle être détectée de manière fiable à l’aide de MsgWaitForMultipleObjects?

Twisted inclut un réacteur implémenté au-dessus de MsgWaitForMultipleObjects . Apparemment, le réacteur a des problèmes à remarquer quand une connexion TCP se termine, du moins dans le cas où un homologue envoie des octets et ferme rapidement la connexion. Ce qui semble se passer est:

  1. Le réacteur appelle MsgWaitForMultipleObjects avec certaines poignées de socket et QS_ALLINPUT .
  2. L’appel se termine et indique que le descripteur d’un socket dans cet état (c’est-à-dire qu’il a des octets en attente de lecture et qu’il a été fermé par l’homologue) est actif.
  3. Le réacteur envoie cette notification à l’implémentation commune de TCP.
  4. L’implémentation TCP lit les octets disponibles dans le socket. Il y en a, ils sont livrés au code de l’application.
  5. Le contrôle est renvoyé au réacteur, qui appelle à nouveau MsgWaitForMultipleObjects .
  6. MsgWaitForMultipleObjects n’indique plus jamais que le handle est actif. L’implémentation TCP ne peut plus jamais regarder le socket, elle ne peut donc jamais détecter la fermeture de la connexion.

Cela le fait apparaître comme si MsgWaitForMultipleObjects est un mécanisme de notification déclenché par les bords. La documentation MSDN dit:

 Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses. 

Cela ne ressemble pas à un déclenchement par front. Cela ressemble à un déclenchement de niveau.

MsgWaitForMultipleObjects est- MsgWaitForMultipleObjects réellement déclenché par le bord? Ou est-il déclenché par un niveau et cette mauvaise conduite est causée par un autre aspect de son comportement?

Addendum Les documents MSDN pour WSAEventSelect expliquent un peu plus ce qui se passe ici, notamment en soulignant que FD_CLOSE est fondamentalement un événement unique. Après sa signalisation une fois, vous ne l’obtiendrez plus jamais. Cela explique en partie pourquoi Twisted a ce problème. Je suis toujours intéressé à savoir comment utiliser efficacement MsgWaitForMultipleObjects étant donné cette limitation, cependant.

Pour utiliser WSAEventSelect et différencier les activités, vous devez appeler WSAEnumNetworkEvents . Assurez-vous de traiter chaque événement signalé, pas seulement le premier.

WSAAsyncSelect facilite la détermination de la cause et est souvent utilisé avec MsgWaitForMultipleObjects .

Vous pouvez donc utiliser WSAAsyncSelect au lieu de WSAEventSelect .

En outre, je pense que vous avez une incompréhension fondamentale de la différence entre déclenchée par le bord et déclenchée par le niveau. Votre raisonnement semble être davantage lié aux événements de réinitialisation automatique et de réinitialisation manuelle.