OVH Cloud OVH Cloud

[HELP] Socket bloqué

9 réponses
Avatar
Pendloup
Bonjour,


Il y a quelques temps, j'ai expos=E9 un pb avec des Sockets qui se
bloquaient. Voici le contexte :

Plusieurs threads tournant en parall=E8le =E9tablissent une connexion
ftp sur un m=EAme serveur. Chaque thread devant r=E9cup=E9rer des fichiers
sur ce serveur. Chaque fois qu'un thread a termin=E9, il ferme sa
connexion. Voici le code d'une d=E9connexion :

send(m_socket,"Quit\r\n",6,0);

shutdown(m_socket, 2);
closesocket(m_socket);



Le pb est que certains thread , pas tous, se trouvent alors bloqu=E9s
dans la fonction recv(). Je pensait que c' =E9tait d=FB a une perte de
connexion, mais visiblement non.

Cette fonction est normalement non bloquante, je fais un appel =E0 :

WSAAsyncSelect(m_socket,m_hWnd,CUT_ASYNC_NOTIFY_MSG,events);

Une fois bloqu=E9e, si je d=E9branche le c=E2ble r=E9seau, la fonction
recv() rend la main et je r=E9cup=E8re bien un code d'erreur m'indiquant
que la connexion est interrompue.

Comment puis-je m'en sortir ? y a t'il moyen par ex de poser un
timeout ?


Je suis vraiment bloqu=E9 sur ce pb. Merci pour votre aide ...

Cordialement,

Pendloup.

9 réponses

Avatar
Cyrille Szymanski
"Pendloup" wrote in news:1153916223.833977.220040@
75g2000cwc.googlegroups.com:

Plusieurs threads tournant en parallèle établissent une connexion
ftp sur un même serveur. Chaque thread devant récupérer des fichiers
sur ce serveur.



Le pb est que certains thread , pas tous, se trouvent alors bloqués
dans la fonction recv().



Cette fonction est normalement non bloquante, je fais un appel à :



WSAAsyncSelect(m_socket,m_hWnd,CUT_ASYNC_NOTIFY_MSG,events);



Je comprends pas trop... multithread et WSAAsyncSelect() ????

Peux-tu poster un code minimaliste qui reproduit l'erreur, ou détailler un
peu plus l'archi de ton programme. Que font les threads et qu'est-ce qui
est fait en réponse à CUT_ASYNC_NOTIFY_MSG ?

--
Cyrille Szymanski
Avatar
Dominique Vaufreydaz
Bonjour,

Le pb est que certains thread , pas tous, se trouvent alors bloqués
dans la fonction recv(). Je pensait que c' était dû a une perte de
connexion, mais visiblement non.



Avant de faire un recv, il faut faire un select. Ensuite, quand y'a des choses
a lire, tu fais un recv. Le select a un timeout.

Attention, les macros FD_ZERO et FD_SET ne sont pas utilisable
dans un for (car mal ecrite) et genere des erreurs de compilation.

Doms.
Avatar
Pendloup
Bonjour,

Effectivement, je fais maintenant un select avec un timeout ça
marche.

Mon pb semble enfin réglé.

Merci à tous.

Cordialement,


Pendloup.


Dominique Vaufreydaz a écrit :

Bonjour,

> Le pb est que certains thread , pas tous, se trouvent alors bloqués
> dans la fonction recv(). Je pensait que c' était dû a une perte de
> connexion, mais visiblement non.

Avant de faire un recv, il faut faire un select. Ensuite, quand y'a d es choses
a lire, tu fais un recv. Le select a un timeout.

Attention, les macros FD_ZERO et FD_SET ne sont pas utilisable
dans un for (car mal ecrite) et genere des erreurs de compilation.

Doms.


Avatar
Pendloup
Bonjour,


Le pb venait du fait que je ne faisait pas appel select() avant
recv(). Maintenant ça marche tip top.

Cordialement,


Pendloup.


Cyrille Szymanski a écrit :

"Pendloup" wrote in news:1153916223.833977.220040@
75g2000cwc.googlegroups.com:

> Plusieurs threads tournant en parallèle établissent une connexion
> ftp sur un même serveur. Chaque thread devant récupérer des fichi ers
> sur ce serveur.

> Le pb est que certains thread , pas tous, se trouvent alors bloqués
> dans la fonction recv().

> Cette fonction est normalement non bloquante, je fais un appel à :

> WSAAsyncSelect(m_socket,m_hWnd,CUT_ASYNC_NOTIFY_MSG,events);

Je comprends pas trop... multithread et WSAAsyncSelect() ????

Peux-tu poster un code minimaliste qui reproduit l'erreur, ou détailler un
peu plus l'archi de ton programme. Que font les threads et qu'est-ce qui
est fait en réponse à CUT_ASYNC_NOTIFY_MSG ?

--
Cyrille Szymanski


Avatar
Dominique Vaufreydaz
Salut,

Ca fait longtemps que je n'ai pas utilisé select, mais j'aimerais en
savoir plus sur ce problème, si tu as 5 minutes (ou un lien).



Quel problem ? Les recv reste bloquant a moins d'un probleme
sur la socket. Si tu fais un select, tu mets un timeout et au bout
de X microsecondes, tu sors. Ensuite, tu verifies dans le resultat
que tu as qqchose en attente, genre :
// Set the fd set to an empty set
FD_ZERO(&fds);
FD_SET( MySocket, &fds );

