2010-07-10 196 views
7

我正在使用python來實現一個簡單的websocket服務器。 我使用的握手來自http://en.wikipedia.org/w/index.php?title=WebSockets&oldid=372387414websocket握手問題

握手本身似乎工作,但是當我點擊發送,我得到一個JavaScript錯誤:

Uncaught Error: INVALID_STATE_ERR: DOM Exception 11

這裏的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> 

而這裏的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() 

有沒有人知道我在做什麼錯在這裏?

+0

我無法在沒有WebSocket類的情況下測試您的代碼。它在哪裏定義? Firefox 3.6.3似乎並不知道它是什麼。 – Nathan 2010-07-12 20:18:04

+0

Chrome Dev有它,而Firefox 4應該有它。 – lowerkey 2010-07-12 21:22:34

+0

如果您沒有100位代表,您是如何提供賞金的? – Nathan 2010-07-13 17:14:48

回答

6

我測試你的代碼在Firefox 4和擊球時發出了同樣的錯誤,但是之前我得到

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

這可能是爲什麼WebSocket的對象已受到破壞。我懷疑你的握手響應缺少一些東西,所以Firefox正在關閉套接字。

從上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.

你的服務器的響應沒有在底部這個特殊的號碼,所以我認爲我們需要弄清楚如何產生的,以及包括它。

編輯:如何生成號

讓我們開始與KEY1,KEY2,並在握手結束的8個字節

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

我們做了一些爲因忽視每個鍵每個字符都不是數字0-9。在Python:

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

接下來我們通過劃分的原始密鑰字符串中的空格的數字,這個數字,所以這裏是一個是計數的空間在一個字符串的函數。

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

從琴鍵上產生的兩個數字是:

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

現在我們需要連接pkey1,pkey2和end8的字節。處理後的密鑰需要表示爲32位Big-Endian數字。

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

然後我們把這些字節的MD5哈希得到一個神奇的數字,我們釘在握手

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

那結束時,我怎麼想它的工作原理至少

+0

感謝您的信息,從來沒有想過自己。我在谷歌上發現了這個:http://golang.org/src/pkg/websocket/server.go它描述瞭如何生成密鑰。在我們發言時努力理解它。 – lowerkey 2010-07-13 22:16:06

+0

下面是握手的更好的描述:http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#page-7 – lowerkey 2010-07-13 22:58:27

+1

我來到了一個類似的解決方案,但我有問題編碼的結果utf-8中的md5算法。 – lowerkey 2010-07-14 23:11:40