Os métodos comuns de comunicação baseados em Ajax (http) entre clientes e servidores Web são divididos em conexões curtas e polling longo .
Conexão curta: toda vez que o cliente e o servidor executam uma operação HTTP, uma conexão é estabelecida e a conexão é encerrada quando a tarefa é concluída.
Sondagem longa: o cliente solicita dados do servidor como uma sondagem tradicional. Porém, se o servidor não tiver dados que possam ser retornados ao cliente imediatamente, ele não retornará um resultado vazio imediatamente, mas manterá a solicitação aguardando a chegada dos dados (ou um tempo limite apropriado: menor que o tempo limite do ajax) e, em seguida, retorne os dados como resultado do cliente.
O mecanismo de pesquisa longa é mostrado na figura abaixo:
2. Conceitos básicos de WebsocketWebSocket é um protocolo para comunicação full-duplex em uma única conexão TCP que o HTML5 começou a fornecer.
O WebSocket simplifica a troca de dados entre o cliente e o servidor, permitindo que o servidor envie dados ativamente para o cliente. Na API WebSocket, o navegador e o servidor só precisam completar um handshake, e uma conexão persistente pode ser criada diretamente entre os dois para transmissão bidirecional de dados.
Na API WebSocket, o navegador e o servidor só precisam realizar uma ação de handshake e, em seguida, um canal rápido é formado entre o navegador e o servidor. Os dados podem ser transmitidos diretamente entre os dois.
Hoje em dia, para implementar a tecnologia push, muitos sites utilizam o polling Ajax. Polling ocorre quando o navegador emite uma solicitação HTTP ao servidor em um intervalo de tempo específico (como a cada 1 segundo) e, em seguida, o servidor retorna os dados mais recentes ao navegador do cliente. Este modelo tradicional traz deficiências óbvias, ou seja, o navegador precisa enviar solicitações continuamente ao servidor. Porém, a solicitação HTTP pode conter um cabeçalho longo, no qual os dados reais válidos podem ser apenas uma pequena parte, o que é obviamente um desperdício. . Muita largura de banda e outros recursos.
O protocolo WebSocket definido pelo HTML5 pode economizar melhor os recursos do servidor e a largura de banda e permitir mais comunicação em tempo real.
O navegador envia uma solicitação ao servidor para estabelecer uma conexão WebSocket por meio de JavaScript. Após a conexão ser estabelecida, o cliente e o servidor podem trocar dados diretamente por meio da conexão TCP.
Depois de obter a conexão Web Socket, você pode enviar dados ao servidor por meio do método send() e receber os dados retornados pelo servidor por meio do evento onmessage.
3. Princípio do aperto de mão do Websocket:O princípio do handshake do Websocket pode ser dividido nas seguintes etapas:
Implementação de código:
import socket, base64, hashlib# Crie uma conexão de soquete sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# Vincule o endereço final e o número da porta sock.bind(('127.0.0.1', 9527))# Ouça sock.listen (5)# Obtenha o objeto de soquete do cliente conn, address = sock.accept()# Obtenha as informações de [handshake] do cliente data = conn.recv(1024)print(data)def get_headers(data): Remova o valor correspondente a Sec-WebSocket-Key do cabeçalho da solicitação e retorne header_dict = {} header_str = data.decode ( utf8) para i em header_str.split(/r/n): if str(i).startswith(Sec-WebSocket-Key): return i.split(:)[1].strip()# Obtenha o valor correspondente a Sec-WebSocket-Key ws_key = get_headers(data)# A string mágica da string mágica é: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11magic_string = '258EAFA5 -E914-47DA-95CA-C5AB0DC85B11'# Emenda socket_str = ws_key + magic_string# criptografia sha1 socket_str_sha1 = hashlib.sha1(socket_str.encode(utf8)).digest()# criptografia base64 socket_str_base64 = base64.b64encode(socket_str_sha1)# Emendando cabeçalho de resposta response_tpl = HTTP/1.1 101 Switching Protocolos/r/n / Upgrade:websocket/r/n / Conexão: Upgrade/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))# O servidor envia o cabeçalho de resposta para o cliente conn.send(response_tpl.encode(utf8))# O cliente e o servidor estabelecem uma conexão longa para receber e enviar dados em um loop enquanto True: msg = conn.recv(8096) print( mensagem)
<!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 receber dados}</script></html>
Em anexo está o cabeçalho da solicitação HTTP iniciada pelo cliente:
b'GET /ws/ HTTP/1.1Host: 127.0.0.1:9527Conexão: UpgradePragma: no-cacheCache-Control: no-cacheUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.3...Upgrade: 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 criptografia e descriptografia de Websocket:
Método de descriptografia:
# 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'# Execute uma operação de bit no segundo byte, que é /x87 bits 9-16 e 127 payload = hashstr[1] & 127# Quando o resultado da operação de bit é igual a 127, os 3-10 bytes são o comprimento dos dados# Bytes 11-14 são a string necessária para a descriptografia da máscara #Os dados vão do 15º byte ao final se carga útil == 127: extend_payload_len = hashstr[2:10] máscara = hashstr[10:14] decoded = hashstr[14:]# Quando o resultado da operação de bits é igual a 126, então os 3-4 bytes são o comprimento dos dados # Os 5-8 bytes são a string necessária para a descriptografia da máscara # Então o dados Do 9º byte até o final se carga útil == 126: extend_payload_len = hashstr[2:4] máscara = hashstr[4:8] decodificado = hashstr[8:]# Quando o resultado da operação de bits é menor ou igual a 125, então este número é o comprimento dos dados # Os 3-6 bytes são a string necessária para a descriptografia da máscara # Os dados vão do 7º byte ao final se carga útil <= 125: extend_payload_len = Nenhum máscara = hashstr[2:6] decodificado = hashstr[6:]str_byte = bytearray() para i no intervalo(len(decodificado)): byte = decodificado[i] ^ máscara[i % 4] str_byte.append(byte)print(str_byte.decode(utf8))
Método de criptografia:
importar structmsg_bytes = 5555555.encode(utf8)token = b/x81length = len(msg_bytes)se comprimento <126: token += struct.pack(B, comprimento)elif comprimento == 126: token += struct.pack(!BH , 126, comprimento)else: token += struct.pack(!BQ, 127, comprimento)msg = token + msg_bytesprint(msg)4. Exemplos de comunicação de link de cliente e servidor com base na estrutura flask e no 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(): # Obtenha o link do usuário user_socket = request.environ. obter(wsgi.websocket) # type:WebSocket print (acesso bem-sucedido) while True: msg = user_socket.receive() #Recebe mensagem print(msg) user_socket.send(msg) #Envia mensagem if __name__ == '__main__': # Especifique o endereço e o número da porta para abra o serviço Websocket http_serv = WSGIServer((127.0.0.1, 8001), aplicativo, handler_class=WebSocketHandler) # Inicia o serviço Websocket http_serv.serve_forever()
arquivo 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()>Clique para criar um link</botton><br><p>Insira uma mensagem: <input type=text placeholder=Input message id=msg></p><buttom class=btn btn- sucesso onclick =send_msg()>Enviar mensagem</buttom><script> var ws = null; WebSocket(ws://127.0.0.1:8001/ws); ws.onmessage = function (data) { console.log(mensagem recebida do servidor=,data.data); document.getElementById(msg).value; ws.send(to_msg) }</script></body></html>
cliente.png
Lado do servidor.png
Desta forma, simplesmente implementamos a comunicação cliente-servidor através do protocolo Websocket. E podemos criar vários links para nos comunicarmos com o lado do servidor ao mesmo tempo.
5. Implemente mensagens instantâneas (IM) baseadas em Websocket:Código do servidor:
do frasco importar Flask, requestfrom geventwebsocket.websocket importar WebSocketfrom gevent.pywsgi importar WSGIServerfrom geventwebsocket.handler importar WebSocketHandlerfrom geventwebsocket.exceptions importar WebSocketErrorimport jsonapp = Flask(__name__)user_socket_dict = {}@app.route(/ws/<username>)def websocket(nome de usuário): # Obtenha o link do usuário user_socket = request.environ.get(wsgi.websocket) # type:WebSocket user_socket_dict[username] = user_socket print(nome de usuário+link bem-sucedido!) while True: msg = user_socket.receive() # Aceita mensagens para soquete em user_socket_dict.values(): # type:WebSocket if user_socket != socket:# Se você mesmo enviar uma mensagem, o servidor não responderá: socket.send(json.dumps({sender: username, msg: msg})) exceto: continueif __name__ == '__main__ ': # Especifique o endereço e o número da porta para abrir o serviço Websocket http_serv = WSGIServer((127.0.0.1, 8001), app, handler_class=WebSocketHandler) # Inicia o serviço 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>Insira seu apelido:<input type=text id=username></p><botton class=btn btn-default onclick=createsocket()>Clique para criar o link</botton><br><p>Por favor, insira a mensagem: <input type=text id=msg >< /p><buttom class=btn btn-success onclick=send_msg()>Enviar mensagem</buttom><br><br><br><div style=border: 2px sólido; largura: 500px; altura: 800px; id=text_div></div><script> var ws = null; function createsocket() { nome de usuário = document.getElementById(nome de usuário).valor; WebSocket(ws://127.0.0.1:8001/ws +/+ nome de usuário ws.onmessage = função); (dados) { var text_div = document.getElementById(text_div); var obj_data = JSON.parse(data.data); innerHTML += add_msg } } função 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 + : + nome de usuário + </p>; = add_msg; ws.send(to_msg);
Cliente01.png
Cliente02.png
Lado do servidor.png
O código é um código de demonstração, com bugs e bugs. É usado principalmente para aprendizado no momento, portanto, nenhuma crítica é permitida. Quem tiver interesse pode otimizar ainda mais! ! !
O texto acima é todo o conteúdo deste artigo. Espero que seja útil para o estudo de todos. Também espero que todos apoiem a Rede VeVb Wulin.