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

Réseau C Discussion :

ne pas rester bloqué sur un connect


Sujet :

Réseau C

  1. #1
    Membre du Club
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Points : 68
    Points
    68
    Par défaut ne pas rester bloqué sur un connect
    Bonjour à tous,

    Voici mon problème:
    J'ai une application redondante sous XP avec 3 threads, 2 sont utilisé pour savoir si l'ordinateur partenaire est actif, le troisième est le thread principal de l'application.

    Le thread principal doit de temps en temps copier ses fichiers à jours sur le partenaire (via un partage netbios), si celui-ci est dispo.

    Pour celà un des thread va tenter de temps en temps de voir si le port netbios 139 est ouvert sur le partenaire en faisant un connect sur ce port.

    Le problème est que si le partenaire est débranché du réseau, le connect va bloquer mon thread le temps d'avoir un timeout sur la socket (ça prends plus de 30 secondes) et le pire, c'est que le thread qui est en attente d'entrées/sorties ne rends pas la main. mon application reste donc bloquée pendant 30 secondes, alors que le temps de cycle ne doit pas dépasser 10 secondes (plus ou moins temps réel)

    J'ai tenté de jouer avec SO_SNDTIMEO mais rien n'y fait, voici mon code:
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
     
    int tcp_init_client(char *server_name, unsigned short port, SOCKET *cli_sock, int required_timetout)
    {
      int                 errnr = -999;
      unsigned int        addr;
      int                 socket_type = TCP_SOCKET_TYPE, ret;
      struct sockaddr_in  server;
      struct hostent      *hp;
      int                 timeout;
      time_t t;
      char strtime[255];
     
      if (port == 0)
      {
        return -1;
      }
     
        hp = gethostbyname(server_name);
     
     
      if (hp == NULL)
      {
     
        errnr = WSAGetLastError();
     
        trc_msg(ERR_TCP, INDENT_0, ERR, 0, "TCP Client: Cannot resolve address [%s]: Error %d", server_name, errnr);    
        return -1;
      }
     
      /* Copy the resolved information into the sockaddr_in structure */
      memset(&server, 0, sizeof(server));
      memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
      server.sin_family = hp->h_addrtype;
      server.sin_port = htons(port);
     
      *cli_sock = socket(AF_INET, socket_type, 0);  /* Open a socket */
      if (*cli_sock == INVALID_SOCKET)
      {
        errnr = WSAGetLastError();
        trc_msg(ERR_TCP, INDENT_0, ERR, 0, "TCP Client: Error Opening socket: Error %d", errnr);
        return -1;
      }
     
      timeout = required_timetout;
      /*We set a send timeout in order to detect that a client is down*/
     
      if (ret = setsockopt(*cli_sock, SOL_SOCKET, SO_SNDTIMEO, (char*) &timeout, sizeof(timeout)))
      {
        errnr = WSAGetLastError();
     
        trc_msg(ERR_TCP, INDENT_0, ERR, 0, "Setsockopt SO_RCVTIMEO failed with error:%d", errnr);
      }
     
     
      trc_msg(ERR_TCP, INDENT_0, INFO, 0, "TCP Client connecting to: %s (%d)", hp->h_name);
     
      t = (time(NULL) + 0);
      strftime(strtime, 255, "%Y%m%d %X\t", my_localtime(&t));
      printf("\n time before:%s", strtime);
      if (connect(*cli_sock, (struct sockaddr *) &server, sizeof(server)) == SOCKET_ERROR)
      {
        errnr = WSAGetLastError();
     
        t = (time(NULL) + 0);
        strftime(strtime, 255, "%Y%m%d %X\t", my_localtime(&t));
        printf("\n time after:%s", strtime);
        if (!quietmode)
          trc_msg(ERR_TCP, INDENT_0, ERR, 0, "TCP Client connect %s (%d) failed: %d", hp->h_name, port, errnr);
        return -1;
      }   
      return 0;
    }
    voilà, je n'ai pas d'erreur lors du setsockopt()
    par contre je n'arrive pas à lire SO_RCVTIMEO avec getsockopt(), chaque fois il me donne l'erreur WSAEFAULT 10014

    D'après mes recherches, fixer SO_SNDTIMEO ou SO_RCVTIMEO ner fonctionne pas des masses.

    Je cherche donc désespérément une solution.

    J'accepetrais volontier d'utiliser un select, mais comment faire sur une socket client?

    merci de toutes vos propositions

  2. #2
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    La réponse à ta question se trouve dans la documentation de ton système:
    http://msdn.microsoft.com/en-us/libr...25(VS.85).aspx
    je cite
    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 possible scenarios:
    1. Use the select function to determine the completion of the connection request by checking to see if the socket is writeable.

    1. 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).

    1. 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).

  3. #3
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Si tu te demandes comment on rend une socket non bloquante sous Windows, je te renvoie encore une fois à la documentation:
    http://msdn.microsoft.com/en-us/libr...73(VS.85).aspx
    Cordialement.

  4. #4
    Membre du Club
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Points : 68
    Points
    68
    Par défaut
    Merci Nicolas de tes réponses vives et anticipantes.

    Ce que dit la doc, c'est donc que je dopis utiliser des socket non-bloquantes. C'est un epu moche mais bon, je veux bien, même si ça va poser des problèmes de portabilité mais ça, je peux encore vivre avec.
    En fait, j'avais déjà tenté ça mais je reste bloqué à un certain point.
    Mon but est de créer une socket, de la définir non bloquante puis de la connecter. ensuite je fais un selcet qui devrait me permetre de voir si j'ai une erreur du type WOULD_BLOCK avec un timeout de 1 sec, ça devrait me permettre de m'en sortir.

    Voici le code que j'ai utilisé:
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
     
    int tcp_is_server_available(char *server_name, unsigned short port, SOCKET *cli_sock, int timeout_wait)
    {
      int                 nb, errnr = -999;
      unsigned int    addr;
      int                 socket_type = TCP_SOCKET_TYPE, ret;
      struct sockaddr_in  server;
      struct hostent      *hp;
      time_t t;
      char strtime[255];
      long            status = 0;
      struct timeval  timeout;
      u_long iMode = 1; /*Set the socket to non-blocking mode (more than 0)*/
      fd_set          writefds;
     
     
     
       /* server address is a name */
        hp = gethostbyname(server_name);
     
      if (hp == NULL)
      {
        errnr = WSAGetLastError();
     
        printf( "TCP Client: Cannot resolve address [%s]: Error %d", server_name, errnr);    
        return -1;
      }
     
      /* Copy the resolved information into the sockaddr_in structure */
     
      memset(&server, 0, sizeof(server));
      memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
      server.sin_family = hp->h_addrtype;
      server.sin_port = htons(port); 
     
      *cli_sock = socket(AF_INET, socket_type, 0);  /* Open a socket */
     
     
      if (*cli_sock == INVALID_SOCKET)
      {
        errnr = WSAGetLastError();
        printf( "TCP Client: Error Opening socket: Error %d", errnr);
        return -1;
      }
      ioctlsocket(cli_sock, FIONBIO, &iMode); /* set non-blocking*/
     
      if (connect(*cli_sock, (struct sockaddr *) &server, sizeof(server)) == SOCKET_ERROR  )
      {
        errnr = WSAGetLastError();
        printf("TCP Client connect %s (%d) failed: %d", hp->h_name, port, errnr);
        return -1;
      }
     
      /* prepare read descriptor */
      FD_ZERO(&writefds);
      FD_SET(cli_sock, &writefds);
     
      /* Set timeout at 0 for select () ==> immediate return from select */
      timeout.tv_sec = timeout_wait / 1000;
      timeout.tv_usec = (timeout_wait - timeout.tv_sec * 1000) * 1000;
     
     
      /* Check if socket ready to be written*/
      nb = select(FD_SETSIZE, NULL, &(writefds), NULL, &(timeout));
     
      /* if error */
      if (nb < 0)
      {
        status = -1;
        errnr = WSAGetLastError();
        printf("TCP select() returned %ld, error %ld", nb, errnr);
        return -1;
      }
      else
      {
        status = 0;
     
        /* check if at least one descriptor is ready AND it's the correct descriptor */
     
        if (FD_ISSET(cli_sock, &writefds))
        {
          /* we can write */
          return 1;
        }
        else
        {
          /* we can not write */
          return 0;
        }
      }
    }
    cependant, la fonction select me retourne toujours -1 avec l'erreur :WSAENOTSOCK 10038

    Est ce qu'un paramètre de moon fdset n'est pas valide?
    au départ je pensais qu'on nepouvait simplement pas utiliser select sur une connection client.

    NB, avec wireshark, je vois que le 3handshake se passe bien, la connection est ouverte entre mon pc et le pc partenaire...

    N'hésitez pas à me traiter de tous les noms si vous voyez une grosse erreur..

    Merci encore.

  5. #5
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Citation Envoyé par gigiskhan Voir le message
    cependant, la fonction select me retourne toujours -1 avec l'erreur :WSAENOTSOCK 10038

    Est ce qu'un paramètre de moon fdset n'est pas valide?

    N'hésitez pas à me traiter de tous les noms si vous voyez une grosse erreur..
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FD_SET(*cli_sock, &writefds);

  6. #6
    Membre du Club
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Points : 68
    Points
    68
    Par défaut
    Merci de ne pas m'avoir insulté,

    Je n'arrive toujours pas à faire respecter de timeout que je fixe, mais je vais travailler le truc de mon côté, je reviens clore le sujet dès que j'ai trouvé.

    Merci encore Nicolas

  7. #7
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Citation Envoyé par gigiskhan Voir le message
    Merci de ne pas m'avoir insulté,
    ça n'arrivera pas sur ce forum.

    Citation Envoyé par gigiskhan Voir le message
    Je n'arrive toujours pas à faire respecter de timeout que je fixe
    Précise ton problème s'il te plaît.

  8. #8
    Membre du Club
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Points : 68
    Points
    68
    Par défaut
    et bien malgré le fait que je dise que la socket est non bloquante, qd je lance un connect(), la fonction reste bloquée le temps d'avoir un timeout si le partenaire n'est pas connecté.
    je reste donc bloqué dans connect avant de pouvoir faire le select...

  9. #9
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Vérifie que ioctlsocket() se déroule correctement.

  10. #10
    Membre du Club
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Points : 68
    Points
    68
    Par défaut
    Il faut que j'arrête d'être c**
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ioctlsocket(*cli_sock, FIONBIO, &iMode);
    et ça fonctionne bcp mieux.

    je vais me dormir et reprendre ça à tête reposée

  11. #11
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Citation Envoyé par gigiskhan Voir le message
    Il faut que j'arrête d'être c**
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ioctlsocket(*cli_sock, FIONBIO, &iMode);
    et ça fonctionne bcp mieux.

    je vais me dormir et reprendre ça à tête reposée

  12. #12
    Membre du Club
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2004
    Messages : 58
    Points : 68
    Points
    68
    Par défaut
    Ayé, ça fonctionne parfaitement.

    Je résume donc les points, pour avoir un timeout sur une connection client sans bloquer un thread:

    1°) créer un socket,
    2°) le déclarer non-bloquant avec ioctlsocket pour windows et fnctl pour linux et autres
    3°) tenter d'ouvrir la connection avec connect
    4°) juste après vérifier si la connection s'est effectuée en temps voulu avec select
    5°) pour choisir le temps de timeout on utilsera les macros FD_SET

    Et voici la fonction qui teste si un serveur écoute sur un port donné:
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    /*----------------------------------------------------------------------------
    / tcp_is_server_available()
    / 
    / Parameters:
    /   server_name:  Name or IP address of the computer that must be checked
    /   port:         Port of the service that must be checked
    /   timeout_wait: Time to wait before returning (msec)
    / 
    / Return Value:
    /   0 no server listening
    /   1 server listening
    / 
    / Purpose:
    /   Checks if a computer is listening on a port via tcp 3 hand check
    / 
    / Remarks:  Made by GAU2009NOV16
    /---------------------------------------------------------------------------*/
    int tcp_is_server_available(char *server_name, unsigned short port, int timeout_wait)
    {
      int                 nb, errnr = -999;
      unsigned int        addr;
      int                 socket_type = TCP_SOCKET_TYPE, ret;
      struct sockaddr_in  server;
      struct hostent      *hp;
      SOCKET              cli_sock = INVALID_SOCKET;
      long                status = 0;
      struct              timeval  timeout;
      u_long              iMode = 1; /*Set the socket to non-blocking mode (more than 0)*/
      fd_set              writefds;
     
      if (port == 0)
      {
        return -1;
      }
      /* Attempt to detect if we should call gethostbyname() or */
     
      if (isalpha(server_name[0]))
      { /* server address is a name */
        hp = gethostbyname(server_name);
      }
      else
      { /* Convert nnn.nnn address to a usable one */
        addr = inet_addr(server_name);
        hp = gethostbyaddr((char *) &addr, 4, AF_INET);
      }
     
      if (hp == NULL)
      {
    #if WIN_COMPILE
        errnr = WSAGetLastError();
        /*WSACleanup(); */
    #else
        errnr = errno;
    #endif
          printf("TCP Client: Cannot resolve address [%s]: Error %d", server_name, errnr);    
        return -1;
      }
     
     
      /* Copy the resolved information into the sockaddr_in structure */
     
      memset(&server, 0, sizeof(server));
      memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
      server.sin_family = hp->h_addrtype;
      server.sin_port = htons(port);
     
      cli_sock = socket(AF_INET, socket_type, 0);  /* Open a socket */ 
     
      if (cli_sock == INVALID_SOCKET)
      {
    #if WIN_COMPILE
        errnr = WSAGetLastError();
    #else
        errnr = errno;
    #endif
        printf("TCP Client: Error Opening socket: Error %d", errnr);
        return -1;
      }
     
    #if WIN_COMPILE
      if (ioctlsocket(cli_sock, FIONBIO, &iMode)== SOCKET_ERROR ) /* set non-blocking*/
      {
        errnr = WSAGetLastError();
    #else
      /*To Check*/
      ret = fcntl(cli_sock, F_GETFL);
      ret = fcntl(cli_sock, F_SETFL, status | O_NONBLOCK); errnr = errno;
      if (ret < 0)
      {
        errnr = errno;
    #endif    
        printf("impossible to set the socket non-blocking %s (%d) failed: %d", hp->h_name, port, errnr);
        return -1;
      }
     
      if (ret = connect(cli_sock, (struct sockaddr *) &server, sizeof(server)) == SOCKET_ERROR )
      {
    #if WIN_COMPILE
        errnr = WSAGetLastError();
    #else
        errnr = errno;
    #endif
        if (errnr != WSAEWOULDBLOCK)
        {
          printf("TCP Client connect %s (%d) failed: %d", hp->h_name, port, errnr);
          return -1;
        }
      }
     
      /* prepare read descriptor */
      FD_ZERO(&writefds);
      FD_SET(cli_sock, &writefds);
     
      /* Unix Style */
      /*
      readfds = (1<<sock) ;
      msk = (1<<sock) ;
      writefds=0 ;
      exceptfds=0 ;
      */
     
      /* Set timeout at 0 for select () ==> immediate return from select */
      timeout.tv_sec = timeout_wait / 1000;
      timeout.tv_usec = (timeout_wait - timeout.tv_sec * 1000) * 1000;
     
     
      /* Check if socket ready to be read */
      nb = select(-1, NULL, &(writefds), NULL, &(timeout));
     
      /* if error */
      if (nb < 0)
      {
        status = -1;
    #if WIN_COMPILE
        errnr = WSAGetLastError();
    #else
        errnr = errno;
    #endif
        printf("TCP select() returned %ld, error %ld", nb, errnr);
        return -1;
      }
      else if (nb == 0)
      {
        printf("socket timeout after %d seconds while connection to %s o, port:%d", timeout.tv_sec, server_name, port);
        closesocket(cli_sock);
        return 0;
      }
      else
      {
        printf("there is %d server listening on %s port:%d", nb, server_name, port);
        closesocket(cli_sock);
        return nb;
      }
    }
    Un grand Merci Nico (tu permets que je t'appelle Nico?) pour ton aide.

  13. #13
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Citation Envoyé par gigiskhan Voir le message
    Un grand Merci Nico (tu permets que je t'appelle Nico?) pour ton aide.
    Je t'en prie, mais ne crie pas victoire trop vite, le non blocking connect est une des choses les moins portables des sockets BSD, ton code ne gère que la partie facile de la chose, là où ça se corse, c'est pour gérer les erreurs, je connais 3 manières de faire selon l'OS utilisé mais je suis sûr qu'il y en ait des différentes pour les OS que je ne connais pas.
    Cordialement.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 22/08/2014, 16h58
  2. Réponses: 2
    Dernier message: 12/03/2008, 16h51
  3. Réponses: 9
    Dernier message: 19/12/2007, 15h42
  4. Réponses: 9
    Dernier message: 16/11/2007, 11h33
  5. rester bloqué sur une zone de texte
    Par Pitou5464 dans le forum Access
    Réponses: 3
    Dernier message: 18/08/2006, 18h56

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