2010-12-07 13 views
5

Esta es una pregunta sobre el protocolo de enlace en Websocket Protocol 76.Problema de enlace de Websocket con el servidor de Python

He escrito un cliente y un servidor, pero estoy teniendo problemas para que el cliente acepte el protocolo de enlace. Puedo ver que se devuelve, pero el cliente cierra inmediatamente la conexión. Supongo que mi respuesta md5sum debe ser incorrecta.

Por lo que puedo decir, estoy siguiendo el procedimiento adecuado, ¿alguien me puede decir lo que estoy haciendo mal?

def create_handshake_resp(handshake): 

    # parse request 
    final_line = "" 
    lines = handshake.splitlines() 
    for line in lines: 
    parts = line.partition(":") 
    if parts[0] == "Sec-WebSocket-Key1": 
     key1 = parts[2] 
    elif parts[0] == "Sec-WebSocket-Key2": 
     key2 = parts[2] 
    final_line = line 

    #concat the keys and encrypt 
    e = hashlib.md5() 
    e.update(parse_key(key1)) 
    e.update(parse_key(key2)) 
    e.update(final_line) 
    return "HTTP/1.1 101 WebSocket Protocol Handshake\r\nUpgrade: WebSocket\r\nConnection:  Upgrade\r\nWebSocket-Origin: http://%s\r\nWebSocket-Location: ws://%s/\r\nWebSocket-Protocol: sample\r\n\r\n%s" % (httphost, sockethost, e.digest()) 



def parse_key(key): 

    spaces = -1 
    digits = "" 
    for c in key: 
    if c == " ": 
     spaces += 1 
    if is_number(c): 
     digits = digits + c 


    new_key = int(digits)/spaces 
    return str(new_key) 

Como se puede ver, estoy realizando lo que creo que es el correcto funcionamiento de las teclas (números se dividen por recuento espacio, resultados concat y la última línea de la solicitud y luego MD5) y un byte 16 la respuesta definitivamente está siendo devuelta.

Cualquier ayuda sería muy apreciada, y tan pronto como tenga una copia de trabajo la publicaré aquí.

Gracias.

EDIT:

cambiado las cabeceras para cumplir con la respuesta de Kanaka. El cliente todavía no acepta el apretón de manos. He encontrado la manera de visualizar las solicitudes de cromo, y esta es la solicitud y la respuesta que se da:

(P) t=1291739663323 [st=3101]  WEB_SOCKET_SEND_REQUEST_HEADERS 
           --> GET/HTTP/1.1 
            Upgrade: WebSocket 
            Connection: Upgrade 
            Host: --- 
            Origin: http://--- 
            Sec-WebSocket-Key1: 3E 203C 220 642; 
            Sec-WebSocket-Key2: Lg 590 ~5 703O G7 =%t 9 

            \x74\x66\xef\xab\x50\x60\x35\xc6\x0a 
(P) t=1291739663324 [st=3102]  SOCKET_STREAM_SENT  
(P) t=1291739663348 [st=3126]  SOCKET_STREAM_RECEIVED 
(P) t=1291739663348 [st=3126]  WEB_SOCKET_READ_RESPONSE_HEADERS 
           --> HTTP/1.1 101 WebSocket Protocol Handshake 
            Upgrade: WebSocket 
            Connection: Upgrade 
            Sec-WebSocket-Origin: http://--- 
            Sec-WebSocket-Location: ws://---/ 
            Sec-WebSocket-Protocol: sample 

            \xe7\x6f\xb9\xcf\xae\x70\x57\x43\xc6\x20\x85\xe7\x39\x2e\x83\xec\x0 

Ad pie de la letra, excepto que he eliminado la dirección IP por razones obvias.

+0

Su sangría no tiene sentido. Supongo que las líneas '# concat'..'return' están destinadas a' create_handshake_resp'? –

+0

Lo siento. Copia y pega el error. Editado – Jivings

+0

Necesitaba los 'espacios = -1' porque no está ignorando el primer espacio después de': 'en el encabezado (por ejemplo' Sec-WebSocket-Key1: a b' solo contiene un espacio, en lo que respecta a la respuesta). Hacer 'line.partition (": ")' previene esto – dbr

Respuesta

5

usted tiene un par de problemas que saltan inmediatamente hacia mí:

  • No está contando los espacios correctamente. Tu contador debe comenzar en 0, no -1.
  • Sus encabezados de respuesta siguen siendo de estilo v75. Cualquier encabezado que comience con "WebSocket-" (WebSocket-Origin, WebSocket-Location, WebSocket-Protocol) debería comenzar con "Sec-WebSocket-" en v76.

Aquí es cómo calculo el chksum respuesta en wsproxy (parte de noVNC un cliente HTML5 VNC):

import struct, md5 
... 
spaces1 = key1.count(" ") 
spaces2 = key2.count(" ") 
num1 = int("".join([c for c in key1 if c.isdigit()]))/spaces1 
num2 = int("".join([c for c in key2 if c.isdigit()]))/spaces2 

