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 :

TCP/IP , information de connexion rompue


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Octobre 2004
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 59
    Par défaut TCP/IP , information de connexion rompue
    Bonjour,

    je développe actuellement une application utilisant une connexion TCP/IP et je suis confronté à un problème assez ennuyeux.

    Je situe :

    mon application doit dialoguer avec un appareil en protocole ARINC-485. Ce protocole est assez simple, si s'agit d'un mode de question / reponse , 1 question du master (mon application) , et 1 réponse et 1 seule du Slave (l'appareil en question). Lorsque je ne dois pas interroger l'appareil, je dois envoyer une commande "IDLE" , et ce , toutes les secondes.

    Ce dialogue se fait en RS485 mais mon application se trouve sur un matériel embarqué ne possédant qu'une interface TCP/IP. j'ai donc connecté un appareil qui convertit du TCP/IP en RS afin de faire le relais.

    Du coup, mon dialogue question/ reponse se fait non plus en RS485 mais en TCP/IP.

    l'algo intuitif qui vient alors est le suivant : (je ne mets pas le code il est assez enorme).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    while (connexion) {
         // verifier la pile de message en attente. Si elle est vide, y ajouter un message IDLE.
     
        send(socket,prochain_message,len,0);
     
         //  puis derriere 
     
        recv(socket,data,1024,0);   
     
    }
    Seulement, ce code ne convient pas car il peut arriver que je ne recoive pas de données , et vu que la fonction recv est bloquante , je bloquerait indéfiniment sur cette fonction ce qui est inenvisageable.

    La solution apportée est la suivante,plutot que de rendre non bloquante la fonction recv, je la laisse bloquante, et je me sers de la fonction select afin d'attendre l'éventuelle arrivée de données sur la socket, et les lire seulement s'il y a des données présentes :

    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
     
     while (connexion) {
      // verifier la pile de message en attente. Si elle est vide, y ajouter un message IDLE.     
     
      send(socket,prochain_message,len,0);
      struct timeval t;
      t.tv_sec = 1;
      t.tv_usec = 0; // 1000ms de timeout
      fd_set ensemble;
      FD_ZERO(&ensemble);
      FD_SET(m_socket,&ensemble);
      valret = select(socket+1, &ensemble, 0, 0, &t);
    if (valret == SOCKET_ERROR){
        NetworkError("select" );
    }        
    if(FD_ISSET(m_socket,&ensemble)!=0) { // des données sont recues
        valret = recv(socket,data,1024,0);
     if (valret== SOCKET_ERROR)  {
    NetworkError("receive" );                
        }
      } 
     }
    L'algo donne donc :

    - j'envoie des données.
    - j'attends 1 seconde si des données sont arrivées.
    - Si des données sont arrivées , je les lis.

    Seulement, il arrive parfois (et c'est un fonctionnement normal), que certains appareils (le convertisseur TCP/IP-RS ou l'appareil distant) soient mis hors tension , ce qui a pour conséquence de rompre la connexion TCP/IP.

    Hors, je n'ai pas l'indication que la connexion est rompue puisque par défaut, je ne fais que des send.


    Voici un extrait du man send :

    Aucune indication d'échec de distribution n'est fournie
    par send. Seules les erreurs locales sont détectées, et
    indiquées par une valeur de retour -1.
    Je ne peux donc pas utiliser la valeur de retour pour tester une erreur de connexion rompue, puisque seules les erreurs locales sont détectées.

    Par contre, recv me renvoie bien une erreur des que la connexion est rompue mais l'appel ne peut pas passer a cause de la facon dont est fait l'algo ( je ne fais appel a recv que s'il y a des données recues, et il ne peut pas en avoir puisque la connexion est rompue).

    Je n'ai donc que 2 fonctions qui sont appelées quand je suis dans cet état là :
    - send , avec laquelle je ne peux pas gérer cette erreur.
    - select : apparemment cette fonction ne retourne pas non plus d'erreur lorsque la connexion est rompue.

    Je n'arrive pas à voir de solution à mon problème , et je ne sais pas comment détecter qu'une connexion a été rompue (autrement qu'avec un appel à recv).

    Quelqu'un peut il m'éclairer à ce sujet ou dois-je revoir totalement mon algo ?


    merci d'avance

  2. #2
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Par défaut
    Lorsque la connexion est rompue select est declenché, et le recv retourne -1 (enfin je suppose car sous Linux, avec la fonction read c'est comme ca que ca se passe).

    Essaye quand meme.

  3. #3
    Membre confirmé
    Inscrit en
    Octobre 2004
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 59
    Par défaut
    je suis bien sous linux, et il me semble que select ne passe pas. Je refais un test et je viens afficher les logs.

  4. #4
    Membre confirmé
    Inscrit en
    Octobre 2004
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 59
    Par défaut
    hum, j'ai peur que ca ne fonctionne pas

    mon code est portable sous windows et sous linux.

    Voici le log quand je suis sous windows :

    Select : valeur de retour : 1
    Receive STV : F9 9C 6A
    Info : receive IDLE message
    Airshow : NORMAL call
    Airshow : request Status Request
    Try to send (3) (3)bytes
    Select : valeur de retour : 1
    Receive STV : F9 9C 6A
    Info : receive IDLE message
    Write serial 00 00 19 51 19 51 03 10 00 00 00 00 00 00 03 15
    Airshow : NORMAL call
    Airshow : request Status Request
    Try to send (3) (3)bytes
    Select : valeur de retour : 1
    Receive STV : F9 9C 6A
    Info : receive IDLE message
    Airshow : NORMAL call
    Airshow : request Status Request
    Try to send (3) (3)bytes
    <<<<<<< JE SIMULE ICI L ARRET DE LA MACHINE>>>>>>>>>>>>
    Select : valeur de retour : 0
    Airshow : request Status Request
    Try to send (3) (3)bytes
    Select : valeur de retour : 0
    Airshow : request Status Request
    Try to send (3) (3)bytes
    Select : valeur de retour : 0
    Airshow : request Status Request
    Try to send (3) (3)bytes
    Select : valeur de retour : 0
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (12)bytes
    Select : valeur de retour : 0
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (12)bytes
    Select : valeur de retour : 0
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (12)bytes
    Select : valeur de retour : 0
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (12)bytes
    Select : valeur de retour : 0
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (12)bytes
    Select : valeur de retour : 0
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (12)bytes
    Select : valeur de retour : 0
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (12)bytes
    Select : valeur de retour : 0
    Write serial 00 00 0F 23 0F 23 83 00 A0 02 58 00 00 00 05 19
    Airshow : UNINITIALIZED call
    Airshow : request PUS
    Try to send (12) (-1)bytes
    <<<<<<<<<<<< JE RECOIS UNE VALEUR DE RETOUR DE LA PART DE SELECT >>>>>>>>>>>>>>
    Select : valeur de retour : 1
    Network Error : (CTouchLiveTV). Error : 10054 (receive)
    Airshow : CONNECTION LOST call
    Error : Can't connect to address 172.16.201.1 port 4001 for LIVETV
    Airshow : CONNECTION LOST call

    Avant la coupure, la fonction select me renvoie bien la valeur 1, ce qui signifie qu'il y a des données à lire sur une des sockets de mon ensemble (c est a dire, ma socket vu que je n'en ai spécifié qu'une seule).

    Lorsque je simule la coupure, select me renvoie bien 0 vu qu'il n'y a plus de données à lire (je ne peux plus en recevoir, mon appareil est coupé).

    Au bout d'un moment, select me renvoie à nouveau 1, ce qui me permet de passer la ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    if(FD_ISSET(m_socket,&ensemble)!=0) { // des données sont recues
                len= recv(m_socket,data,1024,0);
                if (len == (DWORD)SOCKET_ERROR)  {
                    NetworkError("receive");                
                    return LIVETV_CONNECTIONLOST;
                }
            }
    et ainsi passer dans le recv, qui lui, me renvoie une erreur SOCKET_ERROR.


    Seulement, sous linux ca ne fonctionne pas pareil, le select me renvoie toujours 0 (j'ai laissé tourner pendant 10mn apres ma coupure, et ca ne change rien).

    Ai je mal initialisé mon select ?

    voici le code exact que j'utilise :

    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
     
    t.tv_sec = 1;
            t.tv_usec = 0; // 1000ms de timeout
            fd_set ensemble;
            FD_ZERO(&ensemble);
            FD_SET(m_socket,&ensemble);
            do {
                valret = select(m_socket+1, &ensemble, 0, 0, &t);
                Log(LOGLEVEL_SYSTEM,"Select : valeur de retour : %d",valret);
            } while (valret == SOCKET_ERROR && SocketErrno == EINTR);
     
            if (valret == SOCKET_ERROR){
                NetworkError("select");
                return LIVETV_CONNECTIONLOST;
            }
     
            if(FD_ISSET(m_socket,&ensemble)!=0) { // des données sont recues
                len= recv(m_socket,data,1024,0);
                if (len == (DWORD)SOCKET_ERROR)  {
                    NetworkError("receive");                
                    return LIVETV_CONNECTIONLOST;
                }
            }
     
            else // si timeout ecoulé , alors return NACK
            {
               if (m_dwIdxTrame == 0) 
                   return LIVETV_NORESPONSE;
               else
                   return LIVETV_BADCHECKSUM;
            }

    sachant que je n'utilise qu' une socket, j'ai initialisé le parametre 0 de la fonction select à m_socket+ 1 (m_socket etant la valeur de ma socket).
    Ce parametre est ignoré sous windows mais pas sous linux.


    Je ne comprends pas pourquoi le fonctionnement est différent sous windows et sous linux ?


    merci

  5. #5
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Par défaut
    Je viens de regarder l'un de mes codes et voila la igne que j'avais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    if((lu=read(S.sock, buf, sizeof(buf))) <= 0) {
    /* deconnexion d'un client */
    }

  6. #6
    Membre confirmé
    Inscrit en
    Octobre 2004
    Messages
    59
    Détails du profil
    Informations forums :
    Inscription : Octobre 2004
    Messages : 59
    Par défaut
    Oui, je sais que l'erreur se produira sur un recv (ou read). Seulement , j'ai mon appel a select qui m'en empeche.

    Sous windows le select me renvoie 1 au bout de 30sec ce qui me permet de faire ensuite mon appel a recv qui me renverra -1.
    Sous linux, le select me renvoie tout le temps 0 , et ce, pendant 10mn, comme si la connexion existait toujours (alors qu'elle est bien rompue j'ai débranché le cable reseau pour simuler, et egalement éteint les appareils).

    Le comportement est différent et je ne vois pas pourquoi puisque c'est le meme code pour les 2.

Discussions similaires

  1. [Débutant] Passage d'informations à la connexion sockets
    Par bobylastar49 dans le forum C#
    Réponses: 6
    Dernier message: 13/12/2012, 13h40
  2. Réponses: 4
    Dernier message: 31/03/2011, 10h49
  3. Réponses: 4
    Dernier message: 05/03/2010, 11h15
  4. [BO 5.1.8] Rafraîchir les informations de connexion
    Par greg543 dans le forum Administration-Migration
    Réponses: 14
    Dernier message: 22/11/2007, 23h31
  5. Enregistrer les informations de connexion client RDP
    Par genialk2000 dans le forum Autres Logiciels
    Réponses: 1
    Dernier message: 31/01/2006, 17h24

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