在Python3中使用WebSocket的Telnet服务器
我一直在用Python3开发一个游戏服务器。我的目标是让这个服务器的通信方式非常灵活,这样不同的客户端都能轻松连接。目前,所有的通信都是通过telnet和miniboa进行的。我希望能支持基于网页的客户端连接。看起来最简单的方法就是使用websocket连接。我试过使用websockify,它是可以工作的,但我更希望不使用代理,因为那样所有的连接看起来都是来自代理的。理想情况下,我希望能在我的telnet服务器中加入一些东西,能够识别websocket的握手请求(和普通请求不同),返回正确的握手,然后保持连接,这样通过telnet和websocket发送和接收的命令就能保持一致。我还没找到能自动做到这一点的东西,所以我在尝试自己写代码来识别websocket的握手并回复相应的握手。我看了很多其他的帖子和例子,特别是python websocket握手(RFC 6455),我对它进行了修改,变成了下面这个测试程序。
#!/usr/bin/env python3
from miniboa import TelnetServer
from base64 import b64encode
from hashlib import sha1
clientlist = []
def client_connects(client):
clientlist.append(client)
def client_disconnects(client):
clientlist.remove(client)
def process_clients():
for client in clientlist:
if client.active and client.cmd_ready:
total_cmd = client.get_command()
print("incoming = {}" .format(total_cmd))
if total_cmd.find(" ") != -1: # breaking apart incoming command
cmd, cmd_var = total_cmd.split(" ", 1)
else:
cmd = total_cmd
cmd_var = ""
if cmd == "Sec-WebSocket-Key:":
GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
cmd_var = cmd_var + GUID
encoded = cmd_var.encode('utf-8')
response_key = b64encode(sha1(encoded).digest())
websocket_answer = (
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
'Sec-WebSocket-Accept: {key}\r\n\r\n',
)
handshake = '\r\n'.join(websocket_answer).format(key=response_key)
client.handshakestr = handshake
if cmd == "Upgrade:":
print("Sending handshake:")
print(client.handshakestr)
print("End of Handshake")
client.send(client.handshakestr)
server = TelnetServer(port=6112, on_connect=client_connects, on_disconnect=client_disconnects)
while True:
process_clients()
server.poll()
这个程序似乎能让我通过初始的握手,但之后连接就立刻断开了。从输出看,浏览器似乎在期待进一步的内容,但我搞不清楚是什么。作为客户端,我在Firefox 29.0上使用了以下代码,这个版本是我从http://opiate.github.io/SimpleWebSocketServer/下载的。
<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script language="javascript" type="text/javascript">
function init()
{
document.myform.url.value = "ws://localhost:8000/"
document.myform.inputtext.value = "Hello World!"
document.myform.disconnectButton.disabled = true;
}
function doConnect()
{
websocket = new WebSocket(document.myform.url.value);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
}
function onOpen(evt)
{
writeToScreen("connected\n");
document.myform.connectButton.disabled = true;
document.myform.disconnectButton.disabled = false;
}
function onClose(evt)
{
writeToScreen("disconnected\n");
document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;
}
function onMessage(evt)
{
writeToScreen("response: " + evt.data + '\n');
}
function onError(evt)
{
writeToScreen('error: ' + evt.data + '\n');
websocket.close();
document.myform.connectButton.disabled = false;
document.myform.disconnectButton.disabled = true;
}
function doSend(message)
{
writeToScreen("sent: " + message + '\n');
websocket.send(message);
}
function writeToScreen(message)
{
document.myform.outputtext.value += message
document.myform.outputtext.scrollTop = document.myform.outputtext.scrollHeight;
}
window.addEventListener("load", init, false);
function sendText() {
doSend( document.myform.inputtext.value );
}
function clearText() {
document.myform.outputtext.value = "";
}
function doDisconnect() {
websocket.close();
}
</script>
<div id="output"></div>
<form name="myform">
<p>
<textarea name="outputtext" rows="20" cols="50"></textarea>
</p>
<p>
<textarea name="inputtext" cols="50"></textarea>
</p>
<p>
<textarea name="url" cols="50"></textarea>
</p>
<p>
<input type="button" name=sendButton value="Send" onClick="sendText();">
<input type="button" name=clearButton value="Clear" onClick="clearText();">
<input type="button" name=disconnectButton value="Disconnect" onClick="doDisconnect();">
<input type="button" name=connectButton value="Connect" onClick="doConnect();">
</p>
</form>
</html>
所以,有人知道: 1. 有没有更简单的方法可以让我的telnet服务器支持websocket? 2. 我在回应websocket连接时哪里出错了? 3. 我是否应该放弃,选择使用代理来处理网页连接?