connect non bloquant

connect non bloquant - C - Programmation

Marsh Posté le 14-05-2012 à 09:11:16    

Bonjour ,
 
Je tente de rendre un connect non bloquant, le but étant de ne pas bloquer 30 sec lorsqu'on tente de se connecter sur une machine qui n'existe pas.
 
J'ai donc utilisé du code trouvé sur internet, qui fonctionne sous windows, mais pas sous linux.
 
Voici le code linux :
 

Code :
  1. #include <stdio.h>
  2. #include <fcntl.h>
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <sys/time.h>
  6. #include <netinet/in.h>
  7. #include <netinet/tcp.h>
  8. #include <unistd.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. int main()
  12. {
  13. int mysocket;
  14. mysocket = socket( AF_INET , SOCK_STREAM , IPPROTO_TCP );
  15. if ( mysocket >= 0)
  16. {
  17.  unsigned long hote_l;
  18.  hote_l = inet_addr( "172.17.0.140" );
  19.  struct sockaddr_in adresse;
  20.  memset ( &adresse , 0 , sizeof( adresse ) );
  21.  adresse.sin_family  = AF_INET;
  22.  adresse.sin_addr.s_addr = hote_l;
  23.  adresse.sin_port  = htons( 40001 );
  24.  // rendre l'appel connect non bloquant pour changer le temps d'attente de la connexion
  25.  int flags;
  26.  int r;
  27.  flags = fcntl (mysocket, F_GETFL);
  28.  r = fcntl (mysocket, F_SETFL, flags | O_NONBLOCK);
  29.  int ret_connect = connect( mysocket , (struct sockaddr *) &adresse , sizeof (adresse ) );
  30.  if ( ret_connect != 0) // echec , attendre que ca se soit bien connecté
  31.  {
  32.   if ( errno == EINPROGRESS )
  33.   {
  34.    struct timeval timeout_connect;
  35.    timeout_connect.tv_sec  = 2;
  36.    timeout_connect.tv_usec = 0;
  37.    fd_set fd_connect_read;
  38.    fd_set fd_connect_write;
  39.    fd_set fd_connect_err;
  40.    FD_ZERO(&fd_connect_read);
  41.    FD_SET(mysocket, &fd_connect_read);
  42.    FD_ZERO(&fd_connect_write);
  43.    FD_SET(mysocket, &fd_connect_write);
  44.    FD_ZERO(&fd_connect_err);
  45.    FD_SET(mysocket, &fd_connect_err );
  46.    int rcode = select((int) mysocket+1, /*&fd_connect_read*/ NULL, &fd_connect_write, /*&fd_connect_err*/ NULL , &timeout_connect);
  47.    if ( rcode > 0 )
  48.    {
  49.     if ( FD_ISSET( mysocket , &fd_connect_write  ))
  50.     {
  51.      // ok
  52.      printf(" ne devrait pas être là\n" );
  53.     }
  54.    }
  55.    else if ( rcode == 0 ) // timeout , pas de connexion
  56.    {
  57.     printf("le serveur n'est pas là\n" );
  58.    }
  59.    else
  60.    {
  61.     printf("select a échoué\n" );
  62.    }
  63.   }
  64.   else
  65.   {
  66.    printf("connect a échoué\n" );
  67.   }
  68.  }
  69.  r = fcntl (mysocket, F_SETFL, flags & ~O_NONBLOCK);
  70.  close( mysocket);
  71. }
  72. return 0;
  73. }


 
 
normalement, le select ne devrait pas renvoyer 1 mais 0.
 
Le comportement sous windows est différent : on n'utilise pas fcntl mais ioctl pour rendre non bloquant, et le select renvoie bien 1 mais il faut tester fd_connect_err qui signifie qu'il y a bien une erreur s'il est positionné.
 
Où ai-je pu faire une erreur ?
 
Merci :)

Reply

Marsh Posté le 14-05-2012 à 09:11:16   

Reply

Marsh Posté le 14-05-2012 à 10:17:27    

J'apporte la correction, pas évident à trouver :
 

Code :
  1. int l_sock_optval = -1;
  2. socklen_t l_sock_optval_len = sizeof(l_sock_optval);
  3. if ( getsockopt( mysocket , SOL_SOCKET , SO_ERROR , (int *)&l_sock_optval , ( socklen_t *) &l_sock_optval_len ) == 0 )
  4. {
  5.         if ( l_sock_optval == 0 )
  6.         {
  7.                  printf("success\n" );
  8.         }
  9.         else if ( l_sock_optval == ECONNREFUSED )
  10.         {
  11.                  printf("refused\n" );
  12.         }
  13. }
  14. else
  15. {
  16.         printf("erreur getsockopt %d\n", errno );
  17. }

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed