web-dev-qa-db-fra.com

Comment identifier la fin de InputStream dans java

J'essaie de lire les octets du serveur en utilisant le programme Socket, c'est-à-dire que j'utilise InputStream pour lire les octets. Si je passe la taille, je peux lire les octets, mais je ne sais pas quelle peut être la longueur. Je ne suis donc pas en mesure d'initialiser le tableau d'octets.

J'ai aussi essayé while (in.read() != -1), j'ai observé que la boucle fonctionne bien lorsque les données sont envoyées, mais la ligne suivante après la boucle n'est pas exécutable, je sens qu'elle cherche toujours les données dans le flux mais il n'y a pas de données . Si je ferme la connexion au serveur, mon client exécutera la ligne suivante suivie jusqu'à la boucle.

Je ne sais pas où je vais mal?

this.in = socket.getInputStream();

int dataInt = this.in.read();

while(dataInt != -1){
    System.out.print(","+i+"--"+dataInt);
    i++;
    dataInt = this.in.read();
}

System.out.print("End Of loop");

J'obtiens la sortie comme: -

,1--0,2--62,3--96,4--131,5--142,6--1,7--133,8--2,9--16,10--48,11--56,12--1,13--0,14--14,15--128,16--0,17--0,18--0,19--48,20--0,21--0,22--0,23--0,24--0,25--1,26--0,27--0,28--38,29--114,30--23,31--20,32--70,33--3,34--20,35--1,36--133,37--48,38--51,39--49,40--52,41--49,42--55,43--49,44--52,45--52,46--54,47--55,48--50,49--51,50--52,51--48,52--53,53--56,54--51,55--48,56--48,57--57,58--57,59--57,60--57,61--57,62--57,63--57,64--56

Mais pas de sortie pour: - Fin de boucle

Veuillez indiquer comment dois-je fermer la boucle?

Dans l'attente de votre réponse. Je vous remercie tous d'avance.

37
Vardhaman

Il cherche plus de données car rien ne lui dit qu'il y a ne sera pas plus de données. L'autre extrémité du réseau pourrait envoyer plus de données à tout moment.

Il n'est pas clair si vous concevez le protocole client/serveur ou essayez simplement de l'implémenter, mais il existe généralement trois façons courantes de détecter la fin d'un message:

  • Fermeture de la connexion à la fin du message
  • Mettre la longueur du message avant les données elles-mêmes
  • Utiliser un séparateur; une valeur qui ne se produira jamais dans les données normales (ou qui serait toujours échappée d'une manière ou d'une autre)

Personnellement, je préfère le préfixe de longueur lorsque cela est possible; il simplifie considérablement la lecture du code, mais autorise toujours plusieurs messages sur la même connexion.

(De plus, je suis d'accord avec Daniel que vous devriez utiliser la surcharge de read qui lit un tampon entier à la fois, au lieu d'un seul octet. Cela sera beaucoup plus efficace - mais ne changera pas fondamentalement le nature de votre problème actuel.)

49
Jon Skeet

Je pense que vous avez en fait répondu à votre propre question.

La raison pour laquelle vous ne quittez pas la boucle est que la fin du flux d'entrée ne se produit que du côté client après que le serveur a fermé son socket. (Ou plus précisément, après avoir fermé son flux de sortie de socket ... ou l'équivalent ... et que l'événement de fermeture s'est propagé à l'extrémité client.)

Jusqu'à ce que cet événement se produise, il est possible que le serveur décide d'écrire plus de données dans le socket. Ainsi, les blocs de lecture côté client ... jusqu'à ce qu'ils obtiennent plus de données ou qu'ils voient l'événement de protocole indiquant que l'extrémité du serveur est fermée.

(En fait, d'autres événements peuvent débloquer la lecture du client, mais ils entraîneront tous un IOException d'une certaine sorte, et probablement un flux dont vous ne pourrez plus lire les données.)


Maintenant, si vous ne voulez pas fermer l'extrémité du serveur maintenant parce que vous voulez envoyer plus de trucs sur le socket plus tard, vous devrez changer votre protocole d'application pour utiliser une sorte de mécanisme de cadrage. Par exemple, le serveur peut envoyer une trame (ou un enregistrement, ou autre) composé du nombre d'octets suivi du nombre donné d'octets. Alternativement, il pourrait utiliser une valeur d'octet distincte ou une séquence d'octets pour marquer la fin d'une trame.

17
Stephen C

Vous pouvez exécuter cet exemple.

Si vous allez attendre la fin du flux, vous devez le fermer du côté de l'envoi pour que EOF (-1) soit reçu.

Pour envoyer plusieurs messages binaires, je préfère envoyer la longueur avant le message car elle permet au code de lire de gros blocs à la fois (c'est-à-dire parce qu'il sait combien il va obtenir)

ServerSocket ss = new ServerSocket(0);
Socket s = new Socket("localhost", ss.getLocalPort());
Socket s2 = ss.accept();

final OutputStream out = s.getOutputStream();
out.write("Hello World!".getBytes());
out.close();

final InputStream in = s2.getInputStream();
for (int b = 0; ((b = in.read()) >= 0);) {
    System.out.println(b + " " + (char) b);
}
System.out.println("End of stream.");
s.close();
s2.close();
ss.close();

impressions

72 H
101 e
108 l
108 l
111 o
32  
87 W
111 o
114 r
108 l
100 d
33 !
End of stream.
5
Peter Lawrey