|
|
|
|
|
- Présentation
- Fonctionnement
- Exemple
- Code de connexion au serveur et d'envoi de messages
- Code de la procédure Callback de retour
- Exemple de serveur de WebSockets développé en WINDEV
Les WebSockets permettent de communiquer depuis une application Web (site Intranet ou Internet exécuté dans un navigateur) vers un serveur Web en utilisant des sockets. Remarque : Le serveur de WebSockets peut correspondre à une application WINDEV, WEBDEV ou autre. Cette page présente un exemple de serveur de WebSockets réalisé en WLangage avec WINDEV. Pour envoyer un message depuis une application Web en utilisant les WebSockets, il est nécessaire de programmer les traitements suivants côté navigateur : - connexion au serveur,
- envoi de message,
- déconnexion.
Pour cela, vous disposez des mêmes fonctions WLangage que côté serveur :
| | SocketConnecte | Permet de se connecter au serveur de webSockets. | SocketEcrit | Permet d'envoyer un message au serveur de webSockets. | SocketExiste | Permet de vérifier si la socket servant à la connexion n'a pas déjà été créée. | SocketFerme | Permet de fermer la socket une fois les envois de messages terminés. |
Code de connexion au serveur et d'envoi de messages SocketConnecte("client", "ws://<AdresseIPServeur>:5001", ProcRetour)  // Remarque : en cas de connexion en mode sécurisé, utiliser 'wss' à la place de 'ws' // SocketConnecte("client", "wss://<AdresseIPServeur>:5001", ProcRetour) // Attention : en code serveur, il est nécessaire d'utiliser // la fonction SocketCréeSSL à la place de la fonction SocketCrée  Info("fermeture socket...")  SocketFerme("client")
Code de la procédure Callback de retour PROCÉDURE ProcRetour(nEvenement, sMessage) gsRes est une chaîne = ""  SELON nEvenement CAS SocketOuverture : SocketEcrit("client", "Texte du message envoyé depuis le navigateur.") RETOUR CAS SocketMessage : gsRes += [RC] + "Réception du message : " + sMessage  CAS SocketFermeture : gsRes += [RC] + "Fermeture de la socket"  CAS SocketErreur : gsRes += [RC] + "Erreur de la socket : " + sMessage RETOUR AUTRE CAS  FIN Info(gsRes)
Exemple de serveur de WebSockets développé en WINDEV Voici un exemple de code pour réaliser un serveur de WebSockets avec WINDEV. Ce code doit être adapté selon votre configuration et vos besoins (Adresse IP du serveur, ports à ouvrir, ...). Avant de modifier cet exemple, il est nécessaire de connaître la technique et la théorie des WebSockets. Cet exemple n'a pas pour but d'expliquer le fonctionnement théorique des WebSockets. Il montre juste comment utiliser des WebSockets. Pour créer un serveur de WebSockets en WINDEV : - Créez un projet WINDEV.
- Créez une fenêtre vierge
- Créer une procédure locale pServeurSocketEcoute par exemple pour écouter les messages envoyés par le client depuis son site Web. Le code de cette procédure locale est le suivant :
// Code de la procédure locale : Ecoute des messages envoyés par le client socket.  PROCÉDURE pServeurSocketEcoute()  ENTETE_WEBSOCKET_CLIENT est une chaîne = "Sec-WebSocket-Key: " ENTETE_WEBSOCKET_PROTOCOL est une chaîne = "Sec-WebSocket-Protocol: "  // Création du serveur de sockets pour effectuer l'écoute des messages arrivants SI SocketCrée("Serveur", 5001) = Faux ALORS Erreur("Erreur de création " + ErreurInfo(errMessage)) SINON // Process (ou thread) d'écoute des messages // Ce traitement est exécuté en tâche de fond // On écoute en permanence car on ne sait pas quand un message arrive ThreadExécute("Thread1", threadNormal, ProcédureAttente) FIN  //----------------------------------------------------------- // Procédure appelée dans le thread d'écoute PROCÉDURE INTERNE ProcédureAttente()  // Boucle sans fin afin d'attendre une connexion d'un client. // Dès qu'un client se connecte pour envoyer un message, // un thread est lancé afin de gérer les messages arrivants. // La procédure ProcédureGestion gère les messages arrivants. BOUCLE Multitâche(0) SI SocketAttendConnexion("Serveur") ALORS Canal est une chaîne Canal = SocketAccepte("Serveur") SocketChangeModeTransmission(Canal, SocketSansMarqueurFin) ThreadExécute(Canal, threadNormal, ProcédureGestion, Canal) FIN FIN  //-------------------------------------------------------------- // Code de la procédure de gestion des messages arrivants PROCÉDURE INTERNE ProcédureGestion(Canal)  sRequête est une chaîne ANSI tabProtocol est un tableau de chaînes sRes est une chaîne sProtocol est une chaîne = "JSON"  // Lecture de la socket jusqu'à avoir la séquence de terminaison d'un message // Dans notre cas, 2 RC qui se suivent TANTQUE ChaîneOccurrence(sRequête, RC + RC) = 0 sRequête += SocketLit(Canal) FIN  // Traitement de la requête qui arrive // La variable sRequête contient le message à traiter // On analyse la chaîne sClé est une chaîne ANSI POUR TOUTE CHAÎNE sLigne DE sRequête SÉPARÉE PAR RC Trace(sLigne) SI sLigne [=  ENTETE_WEBSOCKET_CLIENT ALORS sClé = sLigne[[Taille(ENTETE_WEBSOCKET_CLIENT)+1 À]] SINON SI sLigne [= ENTETE_WEBSOCKET_PROTOCOL // Récupération des protocoles ChaîneVersTableau(ExtraitChaîne(sLigne, 2, ":"), tabProtocol, ",") FIN FIN   // Préparation de la réponse à envoyer au client sRes = [ HTTP/1.1 101 Web Socket Protocol Handshake Upgrade: websocket Connection: Upgrade WebSocket-Origin: <AdresseIPServeur> WebSocket-Location: ws://<AdresseIPServeur>:5001 Sec-WebSocket-Accept: %1 ] SI tabProtocol..Occurrence <> 0 ALORS sRes += [RC] + "Sec-WebSocket-Protocol: %2" sProtocol = Majuscule(SansEspace(tabProtocol[1])) sRes = ChaîneConstruit(sRes, Crypte(HashChaîne(HA_SHA_160, sClé + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"), "", compresseAucun, encodeBASE64), sProtocol + RC + RC)  SINON sRes = ChaîneConstruit(sRes, Crypte(HashChaîne(HA_SHA_160, sClé + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"), "", compresseAucun, encodeBASE64) + RC + RC) FIN  // Envoi la réponse au client SocketEcrit(Canal, sRes)  BOUCLE bufFrame est un Buffer = SocketLit(Canal) SI 0 = Taille(bufFrame) ALORS Trace("Break") BREAK FIN  nLongueurFrame est un entier = Asc(bufFrame[[2]]) & 127 bufMasque est un Buffer bufDonne est un Buffer SI 126 = nLongueurFrame ALORS nLongueurFrame = HexaVersEntier( BufferVersHexa(bufFrame[[3 SUR 2]])) //BufferVersEntier(bufFrame, 3, 2) bufMasque = bufFrame[[5 À 8]] bufDonne = bufFrame[[9 À]] SINON SI 127 = nLongueurFrame ALORS nLongueurFrame = HexaVersEntier(BufferVersHexa(bufFrame[[3 SUR 8]])) bufMasque = bufFrame[[11 À 14]] bufDonne = bufFrame[[15 À]] SINON bufMasque = bufFrame[[3 À 6]] bufDonne = bufFrame[[7 À]] FIN sTexte est une chaîne ANSI POUR i = 1 _À_ Taille(bufDonne) sTexte += Caract(OUExclusifBinaire( Asc(bufDonne[[i]]), Asc(bufMasque[[(i - 1) modulo 4 + 1]]))) FIN Trace(UTF8VersAnsi(sTexte))  // Formatage de la réponse SELON sProtocol CAS "XML" sRes = [ <XML status="ok"> %1 </XML> ] CAS "JSON" sRes = [ { "status" : "ok", "reponse": "%1" } ] AUTRE CAS sRes = ChaîneVersUTF8("Format non supporté !") FIN sRes = ChaîneConstruit(sRes, sTexte)  nLongueurRéponse est un entier = Taille(sRes) bufRéponse est un Buffer bufRéponse[[1]] = Caract(OUBinaire(0x80, ETBinaire(0x1, 0xF))) SI nLongueurRéponse <= 125 ALORS bufRéponse[[2]] = Caract(nLongueurRéponse) SINON SI nLongueurRéponse <= 65536 ALORS bufRéponse[[2]] = Caract(126) // Manque l'écriture de la longueur bufRéponse += HexaVersBuffer(Droite(EntierVersHexa(nLongueurRéponse), 4)) SINON bufRéponse[[2]] = Caract(127) // Manque l'écriture de la longueur bufRéponse += HexaVersBuffer(EntierVersHexa(nLongueurRéponse)) FIN SocketEcrit(Canal, bufRéponse + sRes) FIN  FIN FIN
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|