Les méthodes de communication courantes basées sur Ajax (http) entre les clients Web et les serveurs sont divisées en connexions courtes et interrogations longues .
Connexion courte : chaque fois que le client et le serveur effectuent une opération HTTP, une connexion est établie et la connexion prend fin lorsque la tâche est terminée.
Interrogation longue : le client demande des données au serveur comme une interrogation traditionnelle. Cependant, si le serveur ne dispose pas de données pouvant être renvoyées immédiatement au client, il ne renverra pas immédiatement un résultat vide, mais maintiendra la requête en attente de l'arrivée des données (ou d'un délai d'attente approprié : inférieur au délai d'attente ajax). , puis renvoie les données en conséquence au client.
Le mécanisme d'interrogation longue est illustré dans la figure ci-dessous :
2. Concepts de base de WebsocketWebSocket est un protocole de communication full-duplex sur une seule connexion TCP que HTML5 a commencé à fournir.
WebSocket simplifie l'échange de données entre le client et le serveur, permettant au serveur de transmettre activement les données au client. Dans l'API WebSocket, le navigateur et le serveur n'ont besoin que d'une poignée de main, et une connexion persistante peut être créée directement entre les deux pour une transmission de données bidirectionnelle.
Dans l'API WebSocket, le navigateur et le serveur n'ont besoin que d'effectuer une action de négociation, puis un canal rapide est formé entre le navigateur et le serveur. Les données peuvent être transmises directement entre les deux.
De nos jours, afin de mettre en œuvre la technologie push, de nombreux sites Web utilisent le sondage Ajax. L'interrogation se produit lorsque le navigateur envoie une requête HTTP au serveur à un intervalle de temps spécifique (par exemple toutes les secondes), puis le serveur renvoie les dernières données au navigateur du client. Ce modèle traditionnel présente des inconvénients évidents, c'est-à-dire que le navigateur doit envoyer en permanence des requêtes au serveur. Cependant, la requête HTTP peut contenir un long en-tête, dans lequel les données réellement valides ne peuvent constituer qu'une petite partie, ce qui est évidemment un gaspillage. . Beaucoup de bande passante et d'autres ressources.
Le protocole WebSocket défini par HTML5 permet de mieux économiser les ressources et la bande passante du serveur et de permettre davantage de communications en temps réel.
Le navigateur envoie une demande au serveur pour établir une connexion WebSocket via JavaScript. Une fois la connexion établie, le client et le serveur peuvent échanger directement des données via la connexion TCP.
Après avoir obtenu la connexion Web Socket, vous pouvez envoyer des données au serveur via la méthode send() et recevoir les données renvoyées par le serveur via l'événement onmessage.
3. Principe de prise de contact Websocket :Le principe de poignée de main de Websocket peut être grossièrement divisé en les étapes suivantes :
Implémentation du code :
import socket, base64, hashlib# Créer une connexion socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# Lier l'adresse de fin et le numéro de port sock.bind(('127.0.0.1', 9527))# Écouter sock.listen (5)# Récupère la connexion de l'objet socket client, adresse = sock.accept()# Obtenez les informations [handshake] du client data = conn.recv(1024)print(data)def get_headers(data) : supprimez la valeur correspondant à Sec-WebSocket-Key de l'en-tête de la requête et renvoyez header_dict = {} header_str = data.decode ( utf8) pour i dans header_str.split(/r/n) : if str(i).startswith(Sec-WebSocket-Key) : return i.split(:)[1].strip()# Récupère la valeur correspondant à Sec-WebSocket-Key ws_key = get_headers(data)# La chaîne magique chaîne magique est : 258EAFA5-E914-47DA-95CA-C5AB0DC85B11magic_string = '258EAFA5 -E914-47DA-95CA-C5AB0DC85B11'# Épissage socket_str = ws_key + magic_string# sha1 chiffrement socket_str_sha1 = hashlib.sha1(socket_str.encode(utf8)).digest()# cryptage base64 socket_str_base64 = base64.b64encode(socket_str_sha1)# En-tête de réponse d'épissage réponse_tpl = HTTP/1.1 101 Commutation Protocoles/r/n / Mise à niveau : websocket/r/n / Connexion : Mise à niveau/r/n / Sec-WebSocket-Accept : %s/r/n / WebSocket-Location : ws://127.0.0.1:9527/r /n/r/n % (socket_str_base64.decode(utf8))# Le serveur envoie l'en-tête de réponse au client conn.send(response_tpl.encode(utf8))# Le client et le serveur établissent une longue connexion pour recevoir et envoyer des données en boucle while True : msg = conn.recv(8096) print( msg)
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Titre</title></head><body></body><script type=text/javascript> ws = new WebSocket(ws://127.0.0.1:9527); ws.onmessage = function (ev) { console.log(ev)//pour recevoir des données}</script></html>
Vous trouverez ci-joint l'en-tête de la requête HTTP initiée par le client :
b'GET /ws/ HTTP/1.1Hôte : 127.0.0.1:9527Connexion : Mise à niveauPragma : no-cacheCache-Control : no-cacheUser-Agent : Mozilla/5.0 (Windows NT 10.0 ; WOW64) AppleWebKit/537.3...Mise à niveau : websocketOrigin : http://localhost:63342Sec-WebSocket-Version : 13Accept-Encoding : gzip, deflate, brAccept-Language : zh-CN,zh;q=0.9Sec-WebSocket-Key : kJXuOKsrl3AR1KeFngRElQ==Sec-WebSocket-Extensions : permessage- dégonfler ; client_max_window_bits'4. Méthodes de cryptage et de décryptage Websocket :
Méthode de décryptage :
# b'/x81/x87/x0e/xc3/xf3/xcd;/xf6/xc6/xf8;/xf6/xc6'==========5555555hashstr = b'/x81/x87/x0e/xc3 /xf3/xcd;/xf6/xc6/xf8;/xf6/xc6'# Effectuez une opération sur les bits sur le deuxième octet, qui est /x87 bits 9 à 16, et 127 payload = hashstr[1] & 127# Lorsque le résultat de l'opération sur les bits est égal à 127, les 3 à 10 octets correspondent à la longueur des données# Octets 11-14 sont la chaîne requise pour le déchiffrement du masque #Les données vont du 15ème octet à la fin si payload == 127 : extend_payload_len = hashstr[2:10] mask = hashstr[10:14] decoded = hashstr[14:]# Lorsque le résultat de l'opération sur les bits est égal à 126, alors les 3 à 4 octets correspondent à la longueur des données # Les 5 à 8 octets sont la chaîne requise pour le décryptage du masque # Ensuite, le data Du 9ème octet à la fin si payload == 126 : extend_payload_len = hashstr[2:4] mask = hashstr[4:8] decoded = hashstr[8:]# Lorsque le résultat de l'opération sur les bits est inférieur ou égal à 125, alors ce nombre correspond à la longueur des données # Les 3 à 6 octets sont la chaîne requise pour le décryptage du masque # Les données vont du 7ème octet à la fin si la charge utile <= 125 : extend_payload_len = Aucun masque = hashstr[2:6] decoded = hashstr[6:]str_byte = bytearray()pour i in range(len(decoded)) : byte = decoded[i] ^ mask[i % 4] str_byte.append(byte)print(str_byte.decode(utf8))
Méthode de cryptage :
import structmsg_bytes = 5555555.encode(utf8)token = b/x81length = len(msg_bytes)si longueur < 126 : token += struct.pack(B, length)elif length == 126 : token += struct.pack(!BH , 126, longueur)else : token += struct.pack(!BQ, 127, longueur)msg = jeton + msg_bytesprint(msg)4. Exemples de communication de liaison client et serveur basée sur le framework flask et le protocole Websocket :
pip3 install gevent-websocket
from flask import Flask, requestfrom geventwebsocket.websocket import WebSocketfrom gevent.pywsgi import WSGIServerfrom geventwebsocket.handler import WebSocketHandlerapp = Flask(__name__)@app.route(/ws)def websocket(): # Récupère le lien de l'utilisateur user_socket = request.environ. obtenir(wsgi.websocket) # type:WebSocket print (accès réussi) while True : msg = user_socket.receive() #Recevoir un message print(msg) user_socket.send(msg) #Envoyer un message si __name__ == '__main__' : # Spécifiez l'adresse et le numéro de port à ouvrez le service Websocket http_serv = WSGIServer ((127.0.0.1, 8001), application, handler_class=WebSocketHandler) # Démarrez le service Websocket http_serv.serve_forever()
fichier html :
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Titre</title> <link href=https://cdnjs.cloudflare.com/ajax/libs/twitter- bootstrap/3.3.7/css/bootstrap.css rel=stylesheet></head><body><botton class=btn btn-default onclick=createsocket()>Cliquez pour créer un lien</botton><br><p>Veuillez saisir un message : <input type=text placeholder=Input message id=msg></p><buttom class=btn btn- success onclick =send_msg()>Envoyer un message</buttom><script> var ws = null function createsocket() { ws = new; WebSocket(ws://127.0.0.1:8001/ws); ws.onmessage = function (data) { console.log(message reçu du serveur=,data.data } } function send_msg() { var to_msg = document.getElementById(msg).value; ws.send(to_msg) }</script></body></html>
client.png
Côté serveur.png
De cette façon, nous implémentons simplement la communication client-serveur via le protocole Websocket. Et nous pouvons créer plusieurs liens pour communiquer avec le côté serveur en même temps.
5. Implémentez la messagerie instantanée (MI) basée sur Websocket :Code du serveur :
depuis flask import Flask, requête depuis geventwebsocket.websocket import WebSocket depuis gevent.pywsgi import WSGIServer depuis geventwebsocket.handler import WebSocketHandler depuis geventwebsocket.exceptions import WebSocketErrorimport jsonapp = Flask(__name__)user_socket_dict = {}@app.route(/ws/<username>)def websocket(username): # Récupère le lien de l'utilisateur user_socket = request.environ.get(wsgi.websocket) # type:WebSocket user_socket_dict[username] = user_socket print(username+link réussi !) while True : msg = user_socket.receive() # Acceptez les messages pour le socket dans user_socket_dict.values() : # tapez :WebSocket si user_socket != socket:# Si vous envoyez un message vous-même, le serveur ne vous répondra pas. essayez : socket.send(json.dumps({sender: username, msg: msg})) sauf : continueif __name__ == '__main__ ': # Spécifiez l'adresse et le numéro de port pour ouvrir le service Websocket http_serv = WSGIServer((127.0.0.1, 8001), app, handler_class=WebSocketHandler) # Démarrez le service Websocket http_serv.serve_forever()
code html :
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Titre</title> <link href=https://cdnjs.cloudflare.com/ajax/libs/twitter- bootstrap/3.3.7/css/bootstrap.css rel=stylesheet></head><body><p>Veuillez entrer votre pseudo :<input type=text id=username></p><botton class=btn btn-default onclick=createsocket()>Cliquez pour créer le lien</botton><br><p>Veuillez saisir le message : <input type=text id=msg >< /p><buttom class=btn btn-success onclick=send_msg()>Envoyer un message</buttom><br><br><br><div style=border: 2px solide ; largeur : 500 px ; hauteur : 800 px ; id=text_div></div><script> var ws = null ; var username = null ; WebSocket(ws://127.0.0.1:8001/ws + / + nom d'utilisateur); ws.onmessage = fonction (données) { var text_div = document.getElementById(text_div); var obj_data = JSON.parse(data.data); var add_msg = <p> + obj_data.sender + : + obj_data.msg + </p>; innerHTML += add_msg; } } function send_msg() { var to_msg = document.getElementById(msg).value; var text_div = document.getElementById(text_div); var add_msg = <p style='text-align: right'> + to_msg + : + nom d'utilisateur + </p>; = add_msg; ws.send(to_msg); }</script></body></html>
Client01.png
Client02.png
Côté serveur.png
Le code est un code de démonstration, avec des bugs et des bugs. Il est principalement utilisé pour l'apprentissage pour le moment, donc aucun pinaillage n'est autorisé. Ceux qui sont intéressés peuvent optimiser davantage ! ! !
Ce qui précède représente l’intégralité du contenu de cet article. J’espère qu’il sera utile à l’étude de chacun. J’espère également que tout le monde soutiendra le réseau VeVb Wulin.