return md5(struct.pack('>II8s', num1, num2, key3)).digest() 
+0

El recuento de espacios que comienza en -1 se debe a que cuando se divide la cadena hay un espacio entre la tecla: y la tecla, que no debe contarse. Trataré de cambiar los encabezados a 76, no noté que habían cambiado. Gracias por tu ayuda, te dejaré saber el resultado. – Jivings

+0

Todavía no tuve suerte, pero actualicé la pregunta para mostrar la solicitud y la respuesta. – Jivings

+0

Whahey! Cambié mi código a tu código de respuesta y funciona :) aunque tuve que incluir el -1 en los espacios. No estoy seguro de lo que estaba mal con el mío, pero gracias de todos modos. – Jivings

2

Aquí está un ejemplo de trabajo de un cliente/servidor WebSocket (cliente en Javascript, servidor en Python 2.6)

Se usó ejemplos de varios lugares (incluyendo de kanaka respuesta/noVNC, y this page y this page)

funciona con Chrome 10.0.648.127, Safari 5.0.3 y MobileSafari en el iPad de IOS 4.3

Es de ninguna manera es un código bien escrito (la página HTML ejemplo es especialmente horrible) - uso bajo su propio riesgo y así sucesivamente ..

#!/usr/bin/env python 

import socket 
import threading 
import struct 
import hashlib 

PORT = 9876 


def create_handshake_resp(handshake): 
    final_line = "" 
    lines = handshake.splitlines() 
    for line in lines: 
     parts = line.partition(": ") 
     if parts[0] == "Sec-WebSocket-Key1": 
      key1 = parts[2] 
     elif parts[0] == "Sec-WebSocket-Key2": 
      key2 = parts[2] 
     elif parts[0] == "Host": 
      host = parts[2] 
     elif parts[0] == "Origin": 
      origin = parts[2] 
     final_line = line 

    spaces1 = key1.count(" ") 
    spaces2 = key2.count(" ") 
    num1 = int("".join([c for c in key1 if c.isdigit()]))/spaces1 
    num2 = int("".join([c for c in key2 if c.isdigit()]))/spaces2 

    token = hashlib.md5(struct.pack('>II8s', num1, num2, final_line)).digest() 

    return (
     "HTTP/1.1 101 WebSocket Protocol Handshake\r\n" 
     "Upgrade: WebSocket\r\n" 
     "Connection: Upgrade\r\n" 
     "Sec-WebSocket-Origin: %s\r\n" 
     "Sec-WebSocket-Location: ws://%s/\r\n" 
     "\r\n" 
     "%s") % (
     origin, host, token) 


def handle(s, addr): 
    data = s.recv(1024) 
    s.send(create_handshake_resp(data)) 
    lock = threading.Lock() 

    while 1: 
     print "Waiting for data from", s, addr 
     data = s.recv(1024) 
     print "Done" 
     if not data: 
      print "No data" 
      break 

     print 'Data from', addr, ':', data 

     # Broadcast received data to all clients 
     lock.acquire() 
     [conn.send(data) for conn in clients] 
     lock.release() 

    print 'Client closed:', addr 
    lock.acquire() 
    clients.remove(s) 
    lock.release() 
    s.close() 

def start_server(): 
    s = socket.socket() 
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    s.bind(('', PORT)) 
    s.listen(1) 
    while 1: 
     conn, addr = s.accept() 
     print 'Connected by', addr 
     clients.append(conn) 
     threading.Thread(target = handle, args = (conn, addr)).start() 

clients = [] 
start_server() 

Además, una página HTML horrible ejemplo para mostrar que funcione:

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
     <title>Test</title> 
     <script type="application/javascript"> 
      var ws; 

      function init() { 
       var servermsg = document.getElementById("servermsg"); 

       ws = new WebSocket("ws://localhost:9876/"); 
       ws.onopen = function(){ 
        servermsg.innerHTML = servermsg.innerHTML + "<br>Server connected"; 
        servermsg.innerHTML = servermsg.innerHTML + "<br>Sending message to server"; 
        ws.send("Hello Mr. Server!"); 
       }; 
       ws.onmessage = function(e){ 
        servermsg.innerHTML = servermsg.innerHTML + "<br>Recieved data: " + e.data; 
       }; 
       ws.onclose = function(){ 
        console.log("Server disconnected"); 
        servermsg.innerHTML = servermsg.innerHTML + "<br>Connected"; 
       }; 
      } 
      function postmsg(){ 
       var text = document.getElementById("message").value; 
       ws.send(text); 
       servermsg.innerHTML = servermsg.innerHTML + "<br>Sent: " + text; 
       return false; 
      } 
     </script> 
    </head> 
    <body onload="init();"> 
     <form action="" onSubmit="postmsg()"> 
      <input type="text" name="message" value="" id="message"> 
      <input type="submit" name="submit" value="" id="submit"> 
     </form> 
     <div id="servermsg"><h1>Message log:</h1></div> 
    </body> 
</html> 
Cuestiones relacionadas