2010-05-12 5 views
4

En travaillant sur un serveur WebSocket Java, j'ai rencontré ce bug étrange. Je l'ai réduit à deux petits fichiers Java, l'un est le serveur, l'autre est le client. Le client envoie simplement 0x00, la chaîne Hello puis 0xFF (conformément à la spécification WebSocket).Problème de socket Java sur linux (0xFF envoyé, -3 reçu)

Sur ma machine Windows, le serveur imprime les éléments suivants:

Listening 
byte: 0 
72 101 108 108 111 recieved: 'Hello' 

Tout sur ma boîte unix même imprime le code les éléments suivants:

Listening 
byte: 0 
72 101 108 108 111 -3 

Au lieu de recevoir 0xFF il obtient -3, ne sort jamais de la boucle et n'imprime jamais ce qu'il a reçu.

La partie importante du code ressemble à ceci:

byte b = (byte)in.read(); 
System.out.println("byte: "+b); 

StringBuilder input = new StringBuilder(); 
b = (byte)in.read(); 
while((b & 0xFF) != 0xFF){ 
input.append((char)b); 
System.out.print(b+" "); 
b = (byte)in.read(); 
} 
inputLine = input.toString(); 

System.out.println("recieved: '" + inputLine+"'"); 
if(inputLine.equals("bye")){ 
break; 
} 

J'ai aussi téléchargé les deux fichiers sur mon serveur:

Mon ordinateur Windows exécute Windows 7 et ma machine Linux est r unning Debian

Edit:
Lorsque b est un entier, il agit toujours étrange. J'envoie 0xFF (255) mais reçois 65533 (pas 65535 ou 255).

Répondre

11

Le problème ne figure pas dans le code que vous avez affiché. Il est ici:

in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

Vous avez affaire à des données binaires de sorte que vous devriez utiliser le flux brut - ne pas en faire un Reader, qui est destiné à la lecture caractères.

Vous recevez 65533 car il s'agit de l'entier utilisé pour le "caractère de remplacement Unicode" utilisé lorsqu'une valeur ne peut pas être représentée comme un caractère Unicode réel. Le comportement exact de votre code actuel dépendra du codage de caractères par défaut sur votre système - ce qui n'est pas quelque chose sur lequel vous devriez compter. En outre, vous supposez que chaque octet devrait se traduire par un seul caractère - vous supposez essentiellement ISO-8859-1. Je n'ai pas vérifié la spécification, mais je doute que c'est ce que vous devrait utiliser.

Enfin, vous ne vérifiez pas b étant -1 - qui est utilisé pour indiquer que le client a fermé le flux.

+0

intéressant .... – aioobe

+0

Ah, merci, le lecteur était le problème: D – Marius

0

Un octet avec la valeur de -3 a un motif binaire de 11111101. Et avec la valeur de -3 a la configuration binaire de 11111111111111111111111111111101

Ainsi, vous obtenez essentiellement la même valeur. J'aimerais avoir compris pourquoi vous obtenez -3.

+0

Voir ma réponse ... c'est parce que c'est * en fait * le caractère de remplacement Unicode. –

0

Et votre vérification EOS est incorrecte.Vous devriez lire dans un int et le comparer à -1. Si la valeur est true, vous avez atteint la fin du flux, fermez donc le socket, ou plus probablement le flux de sortie, et procédez en conséquence. Sinon, placez-le dans un octet. Au moment où vous êtes incapable de transmettre 0xff parce qu'il sera traité comme EOS.

3

Une solution différente de Jon ci-dessus, définissez simplement le jeu de caractères comme ISO-8859-1. Par défaut, Java utilise UTF-8. Ainsi, Java interprétera correctement les octets comme les caractères que vous vouliez qu'ils soient. Ceci est nécessaire car 0xFF qui est votre octet final est un caractère invalide en UTF-8. L'autre option consiste à définir le jeu de caractères par défaut pour Java à utiliser avec ISO-8859-1. http://en.wikipedia.org/wiki/UTF-8#Codepage_layout

Je me souviens quand Java est passé de lancer une exception à remplacer le caractère par le caractère de remplacement (int 65533).