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

Entrée/Sortie Java Discussion :

Trame reçue en plusieurs étapes


Sujet :

Entrée/Sortie Java

  1. #1
    Membre du Club
    Inscrit en
    Août 2008
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 184
    Points : 49
    Points
    49
    Par défaut Trame reçue en plusieurs étapes
    Bonjour,

    Je suis entrain de faire un serveur socket avec API NIO, ma question est la suivante , comment je peux recevoir les messages (sous forme de string en Hexa) dans le cas où il y a des problèmes ou des surcharge coté réseau ce qui va entrainer que mes trames vont arrivé en plusieurs morceau ,sachant que je connais pas la taille du message envoyé par un client.
    voici mon code utilisé jusqu’à maintenant :
    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
     
    while (active) {
     
    					try {
    						selector.select();
    						Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
     
    						while (keys.hasNext()) {
     
    							try {
    								SelectionKey key = keys.next();
    								keys.remove();
     
    								if (!key.isValid()) {
    									continue;
    								}
     
    								//l'évenement correspond à une acceptation de connexion
    								if(key.isAcceptable()) {
     
    									SocketChannel channel = server.accept();
    									channel.configureBlocking(false);
    									channel.register(selector, SelectionKey.OP_READ);
    									System.out.println("Client is connected");
    								}
    								//l'évenement correspond à une lecture
    								else if(key.isReadable()) {
     
    									SocketChannel client = (SocketChannel) key.channel();
    									doRead(client, key);
     
    								}
    								//l'évenement correspond à l'écriture
    								else if(key.isWritable()) {
     
    									SocketChannel client = (SocketChannel) key.channel();
    									doWrite(client, key);
     
    								}
    							} catch (IOException e) {
    								trace.println(-1, "Exception in channel", e);
    								if(keys != null)
    									keys.remove();
    							}
    						}
    					} catch (ClosedChannelException e) {
    						trace.println(-1, "Exception in closing channel", e);
    					} catch (IOException e) {
    						trace.println(-1, "Exception in channel", e);
    					}
    			}
    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
     
    public void  doRead(SocketChannel client , SelectionKey key) throws IOException {
     
    		ByteBuffer readBuffer = ByteBuffer.allocate(8192);
    		readBuffer.clear();
    		int numread ;
    		while (true) {
     
                numread = client.read( readBuffer );
     
                if (numread <=0) {
                  break;
                }
     
              }
     
    		if (numread == -1) {
     
    			return ;
    		}
     
    		readBuffer.flip() ;
    		System.out.println("SERVER RECEVE : " + new String(readBuffer.array())) ;
    		processCommunication(client , readBuffer);
    		key.interestOps(SelectionKey.OP_WRITE) ;
     
     
    	}
    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
     
    public void doWrite(SocketChannel client , SelectionKey key) throws IOException {
     
    		//ByteBuffer resp = ByteBuffer.wrap(("ACK : "+message).getBytes());
     
    		ByteBuffer resp = queuedWrites.get(client) ;
     
    		System.out.println("SERVER RESPONSE :" + new String(resp.array())) ;
     
    		while (true) {
     
    			int n = client.write(resp) ;
     
    			if (n == 0 || resp.remaining() == 0)
    				break ;
    		}	
     
    		key.interestOps(SelectionKey.OP_READ) ;
     
    		if("ACK".equalsIgnoreCase(new String(resp.array()).trim())) {
    			client.close();
    			key.channel().close();
    			key.cancel();
    		}
     
    	}
    J'ai lu sur le net , qu'il faut utiliser un objet attaché au Key , mais je sais pas comment faire cela pour résoudre mon problème
    Merci d'avance

  2. #2
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 565
    Points : 21 631
    Points
    21 631
    Par défaut
    Il n'est pas autorisé de "ne pas savoir quelle est la taille d'un message." La première chose que doit contenir un message, c'est sa propre taille. Ou alors il doit exister un genre de délimiteur qui permet de reconnaître qu'il est terminé. Auquel cas, il faut lire et accumuler les données, attachées à la Key, jusqu'à atteindre le délimiteur.
    Sauf si une socket ne peut transmettre qu'un seul message, là il suffit de lire la socket jusqu'à ce que son flux de lecture soit fermé.

  3. #3
    Membre du Club
    Inscrit en
    Août 2008
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 184
    Points : 49
    Points
    49
    Par défaut
    Je vais recevoir des trames de déférente taille , c'est possible que j'aurai des \r\n pour dire que c'est la fin de la trame , mais comment faire que cumuler les messages d'un même key ?
    Y-a-t-il un exemple ou un bout de code SVP?

  4. #4
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 565
    Points : 21 631
    Points
    21 631
    Par défaut
    J'ai pas d'exemple sous la main, mais il suffit d'associer un ByteArrayOutputStream à la SelectionKey. Puis tu y mets tout ce que tu reçois.

    ... Si tu dois chercher des \r\n qui séparent les messages, il vaudrait mieux associer une List<ByteBuffer>, et tu crées et ajoute un nouveau ByteBuffer à chaque fois que le dernier est plein. Ce sera un peu meilleur niveau performances.

  5. #5
    Membre du Club
    Inscrit en
    Août 2008
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 184
    Points : 49
    Points
    49
    Par défaut
    mon problème que j'ai pas un \r\n à chaque fois , je vous donne un exemple :
    Le client envoie la chaine suivante : FF1DE29B063900010900000001AEC31C4673539304977F23000708C41C46CD569304547323002C8F0744C41C4672689304F38423002981025DC41C4672729304B186230051030000300000\n\r
    Il se peut que je reçois cette chaine en 3 étapes :
    FF1DE29B063900010900000001AEC31C4673539304977F23000708C41C46CD5693
    puis :
    04547323002C8F0744C41C4672689304F38423002981025D
    et à la fin :
    C41C4672729304B186230051030000300000\n\r

  6. #6
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 565
    Points : 21 631
    Points
    21 631
    Par défaut
    Eh ben quoi ?

    Partons sur l'idée d'un ByteArrayOutputStream :

    - Quand tu reçois une trame, tu regardes si elle contient un \r\n.
    -- Si non, tu l'ajoutes au ByteArrayOutputStream.
    -- Si oui,
    --- tu ajoutes tout ce qu'il y a avant le \r\n au ByteArrayOutputStream,
    --- tu l'enlèves, et tu traites son contenu comme un message.
    --- Tu poses un nouveau ByteArrayOutputStream, et tu traites le reste de la trame comme si c'était une nouvelle trame reçue.

    Quel est le problème ?

  7. #7
    Membre du Club
    Inscrit en
    Août 2008
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 184
    Points : 49
    Points
    49
    Par défaut
    Merci thelvin pour tes explications

    C'est ce que je veux faire ,mais je bloque sur un nouveau problème:
    1) je reçois jamais mes \r\n dans j'affiche le bytebuffer .
    Qand j'affiche mon buffer , j'ai ma string en plus de caractères bizzare sous forme de carreau!!!
    2) j'arrive pas à copier le contenu du bytebuffer dans le ByteArrayOutputStream (je veus copier seulement le contenu pas tout le buffer)

    Voila mon code utilisé :

    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
     
    public void  doRead(SocketChannel client , SelectionKey key , ByteArrayOutputStream buffer) throws IOException {
    		System.out.println("DoRead");
    		boolean isEnd = false;
    		ByteBuffer readBuffer = ByteBuffer.allocate(512);
    		readBuffer.clear();
    		int numread ;
    		while (true) {
     
                numread = client.read( readBuffer );
     
                if (numread <=0) {
                  break;
                }
     
              }
     
    		if (numread == -1) {
     
    			return ;
    		}
     
    		readBuffer.flip() ;
    		System.out.println("SERVER RECEVE : " + new String(readBuffer.array())) ;
     
    		buffer.write(readBuffer.array());
     
    		System.out.println("ALL BUFFER : " + new String(buffer.toByteArray())) ;
    		while(readBuffer.hasRemaining()) {
    			 Char c = (Char)readBuffer.get();
    			 if (c == '\n' || c == '\r') {
    				 System.out.println("isEnd now");
    				 isEnd = true;
    				 break;
    			 }
    		}
    		if(isEnd) {
    			System.out.println("End");
    			//msgQueue.add(buffer);
    			key.interestOps(SelectionKey.OP_WRITE) ;
    		}		
    	}
    Merci pour vos aides.

  8. #8
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 565
    Points : 21 631
    Points
    21 631
    Par défaut
    Bon, ça avance pas mal.

    Citation Envoyé par cyclopsnet Voir le message
    1) je reçois jamais mes \r\n dans j'affiche le bytebuffer .
    Et t'es sûr qu'il y en a, au moins ? Au début tu disais "peut-être." Comment les messages sont-ils séparés dans tes échanges réseau ?

    Citation Envoyé par cyclopsnet Voir le message
    Qand j'affiche mon buffer , j'ai ma string en plus de caractères bizzare sous forme de carreau!!!
    Probablement des zéros, dûs au fait que tu copies le buffer entier dans le ByteArrayOutputStream, au lieu de seulement ce qu'il a reçu.

    Citation Envoyé par cyclopsnet Voir le message
    2) j'arrive pas à copier le contenu du bytebuffer dans le ByteArrayOutputStream (je veus copier seulement le contenu pas tout le buffer)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    buffer.write(array, start, length);

  9. #9
    Membre du Club
    Inscrit en
    Août 2008
    Messages
    184
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 184
    Points : 49
    Points
    49
    Par défaut
    C'est résolu voilà le code de a méthode si qlq en aura besoin :
    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
     
    public void  doRead(SocketChannel client , SelectionKey key , ByteArrayOutputStream buffer) throws IOException {
     
    		boolean isEnd = false;
     
    		ByteBuffer readBuffer = ByteBuffer.allocate(512);
    		readBuffer.clear();
     
    		int numread = 0 , capacity = 0;
     
    		while (isRunning) {
     
    			numread = client.read( readBuffer );
     
    			if(numread > 0)
    				capacity = numread;
     
    			if (numread <=0) {
    				break;
    			}
    		}
     
    		if (numread == -1) {
     
    			return ;
    		}
     
    		readBuffer.flip() ;
     
    		buffer.write(readBuffer.array() , 0 , capacity);
     
    		while(readBuffer.hasRemaining()) {
    			String c = new String(new byte[] {readBuffer.get()});
    			if ("\n".equalsIgnoreCase(c) || "\r".equalsIgnoreCase(c)) {
    				isEnd = true;
    				break;
    			}
    		}
     
    		if(isEnd) {
    			synchronized (msgQueue) {
    				msgQueue.notify();
    			}
    			msgQueue.add(ByteBuffer.wrap(buffer.toByteArray()));
    			key.interestOps(SelectionKey.OP_WRITE) ;
    		}
     
    		//	processCommunication(client , readBuffer);
     
     
     
    	}
    Merci thelvin

  10. #10
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 565
    Points : 21 631
    Points
    21 631
    Par défaut
    ... Mais ça a pas de sens. Il se passe quoi si tu as encore des caractères après le \r ou le \n ?
    Ils se retrouvent ajoutés au message qui essaie de s'arrêter avant eux.

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

Discussions similaires

  1. Réponses: 7
    Dernier message: 04/07/2017, 20h15
  2. Réponses: 4
    Dernier message: 11/09/2008, 17h12
  3. [MySQL] Un petit exemple de formulaire en plusieurs étapes
    Par guismoman33 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 27/03/2008, 17h57
  4. Réponses: 2
    Dernier message: 26/09/2007, 16h45
  5. Réponses: 19
    Dernier message: 21/11/2006, 11h57

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