websocket握手问题
Posted
技术标签:
【中文标题】websocket握手问题【英文标题】:websocket handshake problem 【发布时间】:2010-07-10 19:25:35 【问题描述】:我正在使用 python 来实现一个简单的 websocket 服务器。 我使用的握手来自http://en.wikipedia.org/w/index.php?title=WebSockets&oldid=372387414。
握手本身似乎有效,但是当我点击发送时,我收到一个 javascript 错误:
未捕获的错误:INVALID_STATE_ERR:DOM 异常 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()
有谁知道我在这里做错了什么?
【问题讨论】:
如果没有 WebSocket 类,我无法测试您的代码。它在哪里定义? Firefox 3.6.3 似乎不知道它是什么。 Chrome Dev 有,Firefox 4 应该有。 如果你没有 100 个代表,你是如何提供赏金的? handleLoad() 和 send(str) 这两个函数如何引用同一个 ws 对象?它是在我没有看到的其他地方声明的全局变量吗? 在 Javascript 中,全局变量只是命名,局部变量是用 var 关键字创建的 【参考方案1】:我在 Firefox 4 上测试了您的代码,并在点击发送时遇到了同样的错误,但在此之前我得到了
Firefox 无法建立连接 到 ws://localhost:8888/ 的服务器。
这可能是 WebSocket 对象被破坏的原因。我怀疑您的握手响应缺少某些内容,因此 Firefox 正在关闭套接字。
来自关于 Websockets 的***文章:
Sec-WebSocket-Key1 和 Sec-WebSocket-Key2 字段和 字段后的八个字节是 服务器使用的随机令牌 最后构造一个 16 字节的令牌 握手以证明它有 读取客户的握手信息。
你的服务器的响应底部没有这个特殊的数字,所以我想我们需要弄清楚如何生成它,并包含它。
编辑:如何生成该数字
让我们从 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()
至少我认为它是这样工作的
【讨论】:
感谢您提供的信息,我自己永远也想不通。我在 google 上找到了这个:golang.org/src/pkg/websocket/server.go 它描述了如何生成密钥。在我们说话的时候努力理解它。 这里对握手有更好的描述:tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#page-7 我找到了一个类似的解决方案,但是在 utf-8 中编码 md5 算法的结果时遇到问题。 pastebin.com/Q4GPcM09 这是我的握手代码,但正如我所说,utf-8 编码有问题。 这里有一个 ruby 实现:github.com/igrigorik/em-websocket/blob/master/lib/em-websocket/… 至于将 MD5 哈希编码为 UTF-8;这不应该是必需的,因为 ASCII 是 UTF-8 的子集。所以一个 ASCII 字符串(MD5 哈希只包含 [0-9a-f])是自动有效的 UTF-8。【参考方案2】:从版本 8 开始,该协议已被弃用,请参考:
http://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-12.txt
对于新版本的协议。
【讨论】:
以上是关于websocket握手问题的主要内容,如果未能解决你的问题,请参考以下文章
WebSocket 与 Ruby 和 EM::WebSocket::Server 握手