Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Petit problème de socket...

10 réponses
Avatar
Arnold McDonald \(AMcD\)
Salut.

J'ai un socket pour lequel je règle le filtre de message que je veux
receptionner ainsi :

WSAAsyncSelect(Socket,hWdw,WM_CLIENT_SOCKET,FD_CONNECT|FD_CLOSE|FD_READ);

Tout fonctionne bien, sauf que en debugguant je me rends compte qu'en fait
je ne reçois jamais le FD_CLOSE.

Quand et comment reçoit-on cette notification ? shutdown(), closesocket(),
etc. Rien n'y fait, impossible de recevoir ce FD_CLOSE !

Gni ?

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/

10 réponses

Avatar
Dominique Vaufreydaz
Salut,

J'ai un socket pour lequel je règle le filtre de message que je veux
receptionner ainsi :
WSAAsyncSelect(Socket,hWdw,WM_CLIENT_SOCKET,FD_CONNECT|FD_CLOSE|FD_READ);
Tout fonctionne bien, sauf que en debugguant je me rends compte qu'en
fait je ne reçois jamais le FD_CLOSE.



Il me semble (a verifier) que l'on recoit close quand l'autre partie
termine la connexion.

Quand et comment reçoit-on cette notification ? shutdown(),
closesocket(), etc. Rien n'y fait, impossible de recevoir ce FD_CLOSE



As-tu la main sur l'autre partie ? Qui fait le shutdown dans ton cas ?
Perso, si c'est mon applie qui ferme sa socket, je ne m'attends pas
a ce que le systeme me previennent que je viens de la fermer.

A verifier en tout cas. Doms.
Avatar
Christophe Leitienne
Salut,

J'ai un socket pour lequel je règle le filtre de message que je veux
receptionner ainsi :

WSAAsyncSelect(Socket,hWdw,WM_CLIENT_SOCKET,FD_CONNECT|FD_CLOSE|FD_READ);

Tout fonctionne bien, sauf que en debugguant je me rends compte qu'en fait
je ne reçois jamais le FD_CLOSE.

Quand et comment reçoit-on cette notification ? shutdown(), closesocket(),
etc. Rien n'y fait, impossible de recevoir ce FD_CLOSE !

Gni ?




Il semble que l'on ne reçoive FD_CLOSE que si l'autre paire ferme la
socket, ou que l'on fasse un shutdown. Dans le MSDN, je trouve: FD_CLOSE
is not posted after closesocket is called (ce qui me paraît assez
logique, puisqu'on n'aura plus de descripteur à ce moment là).

J'ai vérifié dans un bout de code où j'utilise WSAAsyncSelect, et j'ai
remarqué:
- que je faisait un shutdown(socket, SD_BOTH) avant un closesocket (ça
doit me permettre de reçevoir le FD_CLOSE quand je ferme la socket de
mon propre chef).
- que même après avoir reçu un FD_CLOSE, je tente de lire (recv)
d'éventuelles données restantes (cf. MSDN: FD_CLOSE should only be
posted after all data is read from a socket, but an application should
check for remaining data upon receipt of FD_CLOSE to avoid any
possibility of losing data).

