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

Linux Discussion :

[SOCKET] Problème avec select()


Sujet :

Linux

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Novembre 2010
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 40
    Par défaut [SOCKET] Problème avec select()
    Bonjour,

    Je travaille actuellement sur les sockets et je me sert de select() afin d'avoir un serveur qui peut accueillir plusieurs client.
    La partie qui lit ce qui se passe sur le socket du serveur fonctionne correctement et je peux avoir plusieurs clients connectés, par contre la lecture des données provenant des différents client ne fonctionne pas. Dès qu'un de mes clients écrit quelque chose, mon serveur rentre dans une des conditions en boucle.

    Condition qui pose problème

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (FD_ISSET(sock, &readfd)) readSock(ssl, buffR, buffRSize);
    Donc avec cette condition, si un client se connecte et envoie des données (une seul fois, pas de boucle), mon serveur va entrer dans cette condition en boucle et m'afficher ce que le client à envoyé sans arrêt. Je n'arrive pas comprendre pourquoi pour le select() il y a encore des données à lire alors que le client n'envoie plus rien.

    Boucle While

    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
    while(1)
        {
    	FD_ZERO(&readfd);
    	FD_SET(sock, &readfd);
    	FD_SET(listen_sock, &readfd);
     
    	fd_max = max(sock, listen_sock);
     
    	printf("\n\n Attente \n\n");
     
    	err = select(fd_max+1, &readfd, 0, 0, 0);
            RETURN_ERR(err, "select()");
     
    	if (FD_ISSET(sock, &readfd)) readSock(ssl, buffR, buffRSize);
    	if (FD_ISSET(listen_sock, &readfd)) 
    	{
    	    /* Socket for a TCP/IP connection is created */
    	    sock = accept(listen_sock, (struct sockaddr*)&sa_cli, &client_len);
    	    RETURN_ERR(sock, "accept");
     
    	    //close (listen_sock);
    	    printf ("Connection from %s, port %u\n", inet_ntoa(sa_cli.sin_addr), ntohs(sa_cli.sin_port));
     
    	    /*  TCP connection is ready.  */
    	    /* A SSL structure is created */
    	    ssl = SSL_new(ctx);
    	    RETURN_NULL(ssl);
     
    	    /* Assign the socket into the SSL structure */
    	    err = SSL_set_fd(ssl, sock);
    	    RETURN_ZER(err);
     
    	    /* Perform SSL Handshake on the SSL server */
    	    err = SSL_accept(ssl);
    	    RETURN_SSL(err);
     
    	    /* Informational output (optional) */
    	    printf("SSL connection using %s\n", SSL_get_cipher(ssl));
     
     
    	    if(SSL_ENABLED)
    	    {
    		/* Get the client s certificate (optional) */
    		client_cert = SSL_get_peer_certificate(ssl);
    		if (client_cert != NULL) 
    		{
    		    printf ("Client certificate:\n");     
    		    str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
    		    RETURN_NULL(str);
    		    printf ("\t subject: %s\n", str);
     
    		    free (str);
    		    str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
    		    RETURN_NULL(str);
    		    printf ("\t issuer: %s\n", str);
     
    		    free (str);
    		    X509_free(client_cert);
    		} 
    		else
    		{
    		    printf("The SSL client does not have certificate.\n");
    		}
    	    }
     
    	} // end read
        } // end while
    Méthode ReadSock

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void readSock(SSL* ssl,char buffR[], int buffRSize)
    {
        int err = SSL_read(ssl, buffR, buffRSize-1); 
        RETURN_SSL(err);
    //    RETURN_ZER(err);
     
        buffR[err] = '\0';
        printf ("Received %d chars:'%s'\n", err, buffR);
     
    }
    #define

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define max(x,y)		((x) > (y) ? (x) : (y))
     
    #define RETURN_NULL(x)		if ((x)==NULL) exit(1)
    #define RETURN_ERR(err,s)	if ((err)==-1) { perror(s); exit(1); }
    #define RETURN_SSL(err)		if ((err)==-1) { ERR_print_errors_fp(stderr); exit(1); }
    #define RETURN_ZER(err)		if ((err)== 0) { ERR_print_errors_fp(stderr); exit(1); }
    Je ne suis peut-être pas claire donc l'explication de mon problème. N'hésitez pas à me poser des questions. Je peux aussi mettre les autres parties du code serveur si nécessaire.

    En espérant que quelqu'un pourrait m'aiguiller.

    Bonne journée,
    palo

  2. #2
    Membre averti
    Inscrit en
    Novembre 2010
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 40
    Par défaut
    Bonjour,

    J'ai pu avancé un peu avec mon problème. J'ai créé une liste chaînée ou je met tous les socket qui sont accepter par mon serveur. Ca me permet d'assigner correctement le FD_SET pour mon select/().

    Maintenant, mon code ne reste pas coincé dans la lecture du socket en boucle. Si un client se connecte et envoie des données, le serveur les récupères correctement. Le problème vient lorsque plusieurs sockets sont connectés au serveur.

    Explication

    • Le serveur attend une action avec select().
    • Client01 fait ça demande de connexion, le serveur accepte et lui attribue le socket n°4.
    • Le serveur attend une action avec select().
    • Client02 fait ça demande de connexion, le serveur accepte et lui attribue le socket n°5.
    • Le serveur attend une action avec select().


    Il y a maintenant 2 possibilité différentes et tout les 2 ne fonctionnent pas correctement

    Possibilité 1

    • Client01 écrit "Client01"
    • Le serveur détecte l'action sur le socket 4, il écoute le socket mais il reste en attente sur ma fonction SSL_read() sans retourner -1, 0 ou le nombre de caractère à écrire.
    • Client02 écrit "Client02"
    • Le serveur écrit "Client02" la ou il s'est bloqué sur le socket n°4, sort de la condition détecte l'activité sur le socket n°5 et affiche "".


    Possibilité 1

    • Client02 écrit "Client02"
    • Le serveur détecte l'action sur le socket 5, il écoute le socket et affiche "Client02"
    • Client01 écrit "Client01"
    • Le serveur détecte l'action sur le socket 4, il écoute le socket mais me retourne -1 alors qu'il y a bien quelque chose sur le socket.


    La question est donc : Comment peut-il afficher les données du 2ème client alors qu'il écoute le socket du 1er client

    Code de la boucle
    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
        while(1)
        {
    	FD_ZERO(&readfd);
    	FD_SET(listen_sock, &readfd);
     
    	fd_max = listen_sock;
     
    	while(myList != NULL)
    	{
    	    FD_SET(myList->val, &readfd);
     
    	    fd_max = max(myList->val, listen_sock);
    	    myList = myList->next;
    	}
    	myList = head;
     
     
    	printf("\nSockets ouverts: "); viewItem(myList);
    	printf("\nAttente action !!\n");
     
    	err = select(fd_max+1, &readfd, 0, 0, 0);
            RETURN_ERR(err, "select()");
     
    	while(myList != NULL)
    	{
    	    if (FD_ISSET(myList->val, &readfd))
    	    {
    		printf("\n\nAction sur socket: %i\n", myList->val);
    		readSock(ssl, buffR, buffRSize);
    		printf("socket %i lu !!\n\n", myList->val);
    		err = close(myList->val);
    		RETURN_ERR(err, "close");
    		delItem(&myList, myList->val);
    	    }
    	    if(myList != NULL) myList = myList->next;
    	}
    	myList = head;
     
     
    	if (FD_ISSET(listen_sock, &readfd)) 
    	{ 
    	    /* Socket for a TCP/IP connection is created */
    	    sock = accept(listen_sock, (struct sockaddr*)&sa_cli, &client_len);
    	    RETURN_ERR(sock, "accept");
     
    	    /* Add the socket in the list */
    	    err = addItem(&myList, sock);
    	    RETURN_SSL(err);
     
    	    //close (listen_sock);
    	    printf ("Connection from %s, port %u\n", inet_ntoa(sa_cli.sin_addr), ntohs(sa_cli.sin_port));
     
    	    /*  TCP connection is ready.  */
    	    /* A SSL structure is created */
    	    ssl = SSL_new(ctx);
    	    RETURN_NULL(ssl);
     
    	    /* Assign the socket into the SSL structure */
    	    err = SSL_set_fd(ssl, queue->val); //sock);
    	    RETURN_ZER(err);
     
    	    /* Perform SSL Handshake on the SSL server */
    	    err = SSL_accept(ssl);
    	    RETURN_SSL(err);
     
    	    /* Informational output (optional) */
    	    printf("SSL connection using %s\n", SSL_get_cipher(ssl));
     
    	    if(SSL_ENABLED)
    	    {
    		/* Get the client s certificate (optional) */
    		client_cert = SSL_get_peer_certificate(ssl);
    		if (client_cert != NULL) 
    		{
    		    printf ("Client certificate:\n");     
    		    str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
    		    RETURN_NULL(str);
    		    printf ("\t subject: %s\n", str);
     
    		    free (str);
    		    str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
    		    RETURN_NULL(str);
    		    printf ("\t issuer: %s\n", str);
     
    		    free (str);
    		    X509_free(client_cert);
    		} 
    		else
    		{
    		    printf("The SSL client does not have certificate.\n");
    		}
    	    }
    	} // end if (listen_sock)
        } // end while
    Code de la fonction readSocket
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /* Receive data from the SSL client */
    void readSock(SSL* ssl,char buffR[], int buffRSize)
    {
        printf("read() - lecture en cours\n");
        int err = SSL_read(ssl, buffR, buffRSize-1);
        printf("read() - nbre caractere: : %i\n", err);
        RETURN_SSL(err); //RETURN_ZER(err);
        printf("read() - lecture OK\n");
     
        buffR[err] = '\0';
        printf ("Received %d chars:'%s'\n", err, buffR);
    }
    Je n'arrive vraiment pas à comprendre pourquoi il reste bloqué sur la fonction SSL_read alors qu'il devrait retourner dans tous les cas une valeur. -1 lors d'erreur, 0 s'il n'y a rien à lire et une valeur >1 pour le nombre de caractère envoyé ...

    merci,
    palo

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 477
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 477
    Par défaut
    Bonjour,

    Je ne sais pas comment est faite SSL_Read() mais, en programmation socket sous UNIX avec un read() ordinaire, un appel réussi à read() mais qui déclare exactement zéro octet lu est en fait le signe que le correspondant a refermé la connexion (ou que l'on a atteint la fin d'un fichier, ou que l'entrée standard a été refermée, soit là encore avec l'atteinte de la fin du fichier, soit avec Ctrl-D).

    Lorsque cela se produit, donc, select() débloque en lecture. Il faut donc traiter ce cas particulier en plus des autres.

  4. #4
    Membre averti
    Inscrit en
    Novembre 2010
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 40
    Par défaut
    Le problème est que lorsque j'écoute le socket 4 (par exemple), il m'affiche le texte du client qui écrit normalement sur le socket 5. Pourtant avec toutes les gestions d'erreurs et les affichages pour le contrôle que je fait, il me dit clairement qu'il est sur le socket n°4 ...

    Par contre si le dernier client qui s'est connecté écrit il n'y a aucun problème, mais tous les autres clients qui vont écrire par la suite vont faire retourner un -1 à mon serveur lors de l'écoute.

    Je suis en train de me demander si je dois créer une structure SSL pour chaque socket, car actuellement j'utilise la même structure pour tous mes sockets.

  5. #5
    Membre averti
    Inscrit en
    Novembre 2010
    Messages
    40
    Détails du profil
    Informations forums :
    Inscription : Novembre 2010
    Messages : 40
    Par défaut
    Bonjour,

    Après être passé à autre chose plusieurs jour pour me reposer l'esprit, j'ai enfin trouvé la provenance de mon erreur.

    Lorsque le socket server accepte les connexions clientes, il créé un nouveau socket (client). J'ajoutais ce socket client dans ma liste chainée, mais il liait aussi ce socket client à un structure SSL et cette dernière contenais tous les sockets dans ma dernière version, au lieu de créer une nouvelle structure SSL pour chaque nouveau client.

    J'ai juste eu à modifier les méthodes d'ajout d'élément dans ma structure pour régler le problème. Voici des parties de mon programme avec les changements en évidence.

    struct.h
    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
    #undef	max
    #define max(x,y)	((x) > (y) ? (x) : (y))
    
    #define EXIT_NULL(x)	if ((x)==NULL) exit(1)
    #define EXIT_ERR(err,s)	if ((err)==-1) { perror(s); exit(1); }
    #define EXIT_SSL(err)	if ((err)==-1) { ERR_print_errors_fp(stderr); exit(1); }
    #define EXIT_ZERO(err)	if ((err)== 0) { ERR_print_errors_fp(stderr); exit(1); }
    
    #define RSA_SERVER_CRT	"../crt/server.crt"
    #define RSA_SERVER_KEY	"../crt/server.key"
    #define RSA_CA_CRT	"../crt/ca.crt"
    
    #define SSL_ENABLED	1 // Set to 1 for authenticate the client
    #define SSL_METHOD	SSLv3_server_method()
    
    struct s_list
    {
        int			val;
        SSL			*pssl;   //AJOUT POUR SOLUTION
        struct s_list	*next;
    };
    Boucle While
    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
        while(1)
        {
    	FD_ZERO(&readfd);
    	FD_SET(listen_sock, &readfd);
    
    	fd_max = listen_sock;
    
    	myList = head;
    	while(myList != NULL)
    	{
    	    FD_SET(myList->val, &readfd);
    
    	    fd_max = max(myList->val, listen_sock);
    	    myList = myList->next;
    	}
    	
    	printf("\nSockets ouverts: "); viewItem(myList);
    	printf("\nAttente action !!\n");
    
    	err = select(fd_max+1, &readfd, 0, 0, 0);
            EXIT_ERR(err, "select()");
    
    	myList = head;
    	while(myList != NULL)
    	{
    	    if (FD_ISSET(myList->val, &readfd))
    	    {
    		printf("Action sur socket: %i\n", myList->val);
    		readSock(myList->pssl, buffR, buffRSize);      // myList->pssl contient la structure SSL associé au socket
    		printf("socket %i lu !!\n\n", myList->val);
    		err = SSL-shutdown(myList->pssl);
    		EXIT_SSL(err);
    		err = close(myList->val);
    		EXIT_ERR(err, "close");
    		SSL_free(myList->pssl);
    		delItem(&myList, myList->val);
    	    }
    	    if(myList != NULL) myList = myList->next;
    	}
    
    	if (FD_ISSET(listen_sock, &readfd)) 
    	{ 
    	    /* Socket for a TCP/IP connection is created */
    	    sock = accept(listen_sock, (struct sockaddr*)&sa_cli, &client_len);
    	    EXIT_ERR(sock, "accept");
    
    	    //close (listen_sock);
    	    printf ("Connection from %s, port %u\n", inet_ntoa(sa_cli.sin_addr), ntohs(sa_cli.sin_port));
    
    	    /*  TCP connection is ready.  */
    	    /* A SSL structure is created */
    	    ssl = SSL_new(ctx);
    	    EXIT_NULL(ssl);
    
    	    /* Assign the socket into the SSL structure */
    	    err = SSL_set_fd(ssl, sock);
    	    EXIT_ZERO(err);
     
    	    /* Perform SSL Handshake on the SSL server */
    	    err = SSL_accept(ssl);
    	    EXIT_SSL(err);
    
    	    /* Add the socket in the list */
    	    err = addItem(&head, sock, ssl); //&myList	// Ajout de la structure et du socket à la liste chainée
    	    EXIT_SSL(err);
    
    	    /* Informational output (optional) */
    	    printf("SSL connection using %s\n", SSL_get_cipher(ssl));
    
    	    if(SSL_ENABLED)
    	    {
    		/* Get the client s certificate (optional) */
    		client_cert = SSL_get_peer_certificate(ssl);
    		if (client_cert != NULL) 
    		{
    		    printf ("Client certificate:\n");     
    		    str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
    		    EXIT_NULL(str);
    		    printf ("\t subject: %s\n", str);
    
    		    free (str);
    		    str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
    		    EXIT_NULL(str);
    		    printf ("\t issuer: %s\n", str);
    
    		    free (str);
    		    X509_free(client_cert);
    		} 
    		else
    		{
    		    printf("The SSL client does not have certificate.\n");
    		}
    	    }
    	} // end if (listen_sock)
        } // end while
    Méthode lié à la structure
    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
    /* Create the new item and assign values */
    int addItem(struct s_list **myList, int num, SSL *ssl)
    {
        /* Create the item */
        struct s_list *newItem = malloc(sizeof(struct s_list));
        if(!newItem)
        {
    	/* Allocation fail */
    	return -1;
        }
        newItem->val = num;
        newItem->pssl = ssl;
        newItem->next = NULL;
     
        if(*myList == NULL)
        {
    	/* First item */
    	*myList = newItem;
    	head = *myList;
    	queue = head;
    	return 1;
        }
        else
        {
    	/* Others items */
    	queue->next = newItem;
    	queue = newItem;
    	return 1;
        }
    }
     
    /* Delete an item in the list */
    int delItem(struct s_list **myList, int num)
    {
        *myList = head;
     
        if(*myList == NULL)
        {
    	/* no item */
    	return -1;
        }
     
        if((*myList)->next == NULL && (*myList)->val == num)
        {
    	/* Last remaining item */
    	*myList = NULL;
    	head = NULL;
    	queue = NULL;
    	return 1;
        }
     
        if(head->val == num)
        {
    	/* First list item */
    	head = head->next;
    	*myList = head;
    	return 1;
        }
     
        /* All others item */
        struct s_list *tmp = *myList;
     
        *myList = head;
        while((*myList) != NULL)
        {
    	if ((*myList)->val == num)
    	{
    	    tmp->next = (*myList)->next;
    	}
     
    	tmp = (*myList);
    	(*myList) = (*myList)->next;
        }
     
        return 1;
    }
     
    /* Print all items in the list */
    int viewItem(struct s_list *myList)
    {
        myList = head;
     
        if(myList == NULL)
        {printf("NULL\n");
    	return -1;
        }
     
     
        while(myList != NULL)
        {
    	printf("%i", myList->val);
    	myList = myList->next;
        }
     
        return 1;
    }

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

Discussions similaires

  1. Problème avec select sous MYSQL
    Par Thomad dans le forum Langage SQL
    Réponses: 2
    Dernier message: 26/01/2006, 11h26
  2. problème avec select sur onchange
    Par Kerod dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 01/12/2005, 14h05
  3. [socket] Problème avec les options
    Par gangsoleil dans le forum Développement
    Réponses: 3
    Dernier message: 13/07/2005, 13h11
  4. Problème avec select top
    Par franculo_caoulene dans le forum MS SQL Server
    Réponses: 8
    Dernier message: 10/12/2004, 14h55
  5. socket : problème avec GetHostByName
    Par SteelBox dans le forum Réseau
    Réponses: 25
    Dernier message: 19/08/2003, 13h49

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