2010-07-10 5 views
7

J'utilise python pour implémenter un simple serveur websocket. La poignée de main que j'utilise vient de http://en.wikipedia.org/w/index.php?title=WebSockets&oldid=372387414.Problème de prise de contact websocket

La poignée de main lui-même semble fonctionner, mais quand je frappe envoie, je reçois une erreur javascript:

Uncaught Error: INVALID_STATE_ERR: DOM Exception 11

Voici le html:

<!doctype html> 
<html> 
    <head> 
     <title>ws_json</title> 

    </head> 
    <body onload="handleLoad();" onunload="handleUnload();"> 
     <input type="text" id='input' /> 
     <input type="button" value="submit" onclick="handleSubmit()" /> 
     <div id="display"></div> 

     <script type="text/javascript"> 
      function showmsg(str){ 
       display = document.getElementById("display"); 
       display.innerHTML += "<p>" + str + "</p>"; 
      } 

      function send(str){ 
       ws.send(str.length); 
       ws.send(str); 
      } 

      function handleSubmit(){ 
       input = document.getElementById('input'); 
       send(input.value); 
       input.focus(); 
       input.value = ''; 
      } 

      function handleLoad(){ 
       ws = new WebSocket("ws://localhost:8888/"); 
       ws.onopen = function(){ 
        showmsg("websocket opened."); 
       } 

       ws.onclose = function(){ 
        showmsg("websocket closed."); 
       } 
      } 

      function handleUnload(){ 
       ws.close(); 
      } 
     </script> 
    </body> 
</html> 

Et voici le code python:

import socket 
import threading 
import json 

PORT = 8888 
LOCATION = "localhost:8888" 

def handler(s): 

    print " in handler " 

    ip, _ = s.getpeername() 
    print "New connection from %s" % ip 
    request = s.recv(1024) 

    print "\n%s\n" % request 
    print s.getpeername() 

    # send response 
    response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" 
    response += "Upgrade: WebSocket\r\n" 
    response += "Connection: Upgrade\r\n" 
    try: 
     peername = s.getpeername() 
     response += "Sec-WebSocket-Origin: http://%s\r\n" % peername[0] # % request[request.index("Origin: ")+8:-4] 
    except ValueError: 
     print "Bad Request" 
     raise socket.error 
    response += "Sec-WebSocket-Location: ws://%s\r\n" % LOCATION 
    response += "Sec-WebSocket-Protocol: sample" 
    response = response.strip() + "\r\n\r\n" 

    print response 
    s.send(response) 

    while True: 
     length = s.recv(1) 
     print length 
     if not length: 
      break 
     length = int(length) 
     print "Length: %i" % length 
     data = s.recv(length) 
     print "Received: %s" % data 
     print "" 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
s.bind(('localhost', PORT)) 
s.listen(5) 

print "server is running..." 
while True: 
    sock, addr = s.accept() 
    threading.Thread(target=handler, args=(sock,)).start() 

Est-ce que quelqu'un sait ce que je fais mal ici?

+0

Je ne peux pas tester votre code sans la classe WebSocket. où est-ce défini? Firefox 3.6.3 ne semblait pas savoir de quoi il s'agissait. – Nathan

+0

Chrome Dev l'a, et Firefox 4 est censé l'avoir. – lowerkey

+0

Comment avez-vous offert une prime si vous n'avez pas 100 rep? – Nathan

Répondre

6

J'ai testé votre code sur Firefox 4 et a obtenu la même erreur après avoir heurté envoyer, mais avant que je suis arrivé

Firefox can't establish a connection to the server at ws://localhost:8888/.

qui est probablement la raison pour laquelle l'objet WebSocket a été détruit. Je soupçonne que votre réponse de prise de contact manque quelque chose, alors Firefox ferme la socket.

de l'article Wikipedia sur Websockets:

The Sec-WebSocket-Key1 and Sec-WebSocket-Key2 fields and the eight bytes after the fields are random tokens which the server uses to construct a 16 byte token at the end of its handshake to prove that it has read the client's handshake.

ne la réponse de votre serveur pas ce numéro spécial en bas, donc je pense que nous avons besoin de savoir comment générer, et l'inclure.

EDIT: Comment générer ce nombre

Commençons par key1, key2, et les 8 octets à la fin de la poignée de main

key1 = "18x 6]8vM;54 *(5: { U1]8 z [ 8" 
key2 = "1_ tx7X d < nw 334J702) 7]o}` 0" 
end8 = "Tm[K T2u" 

Nous faisons un numéro pour chaque clé en ignorant chaque caractère qui n'est pas un chiffre 0-9. En Python:

def numFromKey(key): 
    return int(filter(lambda c: c in map(str,range(10)),key)) 

prochaine on divise ce nombre par le nombre d'espaces dans la chaîne clé d'origine, alors voici une est une fonction qui compte les espaces dans une chaîne.

def spacesIn(key): 
    return len(filter(lambda c: c==' ',key)) 

Les deux chiffres résultant des clés sont les suivants:

pkey1 = numFromKey(key1)/spacesIn(key1) 
pkey2 = numFromKey(key2)/spacesIn(key2) 

Maintenant, nous avons besoin de concaténer les octets de pkey1, pkey2 et end8. Les clés traitées doivent être représentées comme des nombres Big-Endian 32 bits.

from struct import pack 
catstring = pack('>L',pkey1) + pack('>L',pkey2) + end8 

Ensuite, nous prenons le md5 de ces octets pour obtenir le chiffre magique que nous louvoyons à la fin de la poignée de main

import md5 
magic = md5.new(catstring).digest() 

est comment je pense que cela fonctionne au moins

+0

Merci pour l'info, ne l'aurais jamais compris moi-même. J'ai trouvé ceci sur google: http://golang.org/src/pkg/websocket/server.go il décrit comment générer une clé. Travailler à la comprendre en ce moment même. – lowerkey

+0

Voici une meilleure description de la poignée de main: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#page-7 – lowerkey

+1

Je suis arrivé à une solution similaire, mais j'ai des problèmes d'encodage des résultats de l'algorithme md5 dans utf-8. – lowerkey

Questions connexes