5
回答
Web Socket Server的Python实现
注册华为云得mate10,2.9折抢先购!>>>   

HTML5提供了许多新接口,其中最令人振奋的无疑是Websocket。正是它的存在令网络双向交互得以实现。

使用Websocket对于客户端来说无疑十分简单。websocket提供了三个简单的函数,onopen,onclose以及onmessage,顾名思义,他们分别监听socket的开启、断开和消息状态。

例如在一个WebSocket的客户端例子中,你可以这样写:

< !DOCTYPE html>
< html xmlns=”http://www.w3.org/1999/xhtml”>
<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>

在代码中,首先创建了一个新的socket,指向websocket服务器端:
var s = new WebSocket(“ws://localhost:8000/”);
然后利用三个基本函数实现状态监听。

当然这个例子并不完善,它参考了麻省理工一位研究生Mr. Yang的文章(http://yz.mit.edu/wp/web-sockets-tutorial-with-simple-python- server/),而你如果需要更好的客户端测试代码,可以看这里:

http://cl.ly/3N3Y3t2s3U1v1h0A433u

我们在新的代码里提供了完成的和服务器交互数据的功能,发送数据我们使用的函数是send(),你可以在代码中看到。我们之所以不直接引用Yang的文章是因为Yang对服务器的理解不够完善,或者用他的话来说就是outdate。

感谢Yang为我们提供了一个简单的socket server的例子,不过可惜放在现在来说它是有问题的,当然我们还是把例子引述如下:

#!/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()

虽然不符合我的风格,不过作为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: http://127.0.0.1\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,完成握手,这里我直接贴出代码。

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”)
 

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代码 http://cl.ly/0T0g47240H3E2c2C2O0w

GOOD LUCK
文章出自Ryan’s Blog(http://kung.in

举报
鉴客
发帖于7年前 5回/5K+阅
顶部