2010-12-07 4 views
5

Il s'agit d'une question relative à la prise de contact au Websocket Protocol 76.Problème de prise de contact Websocket à l'aide du serveur Python

J'ai écrit un client et un serveur, mais j'ai du mal à obtenir le client pour accepter la prise de contact. Je peux voir qu'il est retourné, mais le client ferme immédiatement la connexion. Je suppose que ma réponse md5sum doit être incorrecte. Pour autant que je sache, je suis la procédure appropriée, quelqu'un peut-il me dire ce que je fais 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) 

Comme vous pouvez le voir, je joue ce que je pense être les bonnes opérations sur les touches (numéros de diviser par le nombre d'espace, les résultats concat et la dernière ligne de la demande, puis MD5) et un 16 octet la réponse est définitivement retournée.

Toute aide serait grandement appréciée, et dès que j'en aurais une copie de travail, je l'afficherai ici.

Merci.

EDIT:

changé les en-têtes pour se conformer à la réponse de Kanaka. La prise de contact n'est toujours pas acceptée par le client. Je trouvé comment afficher les demandes de chrome, ce qui est la demande et la réponse étant donnée:

(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 mot pour mot, sauf que j'ai supprimé l'adresse IP pour des raisons évidentes.

+0

Votre empreinte n'a pas de sens. Je suppose que les lignes '# concat'..'return' sont censées être dans' create_handshake_resp'? –

+0

Désolé. Copiez et collez une erreur. Édité. – Jivings

+0

Vous aviez besoin de 'spaces = -1' car vous n'ignorez pas le premier espace après': 'dans l'en-tête (par exemple' Sec-WebSocket-Key1: a b' contient seulement un espace, en ce qui concerne la réponse). Faire 'line.partition (": ")' empêche cela – dbr

Répondre

5

Vous avez un problème de couple qui sautent immédiatement à moi:

  • Vous ne comptez pas les espaces correctement. Votre compteur devrait commencer à 0 et non -1.
  • Vos en-têtes de réponse sont toujours de style v75. Tout en-tête commençant par "WebSocket-" (WebSocket-Origine, WebSocket-Location, WebSocket-Protocol) devrait plutôt commencer par "Sec-WebSocket-" dans v76.

Voici comment je calcule la chksum de réponse dans wsproxy (partie de noVNC un client 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

Le nombre d'espace commençant à -1 est parce que quand la chaîne est divisée il y a un espace entre la: et la clé, qui ne devrait pas être compté. Je vais essayer de changer les en-têtes à 76, je n'ai pas remarqué qu'ils avaient changé. Merci pour votre aide, je vous ferai connaître le résultat. – Jivings

+0

Toujours pas de chance, mais j'ai mis à jour la question pour montrer la demande et la réponse. – Jivings

+0

Whahey! J'ai changé mon code pour votre code de réponse et cela fonctionne :) bien que je devais inclure le -1 sur les espaces. Je ne sais pas ce qui n'allait pas avec le mien mais merci quand même! – Jivings

2

Voici un exemple de travail d'un client WebSocket/serveur (client Javascript, serveur en Python 2.6)

Il a utilisé des exemples de divers endroits (y compris la réponse de kanaka/noVNC, et this page et this page)

Fonctionne avec Chrome 10.0.648.127, Safari 5.0.3 et MobileSafari sur iPad de iOS 4.3

Il est loin d'un code bien écrit (l'exemple page HTML est particulièrement horrible) - utiliser à vos propres risques et ainsi de suite ..

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

en outre, une page merdiques exemple HTML pour l'afficher de travail:

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