Comment bloquer un appele read() sur une socket ?
Bonjour,
Je fais transiter des bytes par le réseau, et la difficulté que j'ai c'est de réussir à bloquer les appels read() .
Code:
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
|
ServerSocket socket = new ServerSocket(12345);
Socket clientSocket;
try
{
clientSocket = socket.accept();
System.out.println("Un nouveau client");
InputStream in2 = clientSocket.getInputStream();
byte fixedByte, id, size;
while(true)
{
System.out.println("reception du message");
fixedByte = (byte) in2.read();
id = (byte) in2.read();
size = (byte) in2.read();
System.out.println(size);
ByteBuffer buf = ByteBuffer.allocate(size+3);
byte[] b = new byte[size];
buf.put(fixedByte);
buf.put(id);
buf.put(size);
in2.read(b);
buf.put(b);
buf.rewind();
System.out.println(buf);
}
}
catch (Exception e)
{
e.printStackTrace();
}
} |
L'affichage
Citation:
serveur
Un nouveau client
// iteration 1
reception du message
52
// le buffer est rempli avec la taille exacte
java.nio.HeapByteBuffer[pos=0 lim=55 cap=55]
// iteration 2
reception du message
// le read() retourn -1
-1
// exception lors ByteBuffer.allocate(size)
java.lang.NegativeArraySizeException
at MainServer.main(MainServer.java:96)
Lors de la 1er itération , les données sont bien récupérés.
Cependant, lors de la 2eme itération, le read() retourn -1,
je ne souhaite pas faire d'attente actives.
Comment je peux m'en sortir?
Merci d'avance.
Pardonnez-moi c'était une fausse piste.
Bonjour,
En fait, je viens de remarquer que vous ne contrôler pas l'état de votre flux. Et d'après la documentation de l'API java, la méthode read de InputStream renvoie le byte lu, ou -1 si la fin du flux est atteinte.
Bref, lorsque votre méthode read renvoie -1, c'est qu'il n'y a plus de données à recevoir.
En générale, on fait un Thread dédié au dialogue. Histoire de remettre le socketserver immédiatement en écoute.
Dans le Thread a qui on aura pris soin de fournie le socket client, on fait un while conditionné sur la validité des données du flux => while (flux.available()>0)
Le plus simple est de bufferiser le dialogue. On crée un byte[1024] de longueur fictive sans se préoccuper du nombre d'octets disponible sur le flux, et on invoque la méthode read(byte[] b). Si les données envoyées représente moins de 1024 octets (taille de notre buffer), ce dernier sera tout simplement comblé de 0 je crois. Le fait de ne plus présenter de données après le read fait sortir le programme de la boucle. Si au contraire les données représentent plus de 1024 octets, notre tableau d'octets sera tout simplement rempli, on boucle, et on poursuit la lecture. Entre temps, celon la nature des données, soit on stock dans un Vector ou autre, soit on concatène dans une chaîne.
Je vous donne un exemple : Je pars du principe que les données sont du texte.
Code:
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
|
Le client :
public class client {
public static void main(String args[]) {
try {
Socket clientSocket = new Socket("localhost", 3456);
BufferedOutputStream ecrivain = new BufferedOutputStream(clientSocket.getOutputStream());
String chaineTest = new String("Coucou et encore coucou...1234567890");
ecrivain.write(chaineTest.getBytes());
ecrivain.flush();
ecrivain.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Le serveur :
public class serveur {
private static Dialogue dialogue = null;
public static void main(String args[]) {
try {
ServerSocket serveur = new ServerSocket(3456);
while (true) {
System.out.println("Message de serveur : \"Serveur à l'écoute...\"");
dialogue = new Dialogue(serveur.accept());
Thread t = new Thread(dialogue);
t.start();
System.out.println("Message de serveur : \"Nouveau dialogue pris en charge.\"");
}
}
catch (Exception e) {}
}
}
Le Thread de dialogue :
public class Dialogue implements Runnable {
private Socket client = null;
public Dialogue(Socket client) {
if (client != null) this.client = client;
}
public void run() {
if (client != null) {
try {
BufferedInputStream fluxIn = new BufferedInputStream(client.getInputStream());
String chaine = new String();
byte[] lecteur = new byte[1024];
while (fluxIn.available() == 0) Thread.sleep(100);
while (fluxIn.available() > 0) {
fluxIn.read(lecteur);
chaine += new String(lecteur);
}
chaine = chaine.substring(0, chaine.indexOf(String.valueOf((char) 0)));
System.out.println("Message de client : \"Message recu :\n" + chaine + "\"");
}
catch (Exception e) {}
}
}
} |
J'ai écrit et testé ce code, il est fonctionnel et m'affiche bien les messages reçus tout en poursuivant l'écoute.:)