1 Contrato
O WebSocket é um protocolo com base na comunicação duplex completa entre clientes e servidores no TCP. Ele é definido no HTML5 e também é uma das especificações básicas da nova geração de WebApps.
Ele rompe as limitações do Ajax anterior, a chave é em tempo real e o servidor pode empurrar ativamente o conteúdo para o cliente! Os aplicativos possíveis incluem: jogos on-line multiplayer, bate-papo ao vivo, monitoramento em tempo real, desktop remoto, servidor de notícias, etc.
Para mim, o que mais quero tentar no momento é o que pode ser feito com a combinação de tela+websocket.
2. Realização
Como o processo de handshake é uma solicitação HTTP padrão, existem duas opções para implementar o WebSocket: 1) implementação no TCP; 2) Implementação no software HTTP existente. A última vantagem é que ele pode compartilhar portas existentes do servidor HTTP e não precisa reimplementar a função de autenticação e analisar solicitações HTTP.
O módulo HTTP do nó é usado neste exemplo. (Consulte Anexamento para versão TCP e todos os arquivos)
1. Código do lado do servidor do nó:
var http = requer ('http'); var url = requer ('url'); // var mime = requer ('mime'); var cripto = requer ('cripto'); var porta = 4400; var server = http.CreateServer (); server.listen (porta, function () {console.log ('O servidor está em execução no localHost:', porta); servidor .on ('conexão', função (s) {console.log ('na conexão', s);}) .on ('request', onRequest). ('upgrade', onupgrade); Object.Keys (req), req.url, req ['upgrade']); if (! req.upgrade) {// Seleção de solicitações de não atualização: interrompa ou forneça uma página da web normal res.WriteHead (200, {'Content-type': 'text/plana'}); Res.Write ('WebSocket Server funciona!'); } res.nd (); return;}; var onUpGrade = function (req, sok, cabeça) {// console.log ('método:', object.Keys (sok)); if (req.headers.upgrade! == 'websocket') {console.warn ('conexão ilegal'); Sock.end (); retornar; } bind_sock_event (meia); tente {handshake (req, meia, cabeça); } catch (e) {console.error (e); Sock.end (); }}; // Enrole o quadro a ser enviado var wrap = function (data) {var fa = 0x00, fe = 0xff, data = data.toString () len = 2+buffer.byTelength (dados), buff = new buffer (len); buff [0] = fa; buff.write (dados, 1); Buff [len-1] = Fe; Retornar Buff;} // Departamento do quadro recebido var des Undersrap = function (data) {return data.slice (1, data.length-1);} var bind_sock_event = function (sock) {sock .on ('dados', function (buffer) {var data = unders (buffer); console.log ('sotaque', recebimento de dados: send ('olá html5,'+date.now ()) sok.emit ('send', dados); Sock.Write (WRAP (Data), 'Binário'); if(!spaces) throw {message:'Wrong key: '+key,name:'HandshakeError'} return get_big_endian(part / spaces);}var get_big_endian = function(n) { return String.fromCharCode.apply(null,[3,2,1,0].map(function(i) { return n >> 8*i & 0xff }))}var challenge = function (key1, key2, cabeça) {var sum = get_part (key1) + get_part (key2) + head.toString ('binário'); Retornar Crypto.createhash ('md5'). update (soma) .digest ('binário');} var handshake = function (req, sok, cabeça) {var output = [], h = req.headers, br = '/r/n'; // Cabeçalho output.push ('HTTP/1.1 101 WebSocket Protocol Handshake', 'Upgrade: WebSocket', 'Conexão: Upgrade', 'Sec-WebSocket-Origin:' + h.origin, 'sec-WebSocket-Location: WS: //' + h.host + req.url, 'Secweb-location: WS: //' + H.Host + Req.url, 'Secweb-Web-Web: ); // corpo var c = desafio (h ['sec-webesocket-key1'], h ['sec-websocket-key2'], cabeça); output.push (c); Sock.Write (output.Join (Br), 'Binário');}2. Código do cliente do navegador:
<html> <head> <title> WebSocket Demo </ititle> </ad Head> <style type = "text/css"> textarea {width: 400px; altura: 150px; display: bloqueio; overflow-y: scroll;} #output {width: 600px; altura: 400px; fundo: whites; Botão {preenchimento: .2em 1em;} </style> <link href = "layout.css" rel = "stylesheet" type = "text/css"/> <body> <texttarea id = "output" readonly = "readonly"> </texturea> <br> <bloTeea "> send"> "> </texton> <broty> <brotlea"> <brotleea "<brotleea" <brotleea "<brotneea" <brotleea "<broty> <broty> <brotneea) type = "text/javascript"> // localhostvar soket = new websocket ('ws: //192.168.144.131: 4400/') soket.onopen = function (e) {log (e.type); Socket.send ('Hello Node');} soket.onclose = function (e) {log (e.type);} soket.onMessage = function (e) {LOG ('Receber @'+new Date (). tolocaletimestring ()+'/n'+e.data); output.Scrolltop = output.ScrolHeight} Socket.Onclose = function (e) {Log (E.Type);} Socket.adDeventListener ('Close', Function () {Log ('A outro manipulador de evento fechado ..');}, false); = id ('input'), send = id ('send'); var log = function (msg) {output.textContent += '>' +msg +'/n'} send.addeventListener ('click', function () {socket.send (input.value);}, false) </script>3. Detalhes
A implementação do protocolo WebSocket acima do protocolo HTTP tem apenas duas etapas: handshake e envia dados.
1. Aperte as mãos
O processo de handshake é chamado de resposta desafio. Primeiro, o cliente inicia um http get solicitação nomeado upgrade, o servidor verifica a solicitação, fornece uma resposta 101 para indicar que a atualização do protocolo é aceita e o aperto de mão está concluído.
As informações do aperto de mão embelezadas pelo Chrome Inspector:
Solicitação URL: WS: //192.168.144.131: 4400/pub/chat? Q = Me
Método de solicitação: obtenha
Código de status: 101 WebSocket Protocol Handshake
Solicitar cabeçalhos
Conexão: atualização
Host: 192.168.144.131: 4400
Origem: http: // localhost: 800
Sec-websocket-key1: P2 G 947T 80 661 JAF2
Sec-websocket-key2: z ZQ ^326 5 9 = 7S1 1 7H4
Sec-Websocket-Protocol :: My-Custom-Chat-Protocol
Atualização: WebSocket
(Key3): 7C: 44: 56: CA: 1F: 19: D2: 0A
Cabeçalhos de resposta
Conexão: atualização
Sec-WebSocket-Location: WS: //192.168.144.131: 4400/pub/chat? Q = Me
Sec-websocket-origin: http: // localhost: 800
Sec-Websocket-Protocol: My-Custom-Chat-Protocol
Atualização: WebSocket
(Resposta do desafio): 52: df: 2c: f4: 50: c2: 8e: 98: 14: b7: 7d: 09: cf: c8: 33: 40
Cabeçalho de solicitação
Host: WebSocket Server Host
Conexão: Tipo de conexão
Atualização: Tipo de atualização do protocolo
Origem: Visite a fonte
Protocolo SEC-WebSocket: Opcional, nome do subprotocolo, definido pelo próprio aplicativo, e vários protocolos são divididos por espaços. (*Uma outra opção deixada é os cookies)
Sec-websocket-key1: chave de autenticação de segurança, a solicitação XHR não pode forjar cabeçalhos de solicitação começando com 'sec-'.
Sec-websocket-key2: o mesmo que acima
KEY3: Conteúdo do corpo da resposta, 8 bytes aleatórios.
Cabeçalho de resposta
Sec-Websocket-Protocol: deve conter o nome do subprotocolo solicitado
Sec-Websocket-Origin: deve ser igual à fonte da solicitação
Localização de Sec-WebSocket: deve ser igual ao endereço solicitado
Resposta do desafio: o conteúdo do corpo da resposta, calculado com base nas três teclas da solicitação, 16 bytes.
Resposta Processo de cálculo da cadeia Pseudocode:
parte_1 = todos os números em Key1 / número de espaços em Key1 parte_2 Mesmo que acima sum = big_endian (parte_1)+big_endian (parte_2)+key3challenge_Response = md5_digest (soma);
Estratégia de cálculo big_endian para números inteiros de 32 bits:
# É muito semelhante ao cálculo de cores RGBA. A partir da seguinte função, podemos ver que o processo de cálculo var big_endian = function (n) {return [3,2,1,0] .map (function (i) {return n >> 8*i & 0xff});} big_endian (0xcc77aaff); // -> [204, 119, 170, 255]2. Envie dados
A API do WebSocket foi projetada para processar dados usando eventos. Os clientes podem obter dados completos, desde que obtenham notificações de eventos sem processamento manualmente do buffer.
Nesse caso, cada dados é chamado de quadro. Na definição de especificação, sua cabeça deve começar com 0x00 e o atributo de cauda termina com 0xFF, para que cada envio de dados tenha pelo menos dois bytes.
Na implementação do servidor, a cabeça e a cauda devem ser cortadas ao receber dados; enquanto a cabeça e a cauda devem ser embalados ao enviar dados. O formato é o seguinte:
# 'Hello' Representação binária original, o cabeçalho da solicitação e aqui estão as codificações UTF8
<Buffer e4 bd a0 e5 a5 bd>
# A representação binária embrulhada.
<Buffer 00 e4 bd a0 e5 a5 bd ff>
O exposto acima é tudo sobre este artigo, espero que seja útil para o aprendizado de todos.