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).
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.
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); }
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 :
L'algo donne donc :
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" ); } } }
- 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 :
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.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.
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![]()
Partager