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 :

ReadLine bloquant sur un socket


Sujet :

Entrée/Sortie Java

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 43
    Points : 29
    Points
    29
    Par défaut ReadLine bloquant sur un socket
    Bonjour à tous,

    Tout d'abord je précise que je connais le principe des sockets et l'écriture et la lecture dessus. J'ai également déjà potassé le tuto de http://humbert-florent.developpez.co...reseau/avance/ et ça fait plus de 2h que je suis sur le même problème mais je ne comprends pas pourquoi cela bloque. Mon développement est dans le cadre d'un petit client POP. Donc là ça bloque au niveau de la récupération de l'entête gràce à la commande TOP (pour ceux qui connaissent). Voici mon code :

    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
    public void receiveDataSocket(String fileNameToWriteData, boolean isItForHead) throws .....{
    		
    		String lineReaded = null;
    		
    		try {
    						
    			fw = new FileWriter(fileNameToWriteData, true);
    			output = new BufferedWriter(fw);
    			
    			if(isItForHead){
    				
    				while((lineReaded = fluxReader.readLine()) !=null){
    					output.write(lineReaded);
    					output.flush();		
    				}
    			}
    			else {
    				do {
    					lineReaded = fluxReader.readLine();
    					output.write(lineReaded+"\r\n");
    					output.flush();
    				}while(!(lineReaded.endsWith("\r\n.\r\n")));
    			
    			}
    		} catch (IOException e) {
    			throw new ..........;
    			
    		} finally{
    			try {
    				
    				if(logger.isInfoEnabled())
    					logger.info("Closing flows for the file after reading on the socket.");
    				
    				output.close();
    				fw.close();
    			} catch (IOException e) {
    				throw new ......;
    			}
    		}		
    	}
    L'endroit où c'est bloqué est mentionné en ROSE Pour la réception sur le socket, j'ai recopié exactement la condition du while que je vois partout. J'arrive donc à récupérer en entier l'entête mais il ne sort jamais car mon fluxReader n'est jamais à null....

    Si quelqu'un voit pourquoi je suis preneur.

    Merci d'avance.

  2. #2
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par JavaDoc
    public String readLine()
    Returns:
    A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
    En langage 'socket', la fin du stream (donc la valeur de retour 'null') signifie "la socket est déconnectée".

    Cela n'a pas la même signification que "la socket est toujours connectée mais on n'a plus rien de nouveau à lire pour le moment". Dans ce cas là, readLine() ne renverra pas 'null', mais simplement bloquera l'exécution jusqu'à avoir quelque chose à lire.

    Est-ce bien le comportement attendu ? (personnellement, je ne pense pas, car il me semble que le protocole POP reste connecté après la réponse à une commande telle que TOP).
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 43
    Points : 29
    Points
    29
    Par défaut
    En effet je ne veux pas que ma socket se déconnecte, je veux juste détecter qu'il n'y a plus de données à recevoir à un instant T, est ce que c'est possible ça ou pas ?

    Merci en tout cas de ta réponse.

  4. #4
    Expert éminent sénior Avatar de Uther
    Homme Profil pro
    Tourneur Fraiseur
    Inscrit en
    Avril 2002
    Messages
    4 569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Tourneur Fraiseur

    Informations forums :
    Inscription : Avril 2002
    Messages : 4 569
    Points : 15 525
    Points
    15 525
    Par défaut
    Il n'y a pas de moyen direct de faire sa car s'il n'y a plus de données a un instant T, on ne sait pas vraiment si le buffer est juste provisoirement vidé parceque le client le lis plus vite que le serveur remplis, ou si c'est parceque le serveur a arrêté d'émettre.

    Tu pourrais éventuellement mesurer le délai et considérer que si tu ne reçois plus de données pendant une durée (à déterminer), c'est que le serveur n'émet plus. Pour cela il te faudrais peut être mieux utiliser les méthode d'I/O non bloquantes du package java.nio ou au moins utiliser un Thread séparé pour que l'application ne soit pas bloquée pendant la lecture.

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 43
    Points : 29
    Points
    29
    Par défaut
    Pour le délai je trouve ça un peu sale, car on ne sait pas combien de temps cela peut durer, et pour le thread d'un sens ce qui m'intéresse c'est de faire un truc séquentiellement. C'est à dire à tel moment je récupère l'entête j'attends que ce soit fini, ensuite je demande de créer un fichier avec ce que j'ai lu, et ensuite je réécoute sur le socket pour recevoir le reste du message... C'est étonnant qu'il n'y ai pas dans la RFC un "caractère de fin" pour le TOP comme il en existe un pour RETR CRLF.CRLF

    C'est ça qui m'embête vraiment...

  6. #6
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par Hellnino18 Voir le message
    Pour le délai je trouve ça un peu sale
    Effectivement, le protocole TCP ne donnant aucune garantie de délai de transmission de données, se baser sur le temps est plutôt très hasardeux.

    Avec des connexions WiFi et autres GPRS, il m'est d'ailleurs déjà arrivé de voir la réception des paquets bloquée pendant une dizaine de secondes avant de 'reprendre la main', comme quoi.
    Citation Envoyé par Hellnino18 Voir le message
    C'est étonnant qu'il n'y ai pas dans la RFC un "caractère de fin" pour le TOP comme il en existe un pour RETR CRLF.CRLF
    La RFC 1939 dit le contraire:

    Responses in the POP3 consist of a status indicator and a keyword possibly followed by additional information. All responses are terminated by a CRLF pair. There are currently two status indicators: positive ("+OK") and negative ("-ERR").
    When all lines of the response have been sent, a final line is sent, consisting of a termination octet (decimal code 046, ".") and a CRLF pair. If any line of the multi-line response begins with the termination octet, the line is "byte-stuffed" by pre-pending the termination octet to that line of the response. Hence a multi-line response is terminated with the five octets "CRLF.CRLF".
    Ce paragraphe faisant partie de l'introduction générale du protocole, on parle bien ici du format général des requêtes / réponses, applicable donc à n'importe quelle commande y compris TOP.

    A noter que la description de la commande TOP précise à nouveau qu'on suit ici les préceptes d'une réponse multi-ligne:
    being careful to byte-stuff the termination character (as with all multi-line responses).
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 43
    Points : 29
    Points
    29
    Par défaut
    Oui oui en fait je viens de voir ça donc j'ai fait un test do{ ... } while(monMessage.startsWith("."); Ca marche à peu près, je ne suis pas sur que ce soit optimisé à fond. J'ai fait un test identique avec \n.\n mais cela ne marchait pas...

  8. #8
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par Hellnino18 Voir le message
    Oui oui en fait je viens de voir ça donc j'ai fait un test do{ ... } while(monMessage.startsWith("."); Ca marche à peu près, je ne suis pas sur que ce soit optimisé à fond. J'ai fait un test identique avec \n.\n mais cela ne marchait pas...
    Si j'ai bien compris la RFC, tu as deux cas en fonction du type de réponse (mono-ligne / multi-ligne), plus la façon de gérer l'échappement d'une séquence ".\crlf" faisant partie du contenu d'une réponse.

    Il te faut donc gérer les 3 cas.

    Attention : ton test "\n.\n" ne peut pas marcher si tu attaques ta socket à grands coups de readLine(), car cette fonction te supprime systématiquement le '\n' à la fin de chaque ligne qu'elle te renvoie.
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 43
    Points : 29
    Points
    29
    Par défaut
    Oui tu as le cas d'une monoligne quand tu reçois par exemple un +OK le serveur est prêt et tu as le cas multi-ligne dans le cas où tu reçois soit le header du message soit le message en entier.
    Je gère déjà cette différentiation, il me manque encore le cas avec le .CRLF, et d'après ce que tu me dis ce n'est pas compatible avec un readLine ?

  10. #10
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par Hellnino18 Voir le message
    Je gère déjà cette différentiation, il me manque encore le cas avec le .CRLF, et d'après ce que tu me dis ce n'est pas compatible avec un readLine ?
    Si, c'est compatible, mais il faut que tu prennes en compte dans ton algo de détection de fin de message que le readLine() te 'mange' un CRLF à chaque fin de ligne.

    La traduction française du protocole utilisé pour une réponse multi-ligne (le cas de TOP):
    Certaines commandes ont une réponse sur plusieurs lignes. Dans ces cas, qui sont clairement explicités ci-après, après avoir envoyé la première ligne de la réponse et la séquence CRLF, chaque ligne complémentaire est envoyée, chacune terminée par la séquence CRLF. Lorsque toutes les lignes de la réponse ont été envoyées, une ligne finale est envoyée, formée d’un point (code ASCII décimal 046, " . ") et de la séquence CRLF. Si une des lignes de la réponse commence par un point, ce point est doublé (transmis deux fois consécutivement ou " byte-stuffed "). Ainsi une réponse sur plusieurs lignes se termine par la séquence de cinq octets " CRLF.CRLF ". Lors de l’examen d’une réponse sur plusieurs lignes, le client examine si la ligne commence par un point. Si c’est le cas : si les deux octets suivants ne forment pas la séquence CRLF, le premier octet de la ligne (le point) est enlevé ; sinon (si CRLF suit immédiatement le point), la réponse du serveur POP se termine ici et la ligne (" .CRLF ") n’est pas considérée comme faisant parti de la réponse sur plusieurs lignes.
    Donc:

    - pour détecter la fin de la réponse: tu dois avoir "CRLF . CRLF". Etant donné que tu lis avec readLine(), il va te manger tes deux CRLF. Donc tu détecteras la fin d'un message quand une ligne contiendra uniquement le caractère point (et pas seulement 'commencera par un point').

    - pour détecter un point en début de ligne qui faisait partie du contenu de la réponse: dans ce cas le point a été doublé. Donc tu dois supprimer le premier point.

    - enfin, le point terminal doit être exclu du contenu du message. Il vaut donc mieux une boucle en "while" qu'en "do ... while".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    String responseContent = "";
    while ( !(repLine = out.readLine()).equals(".") ) { 
     
        if (repLine.beginsWith(".") {
            // on enlève le point doublé.
            repLine = repLine.subString(1);
        }
        responseContent += repLine + "\n";
    }
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  11. #11
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 43
    Points : 29
    Points
    29
    Par défaut
    Merci beaucoup de ta réponse, ça semble bien marché, (il faudra que je fasse le test en mettant un point isolé dans un mail pour voir si ça bug ou non). Sinon j'ai testé la taille de mon fichier (où j'enregistre mon mail), elle est différente de 4 octets, mon mail quand je le regarde par Telnet est de 2814 octets, et qand j'enregistre ce mail dans mon fichier il fait 2818octets.

    Cela peut être du à quoi ? (bon à vrai dire pour le moment ce n'est pas trop grave, ça doit être un retour à la ligne ou quelque chose dans le genre qui a sauté...)

  12. #12
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Points : 2 161
    Points
    2 161
    Par défaut
    Citation Envoyé par Hellnino18 Voir le message
    Sinon j'ai testé la taille de mon fichier (où j'enregistre mon mail), elle est différente de 4 octets
    Là, sans exemples concrets avec fichiers attachés, on ne pourra rien conclure.
    Mon projet du moment: BounceBox, un jeu multijoueurs sur Freebox, sur PC et depuis peu sur smartphone/tablette Android.

  13. #13
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Février 2009
    Messages
    43
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 43
    Points : 29
    Points
    29
    Par défaut
    Je vais chercher de mon côté, je vais passer le topic en résolu et je te remercie toi et Uther de m'avoir aiguillé et aider sur mon problème, cela me permet comme ça de garder la moitié des cheveux qu'il me reste (après en avoir arracher la moitié hier )

    Merci beaucoup.

    Hellnino

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

Discussions similaires

  1. [Réseau] select() et accept() sur plusieurs sockets
    Par Higestromm dans le forum C++
    Réponses: 13
    Dernier message: 13/10/2008, 09h18
  2. Probleme de read() bloquant sur un socket.
    Par gregb34 dans le forum C++
    Réponses: 26
    Dernier message: 16/04/2008, 15h11
  3. Lecture non bloquante sur plusieurs Sockets avec nio
    Par ratakses dans le forum Entrée/Sortie
    Réponses: 9
    Dernier message: 19/04/2007, 16h14
  4. Réponses: 3
    Dernier message: 20/10/2006, 19h50
  5. Questionsssss sur les sockets?
    Par Nino dans le forum Développement
    Réponses: 5
    Dernier message: 01/04/2003, 21h11

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