// Set or reset the timeout value (select may have change it)
timeout.tv_sec = 0;
timeout.tv_usec = 10000; // 10 ms

#ifndef WIN32
MaxDesc = MySocket + 1;
#else
// On WIN32 plateform, the value is unused and remain 0
#endif

nReady = select(MaxDesc, &fds, NULL, NULL, &timeout);

// If our only socket is readable...
if ( nReady > 0 )
{
// ... process the result
// recv and co...
}

Si le resultat est 0, il n'y a rien dans la socket, si < 0 (donc -1
ou SOCKET_ERROR sur Windows), y'a eu un soucis.

Sinon, faire juste gaffe, on peut ecrire :
FD_SET(xx);
while() {}

mais pas
for( FD_SET(xxx);;) {}

Sous Windows, la macro est pourrie ca compile pas (syntaxe). Sous MacOs/Linux
pas de probleme.

Bref, pour faire du code portable, tu transformes ton for en while et hop
ca roule. Ca permet aussi a ton thread toutes les x millisecond de verifier
si on lui a pas demander de s'arreter par exemple.

Doms.
Avatar
Cyrille Szymanski
"Pendloup" wrote in news:1153996145.909621.221560
@i42g2000cwa.googlegroups.com:

Le pb venait du fait que je ne faisait pas appel select() avant
recv(). Maintenant ‡a marche tip top.



Soit tu es en 1:n et tu multiplexes plusieurs connexions sur le même
thread. En utilisant WSAAsyncSelect() tu reçois un message quand il y a des
données et recv() ne devrait jamais bloquer.

Ou alors tu fais du multithreading type 1:1 et les threads bloquent en
attendant les données, et c'est normal.

Là on dirait que tu es un peu entre les deux, et qu'il y a une sorte de
"race condition" qui fait que ça bloque. Je ne comprends pas pourquoi un
appel à select() débloque le programme ?

--
Cyrille Szymanski
Avatar
Cyrille Szymanski
"Dominique Vaufreydaz" wrote in
news::

timeout.tv_sec = 0;
timeout.tv_usec = 10000; // 10 ms

nReady = select(MaxDesc, &fds, NULL, NULL, &timeout);

// If our only socket is readable...
if ( nReady > 0 )
{
// ... process the result
// recv and co...
}



Ouh 10 ms de timeout.

Je suis d'accord sur le principe de toujours faire un select() avant un
recv() pour pas bloquer bêtement le thread, mais dans ce cas tu mets un
timeout à 1 voire 10 secondes ou plus pour pas faire de l'attente active.

Sinon c'est qu'il te faut une autre stratégie E/S, genre WSAAsyncSelect(),
sockets non bloquantes, IOCP...

--
Cyrille Szymanski
Avatar
Dominique Vaufreydaz
Salut,

Ouh 10 ms de timeout.
Je suis d'accord sur le principe de toujours faire un select() avant
un recv() pour pas bloquer bêtement le thread, mais dans ce cas tu
mets un timeout à 1 voire 10 secondes ou plus pour pas faire de
l'attente active.



C'est pas de l'attente active mais pseudo active. Ensuite,
si tu as une applie fortement multithread car fortement
multiconnexion reseau, et que tu la termine, et que tu veux
la terminer proprement (pas de TerminateThread, hein !),
ben mon ami, tu vas pas attendre (ou faire attendre a l'utilisateur)
10 secondes que ton thread sorte du select pour pouvoir le terminer...

Sinon c'est qu'il te faut une autre stratégie E/S, genre
WSAAsyncSelect(),



Pas portable.

sockets non bloquantes, IOCP...



Et une fois que tu as fait un recv non bloquant, tu sors et tu fais
quoi ? Sleep ? de Combien ? 10 secondes ? C'est exactement la
meme chose dans le principe.

Je continue comme ca. Ca marche du feu de dieu sans prendre
plein de CPU, et en plus ca marche aussi sous MacOSX et
Linux.

Doms.
Avatar
Cyrille Szymanski
"Dominique Vaufreydaz" wrote in
news::

C'est pas de l'attente active mais pseudo active. Ensuite,
si tu as une applie fortement multithread car fortement
multiconnexion reseau, et que tu la termine, et que tu veux
la terminer proprement (pas de TerminateThread, hein !),
ben mon ami, tu vas pas attendre (ou faire attendre a
l'utilisateur) 10 secondes que ton thread sorte du select pour
pouvoir le terminer...



Tout dépend de ce que doit faire le thread. S'il a d'autres occupations,
alors à la limite pourquoi pas .

Mais s'il doit simplement lire des données, faire de l'attente pseudo
active à pas de 10ms juste pour le cas où on désire fermer l'application
ça me paraît un peu exagéré ;-)

WSAAsyncSelect(),



Pas portable.

Je continue comme ca. Ca marche du feu de dieu sans prendre
plein de CPU, et en plus ca marche aussi sous MacOSX et
Linux.



Oui dans ce cas je vois pas trop comment faire autrement.

Je voulais juste comprendre comment les gens résolvent ce genre de
problème.

--
Cyrille Szymanski