Je viens posté ici un message a propos de programmation réseau.
Je suis en train de programmer un client pour un serveur que j'ai conçue.
Et je tente de faire un connect non bloquant sur mon serveur.
Pourquoi?
Parce que mon serveur est dupliqué sur plusieurs poste de travail et une
erreur de configuration de port sur le client le bloque durant environ 30 a 40s et l'erreur
Time out est retourné par la fonction connect.
Par conséquant j'ai cherché sur le net et voila ce que j'ai programmé :
Le principe est simple, je passe la soket en mode non-bloquant avec fcntl() pour faire un appelle a connect non bloquant puis je passe le descripteur de socket a la fonction select() pour savoir si on peut écrire des données deçue.
Code : Tout sélectionner
int TimeOut_Connect( int fd_client, const int time_out, struct sockaddr_in *adresse )
{
// variable time out
fd_set writefds;
int ret = 0;
struct timeval timeout;
int ttmt = 1;
int flags;
// passage de la socket en mode non bloquant
flags = fcntl( fd_client, F_GETFL);
ret = fcntl( fd_client, F_SETFL, flags | O_NONBLOCK);
// apelle a connecte non bloquand
connect( fd_client, (struct sockaddr*)adresse, sizeof(struct sockaddr_in) );
memset( &timeout, '\0', sizeof(struct timeval) );
// réglage du time out
timeout.tv_sec = time_out;
while( ttmt ) // boucle d'attente d'arrivé des données sur la socket
{
// manipulation de la structure fd_set par les macros recommandées
FD_ZERO(&writefds);
FD_SET(fd_client, &writefds);
// appelle à select pour vérifier la possibilité d'écrirre sur la socket
ret = select( fd_client, NULL, &writefds, NULL, &timeout);
if( ret < 0 )
{
FD_CLR( fd_client, &writefds ); // supprime la socket de l'ensemble readfs
// Passage de la socket en mode bloquant
ret = fcntl (fd_client, F_SETFL, flags & ~O_NONBLOCK);
puts(" Select a échoué ");
return -1;
}
// des données sont recus avant la fin du time out
if( FD_ISSET(fd_client, &writefds) )
{
FD_CLR( fd_client, &writefds ); // supprime la socket de l'ensemble readfs
// Passage de la socket en mode bloquant
ret = fcntl (fd_client, F_SETFL, flags & ~O_NONBLOCK);
puts("OK OK OK");
return 0;
}
// fin du time out
if( ret == 0 )
{
// supprime la socket de l'ensemble readfs bloquant
FD_CLR( fd_client, &writefds );
// Passage de la socket en mode
ret = fcntl (fd_client, F_SETFL, flags & ~O_NONBLOCK);
puts(" Fin du Time-out ");
return 1;
}
}
ret = fcntl (fd_client, F_SETFL, flags & ~O_NONBLOCK);
return -1;
}
Le problème est que ma fonction même si elle se connecte sur un port d'une machine distante près a recevoir des données, elle échoue et me retourne "Fin du Time-out" soit 1 dans mon cas.
Si je passe juste la socket en mode non bloquant sans faire du select j'obtiend l'erreur "opération en cour" sur la fonction connecte mais que le port en face soit ouvert près a recevoir des données ou fermé. Après je peut envoyé des données si le port est ouvert mais aucun moyen de savoir si la connection a été établie par conséquent un apelle a send peut devenir bloquant penant 30s.
D'après le man de connect() il faut ajouter une opération qui est la suivante:
EINPROGRESS
La socket est non-bloquante, et la connexion ne peut pas être établie immédiatement. Il est alors possible d'utiliser select(2) pour attendre que la socket soit disponible en écriture. Une fois que select confirme la possibilité d'écrire, utilisez getsockopt(2) pour lire l'option SO_ERROR du niveau SOL_SOCKET. Cette option indiquera si connect a réussi (SO_ERROR valant zéro) ou si une erreur s'est produite (SO_ERROR correspondant à l'un des codes d'erreurs décrits ci-dessus).
A qu'elle moment dans ma fonction dois-je utilisé getsockopt() et de qu'elle manière?
ou existe-il une méthode plus simple?
Mercie d'avance de vos réponse.