Los métodos de comunicación comunes basados en Ajax (http) entre clientes y servidores web se dividen en conexiones cortas y sondeos largos .
Conexión corta: cada vez que el cliente y el servidor realizan una operación HTTP, se establece una conexión y la conexión finaliza cuando se completa la tarea.
Sondeo largo: el cliente solicita datos del servidor como un sondeo tradicional. Sin embargo, si el servidor no tiene datos que puedan devolverse al cliente inmediatamente, no devolverá un resultado vacío inmediatamente, sino que mantendrá la solicitud esperando a que lleguen los datos (o un tiempo de espera apropiado: menor que el tiempo de espera de ajax). y luego devolver los datos como resultado del cliente.
El mecanismo de sondeo largo se muestra en la siguiente figura:
2. Conceptos básicos de WebsocketWebSocket es un protocolo para comunicación full-duplex en una única conexión TCP que HTML5 comenzó a proporcionar.
WebSocket simplifica el intercambio de datos entre el cliente y el servidor, permitiendo que el servidor envíe datos activamente al cliente. En la API WebSocket, el navegador y el servidor solo necesitan completar un protocolo de enlace y se puede crear una conexión persistente directamente entre los dos para la transmisión de datos bidireccional.
En la API WebSocket, el navegador y el servidor solo necesitan realizar una acción de protocolo de enlace y luego se forma un canal rápido entre el navegador y el servidor. Los datos se pueden transmitir directamente entre los dos.
Hoy en día, para implementar la tecnología push, muchos sitios web utilizan el sondeo Ajax. El sondeo se produce cuando el navegador emite una solicitud HTTP al servidor en un intervalo de tiempo específico (como cada 1 segundo) y luego el servidor devuelve los datos más recientes al navegador del cliente. Este modelo tradicional tiene desventajas obvias, es decir, el navegador necesita enviar solicitudes continuamente al servidor. Sin embargo, la solicitud HTTP puede contener un encabezado largo, en el que los datos reales válidos pueden ser solo una pequeña parte, lo que obviamente es un desperdicio. Mucho ancho de banda y otros recursos.
El protocolo WebSocket definido por HTML5 puede ahorrar mejor los recursos del servidor y el ancho de banda y permitir una mayor comunicación en tiempo real.
El navegador envía una solicitud al servidor para establecer una conexión WebSocket a través de JavaScript. Una vez establecida la conexión, el cliente y el servidor pueden intercambiar datos directamente a través de la conexión TCP.
Después de obtener la conexión Web Socket, puede enviar datos al servidor a través del método send() y recibir datos devueltos por el servidor a través del evento onmessage.
3. Principio del protocolo de enlace de Websocket:El principio de protocolo de enlace de Websocket se puede dividir aproximadamente en los siguientes pasos:
Implementación del código:
import socket, base64, hashlib# Crear una conexión de socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# Vincular la dirección final y el número de puerto sock.bind(('127.0.0.1', 9527))# Escuchar sock.listen (5)# Obtenga la conexión del objeto de socket del cliente, dirección = sock.accept()# Obtenga la información del [apretón de manos] del cliente data = conn.recv(1024)print(data)def get_headers(data): elimine el valor correspondiente a Sec-WebSocket-Key del encabezado de la solicitud y devuelva header_dict = {} header_str = data.decode (utf8) para i en header_str.split(/r/n): si str(i).startswith(Sec-WebSocket-Key): regresar i.split(:)[1].strip()# Obtenga el valor correspondiente a Sec-WebSocket-Key ws_key = get_headers(data)# La cadena mágica La cadena mágica es: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11magic_string = '258EAFA5 -E914-47DA-95CA-C5AB0DC85B11'# Empalme socket_str = ws_key + magic_string# cifrado sha1 socket_str_sha1 = hashlib.sha1(socket_str.encode(utf8)).digest()# cifrado base64 socket_str_base64 = base64.b64encode(socket_str_sha1)# Encabezado de respuesta de empalme Response_tpl = HTTP/1.1 101 Conmutación Protocolos/r/n / Actualización: websocket/r/n / Conexión: Actualización/r/n / Sec-WebSocket-Aceptar: %s/r/n / WebSocket-Ubicación: ws://127.0.0.1:9527/r /n/r/n % (socket_str_base64.decode(utf8))# El servidor envía el encabezado de respuesta al cliente conn.send(response_tpl.encode(utf8))# El cliente y el servidor establecen una conexión larga para recibir y enviar datos en un bucle mientras es Verdadero: msg = conn.recv(8096) print( mensaje)
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Título</title></head><body></body><script type=text/javascript> ws = new WebSocket(ws://127.0.0.1:9527); ws.onmessage = function (ev) { console.log(ev)//para recibir datos}</script></html>
Se adjunta el encabezado de la solicitud HTTP iniciada por el cliente:
b'GET /ws/ HTTP/1.1Host: 127.0.0.1:9527Conexión: UpgradePragma: no-cacheCache-Control: no-cacheUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.3...Actualización: 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- desinflar; client_max_window_bits'4. Métodos de cifrado y descifrado de Websocket:
Método de descifrado:
# 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'# Realice una operación de bits en el segundo byte, que es /x87 bits 9-16 y 127 carga útil = hashstr[1] & 127# Cuando el resultado de la operación de bits es igual a 127, los 3-10 bytes son la longitud de los datos # Bytes 11-14 son las cadenas necesarias para descifrar la máscara #Los datos van desde el byte 15 hasta el final si la carga útil == 127: extend_payload_len = hashstr[2:10] mask = hashstr[10:14] decodificado = hashstr[14:]# Cuando el resultado de la operación de bits es igual a 126, entonces los 3-4 bytes son la longitud de los datos # Los 5-8 bytes son la cadena requerida para el descifrado de la máscara # Entonces el datos Desde el noveno byte hasta el final si carga útil == 126: extend_payload_len = hashstr[2:4] máscara = hashstr[4:8] decodificado = hashstr[8:]# Cuando el resultado de la operación de bits es menor o igual a 125, entonces este número es la longitud de los datos # Los 3-6 bytes son la cadena requerida para el descifrado de la máscara # Los datos van desde el séptimo byte hasta el final si la carga útil <= 125: extend_payload_len = Ninguna máscara = hashstr[2:6] decodificado = hashstr[6:]str_byte = bytearray()for i in range(len(decodificado)): byte = decodificado[i] ^ máscara[i % 4] str_byte.append(byte)print(str_byte.decode(utf8))
Método de cifrado:
importar structmsg_bytes = 5555555.encode(utf8)token = b/x81length = len(msg_bytes)if longitud < 126: token += struct.pack(B, longitud)elif longitud == 126: token += struct.pack(!BH , 126, longitud)de lo contrario: token += struct.pack(!BQ, 127, longitud)msg = token + msg_bytesprint(msj)4. Ejemplos de comunicación de enlace de cliente y servidor basados en el marco flask y el protocolo 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(): # Obtener el enlace del usuario user_socket = request.environ. obtener (wsgi.websocket) # escriba: WebSocket print (acceso exitoso) mientras que True: msg = user_socket.receive() #Recibir mensaje print(msg) user_socket.send(msg) #Enviar mensaje si __name__ == '__main__': # Especifique la dirección y el número de puerto para abra el servicio Websocket http_serv = WSGIServer ((127.0.0.1, 8001), aplicación, handler_class=WebSocketHandler) # Iniciar el servicio Websocket http_serv.serve_forever()
archivo html:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Título</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()>Haga clic para crear un enlace</botton><br><p>Ingrese un mensaje: <input type=text placeholder=Ingrese id del mensaje=msg></p><buttom class=btn btn- éxito al hacer clic =send_msg()>Enviar mensaje</buttom><script> var ws = null función createsocket() { ws = nuevo; WebSocket(ws://127.0.0.1:8001/ws); ws.onmessage = función (datos) { console.log(mensaje recibido del servidor =,datos.data); función send_msg() { var to_msg =); document.getElementById(msg).value; ws.send(to_msg) }</script></body></html>
cliente.png
Lado del servidor.png
De esta forma, simplemente implementamos la comunicación cliente-servidor a través del protocolo Websocket. Y podemos crear múltiples enlaces para comunicarnos con el lado del servidor al mismo tiempo.
5. Implementar mensajería instantánea (IM) basada en Websocket:Código del servidor:
desde flask importar Flask, solicitud desde geventwebsocket.websocket importar WebSocket desde gevent.pywsgi importar WSGIServer desde geventwebsocket.handler importar WebSocketHandler desde geventwebsocket.exceptions importar WebSocketErrorimport jsonapp = Flask(__name__)user_socket_dict = {}@app.route(/ws/<username>)def websocket(nombre de usuario): # Obtener el enlace del usuario user_socket = request.environ.get(wsgi.websocket) # tipo:WebSocket user_socket_dict[nombre de usuario] = user_socket print(nombre de usuario+enlace exitoso!) while True: msg = user_socket.receive() # Aceptar mensajes para socket en user_socket_dict.values(): # tipo:WebSocket si user_socket != socket:# Si envía un mensaje usted mismo, el servidor no le responderá, intente: socket.send(json.dumps({sender: nombre de usuario, msg: msg})) excepto: continueif __name__ == '__main__. ': # Especifique la dirección y el número de puerto para abrir el servicio Websocket http_serv = WSGIServer((127.0.0.1, 8001), app, handler_class=WebSocketHandler) # Iniciar el servicio Websocket http_serv.serve_forever()
código html:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Título</title> <link href=https://cdnjs.cloudflare.com/ajax/libs/twitter- bootstrap/3.3.7/css/bootstrap.css rel=stylesheet></head><body><p>Ingrese su apodo:<input type=text id=username></p><botton class=btn btn-default onclick=createsocket()>Haga clic para crear el enlace</botton><br><p>Ingrese el mensaje: <input type=text id=msg >< /p><buttom class=btn btn-success onclick=send_msg()>Enviar mensaje</buttom><br><br><br><div style=border: 2px sólido; ancho: 500px; alto: 800px; id=text_div></div><script> var ws = null; var nombre de usuario = null; función createsocket() { nombre de usuario = document.getElementById(nombre de usuario). WebSocket(ws://127.0.0.1:8001/ws + / + nombre de usuario ws.onmessage = función); (datos) { 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>; internalHTML += add_msg; } } función enviar_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 + : + nombre de usuario + </p>; = add_msg; ws.send(to_msg); }</script></body></html>
Cliente01.png
Cliente02.png
Lado del servidor.png
El código es un código de demostración, con errores y errores. Por el momento, se utiliza principalmente para aprender, por lo que no se permiten críticas. ¡Aquellos que estén interesados pueden optimizar aún más! ! !
Lo anterior es el contenido completo de este artículo. Espero que sea útil para el estudio de todos. También espero que todos apoyen VeVb Wulin Network.