2010-12-07 2 views
5

Dies ist eine Frage zum Handshake in Websocket Protocol 76.Websocket-Handshake-Problem mit Python-Server

Ich habe einen Client und Server geschrieben, habe aber Probleme, den Client den Handshake zu akzeptieren. Ich kann sehen, dass es zurückgegeben wird, aber der Client schließt sofort die Verbindung. Ich vermute, dass meine MD5sum Antwort falsch sein muss.

Soweit ich das beurteilen kann, befolge ich die richtige Prozedur, kann mir jemand sagen, was ich falsch mache?

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) 

Wie Sie sehen können, bin ich durchführen, was ich denke, die richtigen Operationen an den Tasten (dividieren Zahlen von Raum zählen, concat Ergebnisse und die letzte Zeile der Anforderung und dann MD5) und ein 16-Byte zu sein Antwort wird definitiv zurückgegeben.

Jede Hilfe würde sehr geschätzt, und sobald ich eine Arbeitskopie habe, werde ich es hier posten.

Danke.

EDIT:

die Header geändert mit kanaka Antwort zu erfüllen. Der Handshake wird vom Kunden immer noch nicht akzeptiert. ich herausgefunden, wie die Anforderungen in Chromium anzuzeigen, und dies ist die Anfrage und Antwort gegeben werden:

(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 wörtlich, es sei denn ich die IP-Adresse aus offensichtlichen Gründen entfernt haben.

+0

Ihr Einzug keinen Sinn macht. Ich nehme an, dass die Zeilen '# concat'..return' in' create_handshake_resp' stehen sollen? –

+0

Entschuldigung. Fehler kopieren und einfügen Bearbeitet. – Jivings

+0

Sie benötigten die 'Leerzeichen = -1 ', da Sie das erste Leerzeichen nach': 'im Header nicht ignorieren (z. B. Sec-WebSocket-Key1: ein b enthält nur ein Leerzeichen, soweit die Antwort betroffen ist). Doing 'line.partition (": ")' verhindert dies – dbr

Antwort

5

Sie haben ein paar Probleme, die sofort an mich herausspringen:

  • Sie sind nicht Räume richtig zu zählen. Ihr Counter sollte bei 0 nicht -1 beginnen.
  • Ihre Antwortheader sind immer noch v75-Stil. Jeder Header, der mit "WebSocket-" (WebSocket-Origin, WebSocket-Location, WebSocket-Protocol) beginnt, sollte stattdessen mit "Sec-WebSocket-" in v76 starten.

Hier ist, wie ich die Antwort chksum in wsproxy (Teil noVNC ein HTML5-VNC-Client) zu berechnen:

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

Die Anzahl der Leerzeichen beginnend bei -1 ist, weil, wenn die Zeichenfolge aufgeteilt ist, ein Leerzeichen zwischen dem: und dem Schlüssel, der nicht gezählt werden soll. Ich werde versuchen, die Header auf 76 zu ändern, bemerkte ich nicht, dass sie sich geändert hatten. Danke für Ihre Hilfe, ich werde Sie das Ergebnis wissen lassen. – Jivings

+0

Immer noch kein Glück, aber ich habe die Frage aktualisiert, um die Anfrage und Antwort zu zeigen. – Jivings

+0

Whahey! Ich habe meinen Code in Ihren Antwortcode geändert und es funktioniert :) obwohl ich die -1 Leerzeichen einfügen musste. Nicht sicher, was mit mir los war, aber trotzdem danke! – Jivings

2

Hier ist ein funktionierendes Beispiel für einen WebSocket Client/Server (Client in Javascript, Server in Python 2,6)

Es verwendet Beispiele aus verschiedenen Orten (einschließlich kanaka Antwort/noVNC und this page und this page)

Arbeiten mit Chrome 10.0.648.127, Safari 5.0.3 und Mobilesafari auf dem iPad von iOS 4.3

Es ist keineswegs gut geschriebener Code (das Beispiel HTML-Seite ist besonders schrecklich) - Benutzung auf eigene Gefahr und so weiter ..

#!/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() 

auch eine beschissene Beispiel HTML-Seite zeigen arbeiten:

<!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>