[programmation] connect non-bloquant (résolu)

Ce qui ne concerne ni le forum ni des problèmes
rasta
archer
Messages : 142
Inscription : mar. 21 févr. 2012, 02:16

[programmation] connect non-bloquant (résolu)

Message par rasta »

Bonjour a tous.

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.
Dernière modification par rasta le lun. 28 janv. 2013, 22:33, modifié 1 fois.
rasta
archer
Messages : 142
Inscription : mar. 21 févr. 2012, 02:16

Re: [programmation] connect non-bloquant

Message par rasta »

Bon j'ai trouvé, en faite mon erreur vient d'ici:

Code : Tout sélectionner

ret = select( fd_client, NULL, &writefds, NULL, &timeout);


qu'il faut transformer en ceci:

Code : Tout sélectionner

ret = select( fd_client+1, NULL, &writefds, NULL, &timeout);
Pourquoi faut-il ajouter +1 au descripteur de la socket?

Là je suis vraiment paumé, surtout que par la suite je fait un appelle a select sur une socket en mode bloquant pour tester si des données sont arrivé et la je ne n'ajoute pas +1 au descripteur de la socket.

hypothése:
Peut-être que lors du passage en mode bloquant la socket est dupliqué par le noyau et que le descripteur choisie est celui juste a +1 du descripteur original.

J'aimerais bien comprendre cela.

Mercie d'avance pour votre aide.
Avatar de l’utilisateur
benjarobin
Maître du Kyudo
Messages : 17230
Inscription : sam. 30 mai 2009, 15:48
Localisation : Lyon

Re: [programmation] connect non-bloquant

Message par benjarobin »

Euh, non cela n'a strictement rien à avoir... As tu lu la documentation de select ?
Le premier paramètre n'est pas le descripteur de fichier (fd) mais la valeur max du descripteur de fichier à surveiller.

Donc si tu passes 3, tu surveilleras 0, 1 et 2 qui sont les entrées sorties standards. Bref il faut faire fd + 1
Zsh | KDE | PC fixe : core i7, carte nvidia
Titre d'un sujet : [Thème] Sujet (état) / Règles du forum
rasta
archer
Messages : 142
Inscription : mar. 21 févr. 2012, 02:16

Re: [programmation] connect non-bloquant

Message par rasta »

Mercie de l'explication, après ton explication je croie avoir comprie.

En faite les descripteurs commence a partir de zero, donc le il faut ajouter plus 1 pour surveiller notre descripteur.
Un peut comme un tableau en C qui commence a zero ?? ... bref je m'égare mais mercie encore :kimouss:
Avatar de l’utilisateur
chipster
Maître du Kyudo
Messages : 2063
Inscription : ven. 11 août 2006, 22:25
Localisation : Saint-Étienne (42)
Contact :

Re: [programmation] connect non-bloquant (résolu)

Message par chipster »

ça pique les nyeux les photes :D
Répondre