Je me souviens très bien avoir passé des heures à essayer de comprendre
la doc MSDN concernant l'utilisation de WSAAsyncSelect
(http://msdn2.microsoft.com/en-us/library/ms741540.aspx).

Christophe.
Avatar
Arnold McDonald \(AMcD\)
Je réponds à vous deux hein.

Il semble en fait que le FD_CLOSE ne soit effectivement reçu que lorsque la
seconde partie de la connexion est interrompue, terminée, fermée, etc. Je
viens de tracer le tout et c'est conforme a votre remarque. OK, un problème
de réglé.

Je ne parviens toutefois pas à recevoir un FD_CLOSE si c'est moi qui ferme
le socket. Je ne trouve pas cela très logique ! Une fois le closesocket()
exécuté, on devrait auparavant recevoir ce FD_CLOSE pour faire un éventuel
dernier recv(), ce qui est d'ailleurs préconisé dans la doc MSDN de
shutdown(). Je suis bien d'accord. Mais si on reçoit pas ce FD_CLOSE...

Bref. Quel que soit le paramétrage de shutdown(), je ne reçois pas de
FD_CLOSE si c'est moi qui clôture. Vais fouiller MSDN et le Net, je vous
tiens au courant.

Merci à vous deux.

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
Christophe Leitienne
Arnold McDonald (AMcD) a écrit :

Je ne parviens toutefois pas à recevoir un FD_CLOSE si c'est moi qui ferme
le socket. Je ne trouve pas cela très logique ! Une fois le closesocket()
exécuté, on devrait auparavant recevoir ce FD_CLOSE pour faire un éventuel
dernier recv(), ce qui est d'ailleurs préconisé dans la doc MSDN de
shutdown(). Je suis bien d'accord. Mais si on reçoit pas ce FD_CLOSE...




J'ai regardé à nouveau mon code. En fait pour fermer la connexion, je
fais simplement shutdown(socket, SD_BOTH). Je reçois ensuite un
événement FD_CLOSE, dans lequel j'appelle closesocket.

Christophe
Avatar
Arnold McDonald \(AMcD\)
Christophe Leitienne wrote:
Arnold McDonald (AMcD) a écrit :



J'ai regardé à nouveau mon code. En fait pour fermer la connexion, je
fais simplement shutdown(socket, SD_BOTH). Je reçois ensuite un
événement FD_CLOSE, dans lequel j'appelle closesocket.



Oui, moi aussi, sauf que... debuggue et regarde, le code n'y passe jamais si
c'est toi qui côture localement ! En parcourant le MSDN sur FD_CLOSE :

- The FD_CLOSE message is posted when a close indication is received for the
*virtual circuit* corresponding to the socket.

- Be aware that the application will only receive an FD_CLOSE message to
indicate closure of a *virtual circuit*, and only when all the received data
has been read if this is a graceful close.

- Note FD_CLOSE is not posted after closesocket is called.

Ou encore, toujours au sujet de la reception de FD_CLOSE :

- After *remote system* initiated graceful close, when no data currently
available to receive.

On peut donc en déduire que si on ferme localement le socket, on ne recevra
pas de FD_CLOSE. Seulement voilà, on trouve également ça dans le MSDN,
toujours au sujet de la reception de FD_CLOSE :

- After *local system* initiates graceful close with shutdown and remote
system has responded with "End of Data" notification (for example, TCP_FIN).

Et voilà mon problème ! Normalement, donc, en utilisant
shutdown(socket,SD_BOTH) on est donc censé recevoir ce FD_CLOSE. Bah non...
Ou alors, est-ce parce que le remote n'envoie pas de "End of data" ?

Pourtant, je ne suis pas idiot, si je lis bien le MSDN :

To assure that all data is sent and received on a connected socket before it
is closed, an application should use shutdown to close connection before
calling closesocket. For example, to initiate a graceful disconnect:

1 - Call WSAAsyncSelect to register for FD_CLOSE notification.
2 - Call shutdown with how=SD_SEND.
3 - When FD_CLOSE received, call recv until zero returned, or SOCKET_ERROR.
4 - Call closesocket.

Ouaip, mais bon, si l'étape 2 n'arrive jamais...

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
Arnold McDonald \(AMcD\)
Bon, j'ai finalement trouvé, au temps pour moi...

En fait, le shutdown(socket,SD_BOTH) doit être placé un certain temps
*avant* le closesocket(socket), et là, ça fonctionne.

Exemple, je fais un shutdown() et j'attends, disons 10" *avant* de traiter
mon WM_CLOSE et de faire le closesocket() etc., là le socket reçoit bien le
FD_CLOSE.

Mais si je fait mon shutdown() *dans* le traitement de mon WM_CLOSE, alors
le socket n'a jamais le temps de recevoir le FD_CLOSE.

Bref, des problèmes de timeout, quoi... Autrement dit, un shutdown() dans un
WM_CLOSE n'aura aucun intérêt si ce n'est théorique.

Vive les joies de la programmation Winsock.

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
Christophe Leitienne
Arnold McDonald (AMcD) a écrit :
Bon, j'ai finalement trouvé, au temps pour moi...

En fait, le shutdown(socket,SD_BOTH) doit être placé un certain temps
*avant* le closesocket(socket), et là, ça fonctionne.

Exemple, je fais un shutdown() et j'attends, disons 10" *avant* de traiter
mon WM_CLOSE et de faire le closesocket() etc., là le socket reçoit bien le
FD_CLOSE.

Mais si je fait mon shutdown() *dans* le traitement de mon WM_CLOSE, alors
le socket n'a jamais le temps de recevoir le FD_CLOSE.



Bon en même temps, si tu fais le shutdown dans le WM_CLOSE de la fenêtre
qui est censée recevoir le message FD_CLOSE, et que tu appelles
DestroyWindow juste après, tu ne reçevra effectivement jamais le FD_CLOSE.

Ce que tu peux peut être faire: ne pas appeler DestroyWindow au
WM_CLOSE, mais faire simplement un shutdown, et attendre le FD_CLOSE
pour appeler DestroyWindow.

Christophe.
Avatar
Arnold McDonald \(AMcD\)
Christophe Leitienne wrote:

Ce que tu peux peut être faire: ne pas appeler DestroyWindow au
WM_CLOSE, mais faire simplement un shutdown, et attendre le FD_CLOSE
pour appeler DestroyWindow.



J'y ai pensé. Mais...

Si c'est moi qui ferme le socket local, oui, je call le DestroyWindow()
puisque je décide de finir l'application. Mais si c'est la connection
distante qui ferme, non, je ne veux pas finir :-). Vu que je n'ai pas le
moyen de savoir d'où provient le FD_CLOSE...

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/
Avatar
PYT
Arnold McDonald (AMcD) a écrit :
Christophe Leitienne wrote:

Ce que tu peux peut être faire: ne pas appeler DestroyWindow au
WM_CLOSE, mais faire simplement un shutdown, et attendre le FD_CLOSE
pour appeler DestroyWindow.



J'y ai pensé. Mais...

Si c'est moi qui ferme le socket local, oui, je call le DestroyWindow()
puisque je décide de finir l'application. Mais si c'est la connection
distante qui ferme, non, je ne veux pas finir :-). Vu que je n'ai pas le
moyen de savoir d'où provient le FD_CLOSE...



C'est pas lié à ce genre de paramètre votre pb ?

http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/regentry/58811.mspx?mfr=true

PYT
Avatar
Arnold McDonald \(AMcD\)
Non, c'est bon, je pense avoir bien résumé le truc ci-dessus :-). Lien
intéressant toutefois, on a souvent affaire à ce TIME_WAIT et il n'est pas
aisé de connaître la valeur. Ceux qui liront ton lien sauront comment y
parvenir désormais.

--
Arnold McDonald (AMcD)

http://arnold.mcdonald.free.fr/