我去,昨晚websocket还工作得好好的,今早就发现不能用了。检查了一圈发现原来是chrome升级到14后,支持的websocket协议改变了,不再是之前的76草案,改为支持draft-10草案了。从75草案开始,这已经是我知道的第三个握手协议方案了。google chrome团队的博客说,这应该是最后一次稳定的版本了,应该不会再改变了,可以将其应用到生产环境中:http://infra.sunway.dk/cms/fh3aggregator/sources/34#iid-189713
另外几个可以看看的资料如下:
http://www.codeproject.com/KB/HTML/Web-Socket-in-Essence.aspx#BrowserSupport
http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
好吧,在safari跟上来以前,我还是将两种握手协议都封装一下吧。代码贴出来:
def __handshakeHandler(self,data):
response = ""
if re.findall(r'Sec-WebSocket-Key: (.*)\n',data):
key = re.findall(r'Sec-WebSocket-Key: (.*)\n',data)[0].strip()
MAGIC_KEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
token = base64.b64encode(hashlib.sha1(key+MAGIC_KEY).digest())
response = '''
HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: %s\r\n\r
'''.lstrip() % token
else:
resource = re.compile("GET (.*) HTTP").findall(data)[0]
host = re.compile("Host: (.*)\r\n").findall(data)[0]
origin = re.compile("Origin: (.*)\r\n").findall(data)[0]
num1 = re.findall(r'Sec-WebSocket-Key1: (.*)\n',data)[0]
num2 = re.findall(r'Sec-WebSocket-Key2: (.*)\n',data)[0]
key = re.findall(r'\r\n\r\n(.*)$',data)[0]
num1_num = int("".join(re.findall(r'\d',num1)))
num1_space = len(re.findall(r' ',num1))
num2_num = int("".join(re.findall(r'\d',num2)))
num2_space = len(re.findall(r' ',num2))
token = "%s%s%s" % (struct.pack('>L',num1_num/num1_space),struct.pack('>L',num2_num/num2_space),key)
token = hashlib.md5(token).digest()
response = '''
HTTP/1.1 101 WebSocket Protocol Handshake\r
Upgrade: WebSocket\r
Connection: Upgrade\r
Sec-WebSocket-Origin: %s\r
Sec-WebSocket-Location: ws://%s/\r
Sec-WebSocket-Protocol: sample\r\n\r
%s'''.strip() % (origin,host,token)
self.transport.write(response)
握手协议改好了就完了吗?NO!!!恶梦才刚开始,现在发送和接收数据也变了规则,新规则坑爹得很啊,看得我那个想死啊!!!
参考地址如下:http://blog.vunie.com/implementing-websocket-draft-10
好吧,终于用python写出了通信的代码,如下:
[ 接收消息 ]
if draftType == "76":
data = data[1:-1]
elif draftType == "10":
if data[0] != "\x81": return
length = int(binascii.b2a_hex(data[1]),16) & 0x7f
if length < 126:
mask = data[2:6]
text = data[6:]
elif length == 126:
mask = data[4:8]
text = data[8:]
elif length == 127:
mask = data[10:14]
text = data[14:]
unMaskedText = ""
for i,v in enumerate(text):
unMaskedText += binascii.a2b_hex(hex(int(binascii.b2a_hex(text[i]),16) ^ int(binascii.b2a_hex(mask[i%4]),16))[2:])
data = unMaskedText
===================================================[发送消息]
response = ""
if draftType == "76":
response = '''\x00%s\xFF''' % str
elif draftType == "10":
token = "\x81"
length = len(str)
if length < 126:
token += binascii.a2b_hex(hex(length)[2:])
elif length < 65535:
token += binascii.a2b_hex(hex(126)[2:])
_a = hex(length>>8)[2:]
if len(_a) % 2:
_a = "0"+_a
token += binascii.a2b_hex(_a)
_b = hex(length & 0xff)[2:]
if len(_b) % 2:
_b = "0"+_b
token += binascii.a2b_hex(_b)
else:
print "I don't know how to do T_T"
response = '''%s%s''' % (token,str)
好吧,也许你也注意到了 “else:
print "I don't know how to do T_T"
”当需发送的字符串长度超过65535的时候,我们需要用8个字节来表示他的长度,而我在这里不知道如何处理了,因为参考的那篇博客里用的是nodejs,而且他没有讲到如何处理这种情况,所以我在这里不知道怎么办了。。。好在,一般情况下,我们是不会需要这么长的发送量的,我将一个二进制图片base64一下,长度也没超过,所以正常情况下,我们没有超过这个长度的可能性,先不处理也不要紧。
===================================================
更新:终于比较圆满地解决接收和发送消息了,具体方法更新在这里:http://hi.baidu.com/cly84920/blog/item/ad3979ec6ac2ab3b63d09fb2.html