IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Discussion :

socket avec timeout sur accept


Sujet :

Windows

  1. #1
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut socket avec timeout sur accept
    Bonjour,

    J'essaie de faire un timeout sur un connect() pour un socket donné. Pour celà, je le passe en mode asynchrone le temps de la connexion et je gère le timeout à l'aide de la fonction select().

    Voici ce que ça donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    // Mode non-bloquant
    fionbio = TRUE;
    ioctlsocket(s, FIONBIO, &fionbio);
    
    iRet = connect(s, (SOCKADDR *) &server, sizeof(server));
    iLastError = WSAGetLastError();
    
    // On repasse en mode bloquant
    fionbio = FALSE;
    ioctlsocket(s, FIONBIO, &fionbio);
    
    if (iRet == SOCKET_ERROR)
    {
    	if (iLastError == WSAEWOULDBLOCK)
    	{
    		fd_set writefds;
    		struct timeval tv;
    						
    		tv.tv_sec = 5;
    		tv.tv_usec = 0; 
    
    		FD_ZERO(&writefds);
    		FD_SET(s, &writefds);
    		select(0, NULL, &writefds, NULL, &tv);
    
    		if (FD_ISSET(s, &writefds))
    		{
    			/* Traitement OK */
    
    			shutdown(s, SD_BOTH);
    		}
    		else
    		{
    			/* Traitement KO */
    		}
    	}
    }
    
    closesocket(s);
    D'après MSDN, lorsque le socket est en mode non-bloquant, alors connect() renvoie WSAEWOULDBLOCK et l'opération continue. Donc pour savoir quand la connexion est faite, il suffit de placer un select() avec le timeout que l'on souhaite:

    For connection-oriented, nonblocking sockets, it is often not possible to complete the connection immediately. In such a case, this function returns the error WSAEWOULDBLOCK. However, the operation proceeds. When the success or failure outcome becomes known, it may be reported in one of several ways depending on how the client registers for notification. If the client uses the select function, success is reported in the writefds set and failure is reported in the exceptfds set. If the client uses the functions WSAAsyncSelect or WSAEventSelect, the notification is announced with FD_CONNECT and the error code associated with the FD_CONNECT indicates either success or a specific reason for failure
    Si le PC distant n'est pas connecté, alors la fonction accept() échoue au bout d'environ 20s. De plus, par défaut, sur Windows XP, on ne peut pas lancer plus de 10 connexions TCP simultannées.

    Donc dans le cas d'une connexion qui échoue, lorsque le timeout est atteint, je souhaite fermer la connexion TCP afin de ne pas dépasser la limite. Or la fonction closesocket() n'a pas l'air suffisant, comme si la fonction connect() continuait à vouloir se connecter et garde la connexion TCP ouverte.

    Pour tester, je lance dans des threads différents des tentatives de connexion au serveur. Je les lance par séries de 10, et une fois les 10 threads exécutés, j'en lance une nouvelle série. Parmi ces 10 threads, j'en mets un qui arrive à se connecter (thread 1), et 9 autres (threads 2 à 10) qui essaient de se connecter sur un serveur éteint (donc échec). La 1e série, le thread 1 arrive à se connecter tandis que dans les autres séries alors la plupart du temps il n'y arrive pas. Je pense donc que les connexion TCP ne sont pas correctement fermées.

    Comment pourrais-je les fermer correctement? Est-ce une autre erreur?

    Merci d'avance

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Euh, je n'ai jamais entendu parler de timeout sur accept()...

    Si j'ai bien compris, ce que tu veux c'est annuler en cours de route une connexion lancée en mode asynchrone? Pour ça, je conseillerais plutôt d'utiliser la fonction de timeout intégrée au socket avec setsockopt() (je crois que pour la connexion, c'est l'option SO_SNDTIMEO).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Euh, je n'ai jamais entendu parler de timeout sur accept()...
    Pourtant c'est marque dans MSDN:

    With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR, and WSAGetLastError will return WSAEWOULDBLOCK. In this case, there are three different steps you can take:

    Use the select function to determine the completion of the connection request by checking to see if the socket is writeable.
    If the application is using WSAAsyncSelect to indicate interest in connection events, then the application will receive an FD_CONNECT notification indicating that the connect operation is complete (successfully or not).
    If the application is using WSAEventSelect to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
    Citation Envoyé par Médinoc Voir le message
    Si j'ai bien compris, ce que tu veux c'est annuler en cours de route une connexion lancée en mode asynchrone?
    Oui c'est exactement ça

    Citation Envoyé par Médinoc Voir le message
    Pour ça, je conseillerais plutôt d'utiliser la fonction de timeout intégrée au socket avec setsockopt() (je crois que pour la connexion, c'est l'option SO_SNDTIMEO).
    Je vais essayer ...

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Ce que tu as cité parles d'un timeout sur connect(), dont je connais parfaitement l'existence.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Donc il faut que je fasse en plus setsockopt() d'après que j'ai compris. A quel moment? Juste avant connect()?
    C'est quoi la différence avec le mode asynchrone?

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Asynchrone, c'est que l'appel de la fonction retourne toujours immédiatement, sans attendre que l'opération soit finie. On doit alors utiliser une autre fonction (select(), WSAWaitForMultipleEvents(), etc.) pour attendre la fin de l'opération, mais on peut faire des trucs entre les deux (comme continuer à réagir aux actions de l'utilisateur).

    Le fait de mettre un timeout ou non (à supposer qu'on puisse le retirer) à connect() est complètement orthogonal à cela. Je pense que le plus simple pour toi, c'est d'appeler connect() de façon synchrone avec un timeout que tu choisis.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Je le mettais en mode asynchrone afin de pouvoir spécifier un timeout de connexion. Cependant je me retrouve avec un problème de limitation de connexion TCP.

    Si on peut spécifier un timeout à connect() en mode synchrone, je suis preneur. J'ai fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    struct timeval tv;	
    tv.tv_sec = 3;
    tv.tv_usec = 0;
    
    setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof(tv));
    connect(s, (SOCKADDR *) &server, sizeof(server));
    mais ça n'a pas l'air de marcher

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    D'après la doc, il faut un int, pas une structure timeval.

    Aussi, si SO_SNDTIMEO ne marche pas, essaie SO_RCVTIMEO à la place, etc.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    En faisant des recherches sur le net, je suis tombé sur ça :

    2.15 - How can I change the timeout for a Winsock function?

    Some of the blocking Winsock functions (e.g. connect()) have a timeout embedded into them. The theory behind this is that only the stack has all the information necessary to set a proper timeout. Yet, some people find that the value the stack uses is too long for their application; it can be a minute or longer.

    You can adjust the send() and recv() timeouts with the SO_SNDTIMEO and SO_RCVTIMEO setsockopt() options. .

    For other Winsock functions, the best solution is to avoid blocking sockets altogether.
    All of the non-blocking socket methods provide ways for you to build custom timeouts:

    *

    Non-blocking sockets with select() – The fifth parameter to the select() function is a timeout value.
    *

    Asynchronous sockets – Use the Windows API SetTimer().
    *

    Event objects – WSAWaitForMultipleEvents() has a timeout parameter.
    *

    Waitable Timers – Call CreateWaitableTimers() to make a waitable timer, which you can then pass to a function like WSAEventSelect() along with your sockets: if none of the sockets is signalled before the timer goes off, the blocking function will return anyway.

    Note that with asynchronous and non-blocking sockets, you may be able to avoid handling timeouts altogether. Your program continues working even while Winsock is busy. So, you can leave it up to the user to cancel an operation that’s taking too long, or just let Winsock’s natural timeout expire rather than taking over this functionality in your code.
    Donc apparemment ça ne marche pas sur connect(), il faut passer en mode non-bloquant, ce qui revient à mon problème initial...

Discussions similaires

  1. Socket, errno 24 sur accept()
    Par moi4567 dans le forum C++
    Réponses: 11
    Dernier message: 22/12/2014, 14h34
  2. Timeout sur accept()
    Par ryuhunter dans le forum C++
    Réponses: 1
    Dernier message: 04/04/2007, 22h38
  3. Timeout sur POST formulaire avec checkbox
    Par shyangel dans le forum Langage
    Réponses: 16
    Dernier message: 11/05/2006, 12h59
  4. Timeout sur read() avec termios et VTIME
    Par olivier857 dans le forum C
    Réponses: 9
    Dernier message: 05/04/2006, 09h30
  5. [Sockets] Timeout sur accept() ?
    Par MikB dans le forum Développement
    Réponses: 2
    Dernier message: 30/12/2003, 17h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo