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

avec Java Discussion :

data In/Out putStream et available()


Sujet :

avec Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Flutter/java/windev/php/javascript
    Inscrit en
    Octobre 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Flutter/java/windev/php/javascript
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 87
    Par défaut data In/Out putStream et available()
    Bonjour,
    je reprends actuellement le code d'un projet qui communique avec une puce embarquée programmée en C.
    La communication se fait via des DataInputStream et dataOutputStream comme suit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public Network(Socket socket) {
            try {
                this.socket = socket;
                this.dis = new DataInputStream(socket.getInputStream());
                this.dos = new DataOutputStream(socket.getOutputStream());
             } catch (IOException ex) {
                Logger.getLogger(Network.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    le client (ici le matériel embarqué donc) se connecte sur un port, on récupere la socket via un accept -> donc TCP et on la passe à la classe Network qui va gérer les stream.
    jusque là pas de soucis.

    pour lire et ecrire on passe par des tableau de byte comme ceci:

    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
    public boolean sendTrame(String trame) {
            try {
                int z;
                int i = 0;
                int j;
                String Hex;
                byte buffer[] = new byte[trame.length() / 2];
                for (z = 0; z < (trame.length()); z++) {
                    Hex = "";
                    Hex = Hex + trame.charAt(z);
                    z++;
                    Hex = Hex + trame.charAt(z);
                    j = Integer.parseInt(Hex, 16);
                    buffer[i] = (byte) (j & 0xFF);
                    i++;
                }
                while(dis.available() > 0) { //On vide le stream au cas ou
                    dis.readByte();
                }
                dos.write(buffer);
                dos.flush();
            } catch (IOException ex) {
                console.traceError("NETWORK_MANAGER", "sendTrame" , ex);
                return false;
            } catch (IndexOutOfBoundsException ex) {
                return false;
            }
            return true;
        }
    et ceci:

    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
    public String receiveTrame() {
            byte[] messageByte = new byte[512];
            String trame = null;
            int size = 0;
            try{
                while (dis.available()>0) {
                    messageByte[size] = dis.readByte();
                    size++;
                }
            } catch (IOException ex) {
             console.traceError("NETWORK_MANAGER", "receiveTrame", ex); //Fin de stream normalement detecté via dis.available()
            }
            if(size > 0) trame = "";
            else console.traceError("NETWORK_MANAGER", "Aucune réponse");
            for (int i = 0; i < size; i++) {
                trame = trame + String.format("%02X", messageByte[i] & 0xFF);
            }
            return trame;
        }
    je l'utilise donc comme cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
                    socket = clients.getClient(); //il se cache derrière un ArrayList<Socket>() en attente de traitement créée avec un accept() dans un autre thread
                    socket.setKeepAlive(true);
                    socket.setSoTimeout(5000);
                    network = new Network(socket, true);
                    network.sendTrameDmeLan(maRequete);
                    trame = network.receiveTrameDmeLan();
    Mon problème c'est que je reçois 8 fois sur 10 une erreur sur la lecture: je retrouve dis.avalaible() == 0 dans la plupart des cas...
    je passe probablement à cotes d'un truc con mais je n'arrive pas à trouver quoi :/
    pour moi dis.readByte() et sensé être bloquant tant que je n'ai rien dans le stream. vu qu'il est vidé avant je devrait y trouver la réponse de ma puce embarqué du coup...

    voilà en gros mon problème... merci à vous pour vos éventuelles réponses.

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Hello,

    le plus simple pour comprendre le cas de available(), c'est qu'il ne sert à rien. Parfaitement inutile. Une méthode fournie dans les temps anciens de Java, qui avait l'air d'une bonne idée dans l'état de l'art de l'époque, mais se révèle sans intérêt.

    En général, quand on appelle une méthode, c'est qu'on attend d'elle quelque chose, mener une action, fournir une information utile, bref on l'appelle parce qu'elle sert à quelque chose.

    Mais available() ne sert à rien. Donc quand on l'appelle, c'est qu'on s'attend à quelque chose, mais elle ne fera pas ce quelque chose, elle ne sert à rien. Donc il ne faut pas l'appeler. Il faut programmer sans jamais s'en servir, où que ce soit.

    Pour savoir si une stream est terminée, on le sait parce que read() renvoie -1, ou parce que read(byte[]) indique que zéro bytes on été lus, donc il n'y en a plus à lire. Mais en faisant comme ça on ne peut pas utiliser readByte().

    Pour utiliser readByte() et savoir combien de fois il faut l'appeler, il faut que cette information soit envoyée dans la stream. Par exemple, le premier octet envoie d'abord combien d'octets il y a dans la trame. Ensuite pour lire la trame, le premier octet indique sa taille, et il n'y a plus qu'à lire ce nombre d'octets.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre confirmé
    Homme Profil pro
    Flutter/java/windev/php/javascript
    Inscrit en
    Octobre 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Flutter/java/windev/php/javascript
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 87
    Par défaut
    Pour utiliser readByte() et savoir combien de fois il faut l'appeler, il faut que cette information soit envoyée dans la stream. Par exemple, le premier octet envoie d'abord combien d'octets il y a dans la trame. Ensuite pour lire la trame, le premier octet indique sa taille, et il n'y a plus qu'à lire ce nombre d'octets.
    je n'ai malheureusement pas la possibilité de modifier ce stream, c'est un protocole propriétaire établie depuis des années auquel je n'ai pas accès.
    je vais dèjà supprimer les available et voir ce que je peux faire du coup.

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Du moment que la socket se ferme après chaque trame, il n'y a pas de problème. Il suffit de lire jusqu'à la fin du stream.

    Sinon, ben, il faut bien trouver un moyen de dire quand une trame commence et quand elle se termine. Et s'il se trouve que available() pourrait par hasard donner des informations correctes à ce sujet de temps en temps, tu as déjà remarqué le problème que ce n'est pas franchement fait pour.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Pour résumer, available te dit ce qui se trouve dans le buffer java de la classe DataInputStream, en gros. Ca ne veux pas dire que l'appelant à l'autre bout de la connection tcp a tout envoyé, ca ne veux pas dire qu'il ne reste pas un bout de la trame dans le buffer noyau à la réception, qu'un équipement sur le trajet a bouffé la moitié du packet et qu'il faudra attentre le renvoi tcp pour avoir la fin, etc.

    Pour ce qui est de savoir ce que tu dois lire, y a pas d'avance, si le protocole derrière tes trame fonctionne un tant soit peu, quelque chose à été prévu. Ca peut être de dire que toutes les trames on la même taille fixe, ou qu'un header quelconque permet de calculer quand on arrive à la fin, ou qu'une séquence de bytes particulier indique la fin de la trame. Tout ce que tu peux faire, c'est appeler les méthodes de lecture jusqu'à la fin de ta trame.

    Enfin, vu le bas niveau de ta gestion de trame, je travaillerais directement avec InputStream plutot que DataInputStream qui risque de bufferiser / interpréter / réordonner certains trucs.

  6. #6
    Membre confirmé
    Homme Profil pro
    Flutter/java/windev/php/javascript
    Inscrit en
    Octobre 2008
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Flutter/java/windev/php/javascript
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 87
    Par défaut
    Bon, j'ai testé pas mal de trucs et j'ai à peu près ceci qui provient du matos embarqué:
    - 2 bytes -> 4F4B ("OK")
    - une structure de x bytes en fonction de la configuration (la c'est variable donc compliqué)
    - un header: FF 00 00 SIZE DATAS[]

    donc dans certains cas je peux faire un read() sur une taille reçu -> ça c'est bon
    dans le cas du OK bah je détecte que ça ne commence pas pas FF -> du coup je teste 4F4B et je m'y retrouve
    par contre pour les réponse de tailles variable je me retrouve avec un délai de timeout seconde à chaque fin de transmission lié au read() et je n'ai aucun fin de chaîne (si je retrouve celui qui à fait le protocole je fais une pierrade de ses mains et je lui fais manger...)
    du coup j'utilise readbyte() qui n'a pas de timeout mais il n'attend pas toujours l'arrivé des données non plus donc je cherche encore...

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

Discussions similaires

  1. [J2SSH] Channel'In/Out'putStream problème
    Par Cyrodiil dans le forum API standards et tierces
    Réponses: 4
    Dernier message: 30/11/2010, 11h21
  2. In/out putStreams (bytearray, piped, image)
    Par ghetolay dans le forum Débuter avec Java
    Réponses: 6
    Dernier message: 18/12/2009, 12h35
  3. Data truncation: Out of range value
    Par briceg dans le forum Développement de jobs
    Réponses: 7
    Dernier message: 06/11/2009, 16h37
  4. Réponses: 1
    Dernier message: 28/05/2007, 09h52
  5. datetime data type resulted in an out-of-range
    Par faamugol dans le forum ASP
    Réponses: 2
    Dernier message: 26/05/2004, 20h51

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