MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

Écrire un serveur WebSocket en Java

Cette traduction est incomplète. Aidez à traduire cet article depuis l'anglais.

Introduction

Cet exemple montre comment cérer une serveur d'API WebSocket API utilisant Java d'Oracle.

Bien que d'autres languages exécutés côté serveur peuvent être utilisés pour créer un serveur de WebSocket, cet exemple utilise Java d'Oracle pour simplifier le code en exemple.

Ce seveur respecte la RFC 6455, dont il prend uniquement en charge les connexions depuis Chrome 16, Firefox 11, IE 10 et au delà.

Premiers pas

WebSockets communique via une connexion TCP (Transmission Control Protocol). La classe Java ServerSocket est située dans le paquet java.net.

ServerSocket

Constructeur :

ServerSocket(int port)

Lors de l'instanciation de la classe ServerSocket, celle-ci est liée au numéro de port renseigné par le paramètre port.

Voici comment implémenter ce que nous venons d'apprendre :

import java.net.ServerSocket;
import java.net.Socket;

public class Server{
    public static void main(String[] args){
        ServerSocket server = new ServerSocket(80);

        System.out.println("Démarrage du serveur sur 127.0.0.1:80.\r\nAttente d’une connexion...");

        Socket client = server.accept();

        System.out.println("Un client s’est connecté.");
    }
}

Socket

Méthodes :

OutputStream

Méthode :

write(byte[] b, int off, int len)

En débutant à partir de la position off, écrit len octets du tableau d'octets fourni.

InputStream

Méthodes :

read(byte[] b, int off, int len)

Reads up to len bytes of data from the input stream into an array of bytes.

Lit jusqu'à len octets de données depuis source d'entrée dans un tableau d'octets.

Développons notre exemple.

Socket client = server.accept();

System.out.println("Un client s’est connecté.");

InputStream in = client.getInputStream();

OutputStream out = client.getOutputStream();

new Scanner(in, "UTF-8").useDelimiter("\\r\\n\\r\\n").next();

Établissement d‘une liaison (handshaking)

Quand un client se connecte à un serveur, il envoit une requête GET pour passer à une connexion WebSocket à partir d'une simple connexion HTTP. Ceci est appelé l’établissement d’une liaison.

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//translate bytes of request to string
String data = new Scanner(in,"UTF-8").useDelimiter("\\r\\n\\r\\n").next();

Matcher get = Pattern.compile("^GET").matcher(data);

if (get.find()) {
    
} else {

}

Créer une réponse est plus facile que de comprendre pourquoi vous devez le faire comme ça.

Vous devez,

  1. obtenir la valeur de la requête d’entête Sec-WebSocket-Key sans aucun espacement;
  2. la lier avec « 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 »;
  3. en calculer les codes SHA-1 et Base64;
  4. renvoyer le résultat comme valeur de l'entête de réponse Sec-WebSocket-Accept qui sera une partie d’une réponse HTTP.
if (get.find()) {
    Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data);
    match.find();
    byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n"
            + "Connection: Upgrade\r\n"
            + "Upgrade: websocket\r\n"
            + "Sec-WebSocket-Accept: "
            + DatatypeConverter
            .printBase64Binary(
                    MessageDigest
                    .getInstance("SHA-1")
                    .digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
                            .getBytes("UTF-8")))
            + "\r\n\r\n")
            .getBytes("UTF-8");

    out.write(response, 0, response.length);
}

Décoder les messages

Après l’établissement réussie d’une liaison, le client peut transmettre des messages au serveur, ils seront désormais encodés.

Si nous envoyons « abcdef », nous obtenons :

129 134 167 225 225 210 198 131 130 182 194 135

- 129:

FIN (est-ce la totalité du message ?) RSV1 RSV2 RSV3 Opcode
1 0 0 0 0x1=0001

FIN : votre message peut être transmis en plusieurs morceaux, mais restons simple pour l’instant.
Opcode 0x1 signifie que ceci est un texte. Liste exhaustive des Opcodes

- 134:

If the second byte minus 128 is between 0 and 125, this is the length of the message. If it is 126, the following 2 bytes (16-bit unsigned integer), if 127, the following 8 bytes (64-bit unsigned integer, the most significant bit MUST be 0) are the length.

Si le second octet moins 128 est entre 0 et 125, alors il s’agit de la longueur du message. Si c’est 126, les deux octets suivants (entier non signé de 16-bits), si c’est 127, les huit octets suivants (entier non signé de 64-bis, dont le poid ford doit être 0) sont la longueur.

Je peux prendre 128 car le premier bit est toujours 1.

- 167, 225, 225 et 210 sont les octets de la clef à décoder. Cela change en permanence.

- Les octets encodés restants constituent le message.

Algorithme de décodage

octet décodé = octet encodé XOR (position de l’octet ET LOGIQUE 0x3)th octet de la clef

Exemple en Java :

byte[] decoded = new byte[6];
byte[] encoded = new byte[] {198, 131, 130, 182, 194, 135};
byte[] key = byte[4] {167, 225, 225, 210};

for (int i = 0; i < encoded.length; i++) {
    decoded[i] = (byte)(encoded[i] ^ key[i & 0x3]);
}

Voir aussi

 

Étiquettes et contributeurs liés au document

 Contributeurs à cette page : Jibec
 Dernière mise à jour par : Jibec,