本文共 3619 字,大约阅读时间需要 12 分钟。
HTML5提供了许多新接口,其中最令人振奋的无疑是Websocket。正是它的存在令网络双向交互得以实现。 使用Websocket对于客户端来说无疑十分简单。websocket提供了三个简单的函数,onopen,onclose以及onmessage,顾名思义,他们分别监听socket的开启、断开和消息状态。 例如在一个WebSocket的客户端例子中,你可以这样写: <code> <!DOCTYPE html> <html xmlns=””> <head> <title>Web Socket Example</title> <meta charset=”UTF-8″> <script> window.onload = function() { var s = new WebSocket(“ws://localhost:8000/”); s.onopen = function(e) { alert(“opened”); } s.onclose = function(e) { alert(“closed”); } s.onmessage = function(e) { alert(“got: ” + e.data); } }; </script> </head> <body> <div id=”holder” style=”width:600px; height:300px”></div> </body> </html> </code> 在代码中,首先创建了一个新的socket,指向websocket服务器端: var s = new WebSocket(“ws://localhost:8000/”); 然后利用三个基本函数实现状态监听。 当然这个例子并不完善,它参考了麻省理工一位研究生Mr. Yang的文章( server/),而你如果需要更好的客户端测试代码,可以看这里: 我们在新的代码里提供了完成的和服务器交互数据的功能,发送数据我们使用的函数是send(),你可以在代码中看到。 我们之所以不直接引用Yang的文章是因为Yang对服务器的理解不够完善,或者用他的话来说就是outdate。 感谢Yang为我们提供了一个简单的socket server的例子,不过可惜放在现在来说它是有问题的,当然我们还是把例子引述如下: <code> #!/usr/bin/env python import socket, threading, time def handle(s): print repr(s.recv(4096)) s.send(”’ HTTP/1.1 101 Web Socket Protocol Handshake\r Upgrade: WebSocket\r Connection: Upgrade\r WebSocket-Origin: http://localhost:8888\r WebSocket-Location: ws://localhost:9876/\r WebSocket-Protocol: sample ”’.strip() + ‘\r\n\r\n’) time.sleep(1) s.send(‘\x00hello\xff’) time.sleep(1) s.send(‘\x00world\xff’) s.close() s = socket.socket() s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((”, 9876)); s.listen(1); while 1: t,_ = s.accept(); threading.Thread(target = handle, args = (t,)).start() </code> 虽然不符合我的风格,不过作为python代码来说依然是极具优美。 我们可以看到,Yang在代码中首先创建了一个socket,然后进行握手,此处的例子是: s.send(”’ HTTP/1.1 101 Web Socket Protocol Handshake\r Upgrade: WebSocket\r Connection: Upgrade\r WebSocket-Origin: http://localhost:8888\r WebSocket-Location: ws://localhost:9876/\r WebSocket-Protocol: sample ”’.strip() + ‘\r\n\r\n’) 向客户端发送了这样一串字符串作为data的head信息以完成握手。当然如果你认真的去测试了Yang的例子,就会发现这样做是不规范的,或者说是不符合当前的Websocket协议的。 控制台会反馈给你这样的信息: miss head: Sec-WebSocket-Local miss head: sec-WebSocket-Origin 这是因为,在第76和77版的websocket协议中,握手远非Yang所做的这般简单。 在draft protocol 76中,具体的握手要求如下 1.Client应从WebSocket-Origin发送head包到WebSocket-Location 2.客户端发送的包结构应该是包括Host,Origin,Sec-WebSocket-Key1, Sec-WebSocket-Key2等信息: 这是我们截取的一个例子: ‘GET / HTTP/1.1\r\n Upgrade: WebSocket\r\n Connection: Upgrade\r\n Host: localhost:9876\r\n Origin: \r\n Sec-WebSocket-Key1: c 33w ^T5 1 1C72 ~66 I E=r 8\r\n Sec-WebSocket-Key2: 354214h9998 f \r\n 3.服务器断获取包后,应该提取总长度为20的sec-websocket-key,然后进行如下计算: For each of these fields, the server has to take the digits from the value to obtain a number (in this case 1868545188 and 1733470270 respectively), then divide that number by the number of spaces characters in the value (in this case 12 and 10) to obtain a 32-bit number (155712099 and 173347027). These two resulting numbers are then used in the server handshake, as described below. 既首先把以上字符串转化成数字,然后再计算key中的空格数目,并用key值除以空格数得到最后key值。 4.发送包含以下信息的head给client,完成握手,这里我直接贴出代码。 <code> csock.send(“HTTP/1.1 101 WebSocket Protocol Handshake\r\n”) csock.send(“Upgrade: WebSocket\r\n”) csock.send(“Connection: Upgrade\r\n”) csock.send(“Sec-WebSocket-Origin: http://”+origin+”\r\n”) csock.send(“Sec-WebSocket-Location: ws://”+host+”:”+str(port)+”/\r\n”) csock.send(“Sec-WebSocket-Protocol: chat\r\n”) csock.send(“\r\n”) </code> 5.在完成握手即可进行数据交互,特别注意的是数据发送应当以0X00开头以0Xff结尾: 因而建议最好采用一个诸如这样的函数 def send(data): first_byte = chr(0×00) payload = data.encode(‘utf-8′) pl = first_byte + payload + chr(0xFF) csock.send(pl) 写到这里,已经实现了一个完整的Websocket服务器端了。你可以从此处下载Server代码 GOOD LUCK 文章转载请注明出自Ryan’s Blog()