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 :

UDP : Serveur RPi 2 Clients Arduino DUE - Problème réception paquets


Sujet :

Réseau C

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Octobre 2015
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Corse (Corse)

    Informations professionnelles :
    Activité : Ingénieur d'études

    Informations forums :
    Inscription : Octobre 2015
    Messages : 1
    Points : 1
    Points
    1
    Par défaut UDP : Serveur RPi 2 Clients Arduino DUE - Problème réception paquets
    Salut à tous !

    Après de nombreuses recherches infructueuses, je me tourne vers vous afin de partager mon désarroi face à ce symptôme étrange.

    Je suis en train de créer un réseau de synchronisation entre un RPi 2 qui joue le rôle de diffuseur de synchro et d'Arduino DUE équipées du Shiel Ethernet 2 qui jouent le rôle d'esclaves à synchroniser.

    J'emets donc une trame avec le RPi en broadcast UDP sur le réseau, mes Arduinos se synchronisent sur une trame et envoient une réponse au serveur.

    Symptôme :
    • La récupération des réponses des clients fonctionne parfaitement bien 2 fois, je récupère simultanément la réponse de mes esclaves.
    • Les réceptions suivantes, je reçois un coup l'un, un coup l'autre... Mais à aucun moment je ne récupère les deux ensembles alors que, côté Arduino, je vois bien la récupération se faire sur les différents clients, simultanément toujours.


    Voici mon code "serveur" (récupéré et assemblé avec différentes sources sur le net) :
    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
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
     
    #include <stdio.h> //printf
    #include <string.h> //memset
    #include <stdlib.h> //exit(0);
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <poll.h>
     
    #define SERVER "192.168.1.255"
    #define BUFLEN 512  //Max length of buffer
    #define PORT 8888   //The port on which to send data
    #define MY_IP "192.168.1.2" //Master's IP
    #define NB_SLAVES 2
     
    void die(char *s)
    {
        perror(s);
        exit(1);
    }
    char readNonBlock(int fd,struct sockaddr_in * si,int slen) {
    	char c='0';
    	char buf[BUFLEN];
    	char ip_sender[BUFLEN];
    	struct pollfd   fds;
        /* on regarde sur l'entree standard */
        fds.fd = fd;
        fds.events = POLLIN;
    memset(buf,'\0', BUFLEN);
        if ( ! poll(&fds, 1, 1) ) {
    		printf("en attente d'un caractère\n" );
    		return c;
     
    		}
    	/*if ( fds.revents & ( POLLOUT | POLLERR | POLLHUP ) ) {
    		printf("Deconnexion ... fin de fichier\n" );
     
    		 ici on sait que le read va retourner 0 
    		}*/
    	if ( recvfrom(fd, buf, BUFLEN, 0, (struct sockaddr *) si, &slen)< 0 ) {
    		printf("Probleme de lecture..." );
    		/* ici le read à foiré */
    		}
    	else{
    		//sprintf(ip_sender," %s\0",inet_ntoa(si->sin_addr));
    		//printf("port is: %d\n", (int) ntohs(si.sin_port));
    		puts(inet_ntoa(si->sin_addr));
    		puts(buf);
    		c='a';
    	}
    	// on a lu un caractère
    	return c;
    	}	
     
    int main(void)
    {
        struct sockaddr_in si_other;
        int s, slen=sizeof(si_other);
        //char buf[BUFLEN];
        char waitingSlaves[12]={'1','1','1','0','0','1','1','0','1','0','1','0'};
     
        if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
        {
            die("socket");
        }
        int broadcastEnable=1;
        int ret=setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
     
        memset((char *) &si_other, 0, sizeof(si_other));
        si_other.sin_family = AF_INET;
        si_other.sin_port = htons(PORT);
     
        if (inet_aton(SERVER , &si_other.sin_addr) == 0) 
        {
            fprintf(stderr, "inet_aton() failed\n");
            exit(1);
        }
     
        if (bind(s, (struct sockaddr* ) &si_other, sizeof(si_other))==-1)
     {
         err("bind");  
     }else{
         printf("Server : bind() successful\n");  
     }
     
        while(1)
        {
    	int j;
    	char ip_sender[12];
    	puts("BIIIIP");
            for(j=0;j<12;j++){
    			//send waitingSlaves
    			if (sendto(s, waitingSlaves+j, 1 , 0 , (struct sockaddr *) &si_other, slen)==-1)
    			{
    			    die("sendto()");
    			}
             }
            //receive a reply and print it
            //clear the buffer by filling null, it might have previously received data
            //memset(buf,'\0', BUFLEN);
            //try to receive some data, this is a blocking call
     
            /*if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1)
            {
                die("recvfrom()");
            }*/
     
           while((recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)>=0)&&(compteur<=NB_SLAVES)){
            	sprintf(ip_sender," %s\0", inet_ntoa(si_other.sin_addr));
    		//printf("port is: %d\n", (int) ntohs(si_other.sin_port));
    		puts(ip_sender);
    		puts(buf);
            	memset(buf,'\0', BUFLEN);
    		compteur++;
    		if(compteur==NB_SLAVES){
    			break;
    		}
            }
            while(readNonBlock(s,&si_other,slen)!='0');
     
     
    	sleep(3);
        }
     
        close(s);
        return 0;
    }
    Comme vous pouvez le constater, j'ai tenté différentes méthodes pour résoudre le problème (elles ne sont pas toutes présentes ici mais je vais vous les détailler immédiatement) :
    • Ligne 105 : C'est le code de base que j'avais récupéré, un code bloquant mais qui récupérait bien tous les messages. J'étais juste obligé de le ctrl+c et de relancer à la mano.
    • Ligne 110 : Récupération du précédent et sortie de boucle avec un compteur de réponses. Le symptôme est apparu là...
    • Ligne 121 : Ré-utilisation d'un code que j'avais sous le coude pour de la lecture Serial, adapté à notre cas. Le symptôme est toujours là.

    De plus j'ai tenté :
    • Thread de l'écoute. J'ai du bidouiller pour le faire fonctionner mais toujours le même symptôme.
    • Création de plusieurs sockets d'écoute (1 pour chaque client chacun sur un port différent) même symptôme.


    Côté Arduino : Il récupère la trame paquet par paquet et dès que la trame est complète, il envoie un message au serveur.
    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
     
    /*
     UDPSendReceiveString:
     This sketch receives UDP message strings, prints them to the serial port
     and sends an "acknowledge" string back to the sender
     
     A Processing sketch is included at the end of file that can be used to send
     and received messages for testing with a computer.
     
     created 21 Aug 2010
     by Michael Margolis
     
     This code is in the public domain.
     */
     
     
    #include <SPI.h>         // needed for Arduino versions later than 0018
    #include <Ethernet2.h>
    #include <EthernetUdp2.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008
     
     
    // Enter a MAC address and IP address for your controller below.
    // The IP address will be dependent on your local network:
    byte mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x1C, 0xFD};
    //byte mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x1C, 0xB8};
    IPAddress ip(192, 168, 1, 3);
    //IPAddress ip(192, 168, 1, 4);
    unsigned int localPort = 8888;      // local port to listen on
     
    // buffers for receiving and sending data
    char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  //buffer to hold incoming packet,
    char  ReplyBuffer[] = "synchronized";       // a string to send back
    char structSync[12]={'1','1','1','0','0','1','1','0','1','0','1','0'};
    // An EthernetUDP instance to let us send and receive packets over UDP
    EthernetUDP Udp;
    int compteur;
    char phrase[12];
     
    void setup() {
      // start the Ethernet and UDP:
      Ethernet.begin(mac, ip);
      Udp.begin(localPort);
     
      Serial.begin(9600);
      Serial.println("Listening UDP");
    }
     
    void loop() {
      // if there's data available, read a packet
      Serial.print("loop n ");
      Serial.println(compteur);
      int packetSize = Udp.parsePacket();
      if (packetSize==1) {
        IPAddress remote = Udp.remoteIP();
        // read the packet into packetBufffer
        Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
        phrase[compteur]=packetBuffer[0];
        compteur++;
        if(compteur==12){
          compteur=0;
          if(phrase[0]==structSync[0]){
            if(phrase[1]==structSync[1]){
              if(phrase[2]==structSync[2]){
                if(phrase[3]==structSync[3]){
                  if(phrase[4]==structSync[4]){
                    if(phrase[5]==structSync[5]){
                      if(phrase[6]==structSync[6]){
                        if(phrase[7]==structSync[7]){
                          if(phrase[8]==structSync[8]){
                            if(phrase[9]==structSync[9]){
                              if(phrase[10]==structSync[10]){
                                if(phrase[11]==structSync[11]){
                                // send a reply to the IP address and port that sent us the packet we received
                                Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
                                Udp.write(ReplyBuffer);
                                Udp.endPacket();
                                //Udp.flush();
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
     
        }
      }
    }
    En plus de ce qui est présenté au dessus, j'ai tenté :
    • Mettre l'adresse ip du serveur en dur
    • Mettre le port de réponse en dur (le même pour tous et 1 unique pour chacun)


    Voilà, j'espère avoir été clair sur ma méthodologie, si l'un d'entre vous pourrait m'expliquer d'où vient le soucis et, peut-être, m'aider à le résoudre, ce serait fortement sympathique

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Salut,

    je n'ai pas lu tout ton code, mais ce que tu racontes ressemble juste à de la perte de paquets. Classique en UDP.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonjour
    Il n'y a pas mal de choses qui m'interpellent dans vos différents codes sources surtout la partie Arduino.
    D'un notre côté comme la souligné @Bousk le protocole UDP ne garantit en rien la bonne livraison des données à son destinateur, ni leur ordre d'arrivée.

    Premières choses qui me piquent les yeux dans les instructions de la partie Arduino, c'est le compteur.
    Concrètement, je pense pas qu'il soit de très grandes utilités (plus clairement il sert absolument à rien). Il est également préférable de mettre une temporisation avant de passer à nouveau dans la boucle et ceux pour une bonne raison (une pause avant d'initialiser toutes les données, instructions et se mettre en attente de lecture de données).

    Concrètement pour vos différents symptômes il faut comprendre ceci.
    Tout d'abord le protocole (un petit rappel que le protocole) UDP ne garantit pas la délivrance des données en état au destinataire sans compté que ces données peuvent être livrées bien après leur envoies pire, aucune donnée de transmis (perte totale des données) et là où ça se complique en plus des caractéristiques de l'UDP. C'est qu'il y a un encombrement de transmission ou d'acquisition des données du côté serveur.
    (
    Citation Envoyé par Estema Voir le message
    ... J'emets donc une trame avec le RPi en broadcast UDP sur le réseau, mes Arduinos se synchronisent sur une trame et envoient une réponse au serveur.
    ).
    Ce qui justifie le comportement actuel (s'il y a encombrement sur un réseau qui utilise le protocole UDP on a systématiquement des pertes de données). Pour ma part, je pense qu'il est préférable d'utiliser le protocole UDP pour l'émission ou la réception de petit message sur l'état de vos capteurs ou l'affichage d'information brève.

    Voici une version très simple basé sur le code source précédent
    Code C : 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
     
    /*
     * sketckExemple.c
     * Utilisation du protocole UDP.
     * Created by sambia39 on 07/11/2015.
     * Copyright © Developpez.net. GPLv 3 
     */
     
    #include <SPI.h>
    #include <Ethernet.h>
    #include <EthernetUdp.h>
     
    /*
     * Liste des variables
     * & types de donnée
     */
    EthernetUDP I_UdpArduino;
    unsigned int Iport_srv = 6789;
    char Buffer_data[UDP_TX_PACKET_MAX_SIZE];
    char Buffer_rep_Arduino[]= "synchronized\0";
    byte Ip_arduino[] = { 192,168,12,12 }; /* Exemple addr ip */
    byte Mac_arduino[] = { 0x90, 0xA2, 0xDA, 0x10, 0x1C, 0xFD };
     
    /*
     * Fonction de définition et
     * initialisation des données
     */
    void setup(){
      Ethernet.begin( Mac_arduino, Ip_arduino );
      I_UdpArduino.begin( Iport_srv );
      Serial.begin( 9600 );
    }
     
     
    /*
     * Boucle principale d'exécution
     * des instructions du programme
     */
    void loop(){
     
      int iData = I_UdpArduino.parsePacket();
      /*  Si des paquets dont disponible 
       *  déclanchement de la lecture des
       *  paquets.
       */
      if( iData ){
     
        /*  lecture des données dans un buffers */
        I_UdpArduino.read( Buffer_data, UDP_TX_PACKET_MAX_SIZE);
     
        /*  Renvoie des données ou une réponse au serveur  */
        I_UdpArduino.beginPacket( I_UdpArduino.remoteIP(),
          I_UdpArduino.remotePort() );
     
        /*  Envoie des données  */
        I_UdpArduino.write( Buffer_rep_Arduino );
        I_UdpArduino.endPacket(); /*  Fin de transmission */
      }
      delay(10);
    }

    Pour la partie serveur c'est aux différents clients de se connecter au serveur puis le lui soumettre les requêtes afin qu'ils soient traités.
    le serveur pourrais transmettre des ordres ou autres dans un autre moyen de transmission garantissant l'intégrité des données "si possible" (je pense par exemple au I2C ou autres de façon à être sous la configuration du type ETS -> Entrée-traitement-Sortie) mais libre à vous de faire autrement.
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

Discussions similaires

  1. [UDP] Serveur fixe port client
    Par sone47 dans le forum Réseau
    Réponses: 4
    Dernier message: 12/01/2012, 09h30
  2. [Débutant] Problème socket serveur (attente du client)
    Par synolog dans le forum C#
    Réponses: 14
    Dernier message: 20/10/2011, 18h16
  3. Réponses: 4
    Dernier message: 29/04/2009, 16h01
  4. [Domaine] Problème lenteur entre 1 serveur et 1 client
    Par Bomba dans le forum Windows Serveur
    Réponses: 4
    Dernier message: 25/04/2007, 18h15
  5. problème d'accès aux données sur serveur par poste client
    Par rahan_dave dans le forum Requêtes
    Réponses: 1
    Dernier message: 25/02/2006, 09h13

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