使用BaseHTTPServer实现WebSocket服务器
WebSocket服务器是一种与客户端进行全双工通信的通信协议。在Python中,可以使用BaseHTTPServer模块来实现WebSocket服务器。
首先,我们需要导入BaseHTTPServer和WebSocketServer。BaseHTTPServer模块提供了一个HTTP服务器框架,WebSocketServer模块提供了对WebSocket通信的支持。
import BaseHTTPServer import WebSocketServer
接下来,我们需要定义一个继承自BaseHTTPServer.BaseHTTPRequestHandler的类来处理HTTP请求。在这个类中,我们需要重写do_GET方法来处理WebSocket握手请求和WebSocket消息的处理。
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('<html><head><title>WebSocket Server</title></head>')
self.wfile.write('<body><h1>WebSocket Server</h1></body></html>')
elif self.path == '/websocket':
self.send_response(101)
self.send_header('Upgrade', 'websocket')
self.send_header('Connection', 'Upgrade')
self.send_header('Sec-WebSocket-Accept', WebSocketServer.encrypt_key(self.headers.getheader('Sec-WebSocket-Key')))
self.end_headers()
WebSocketServer.handle_websocket(self)
else:
self.send_response(404)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write('Not Found
')
在do_GET方法中,如果请求的路径是根路径/,则返回一个简单的HTML页面。如果请求的路径是/websocket,则返回一个101状态码,表示协议切换到WebSocket,并调用WebSocketServer模块的handle_websocket方法来处理WebSocket连接。
下面是WebSocketServer模块的代码。这个模块实现了对WebSocket握手和消息的处理。
import hashlib
import base64
def encrypt_key(key):
return base64.b64encode(hashlib.sha1(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest())
def handle_websocket(handler):
connection = handler.request
connection.sendall('HTTP/1.1 101 Web Socket Protocol Handshake\r
')
connection.sendall('Upgrade: WebSocket\r
')
connection.sendall('Connection: Upgrade\r
')
data = connection.recv(1024)
# 解析WebSocket握手请求并返回响应
headers = parse_headers(data)
response = generate_response(headers.get('Sec-WebSocket-Key'))
connection.sendall(response)
# 循环处理WebSocket消息
while True:
try:
data = connection.recv(1024)
if not data:
break
# 解析WebSocket消息
message = parse_message(data)
print 'Received message:', message
# 发送WebSocket消息
response = generate_message_response(message)
connection.sendall(response)
except Exception as e:
print 'Exception:', e
break
connection.close()
def parse_headers(data):
headers = {}
for line in data.split('\r
'):
if ':' in line:
key, value = line.split(':', 1)
headers[key.strip()] = value.strip()
return headers
def parse_message(data):
# 解析WebSocket消息
opcode = ord(data[0]) & 0x0F
mask = ord(data[1]) & 0x80
length = ord(data[1]) & 0x7F
if length == 126:
length = ord(data[2:4])
offset = 4
elif length == 127:
length = ord(data[2:10])
offset = 10
else:
offset = 2
if mask:
mask_key = data[offset:offset+4]
offset += 4
message = ''.join([chr(ord(byte) ^ ord(mask_key[i%4])) for i, byte in enumerate(data[offset:])])
else:
message = data[offset:]
return message
def generate_response(key):
# 生成WebSocket握手响应
response = []
response.append('HTTP/1.1 101 Web Socket Protocol Handshake\r
')
response.append('Upgrade: WebSocket\r
')
response.append('Connection: Upgrade\r
')
response.append('Sec-WebSocket-Accept: %s\r
' % encrypt_key(key))
response.append('\r
')
return ''.join(response)
def generate_message_response(message):
# 生成WebSocket消息响应
response = []
response.append('\x81')
response.append(chr(len(message)))
response.append(message)
return ''.join(response)
在handle_websocket方法中,我们首先发送一个WebSocket握手的响应,然后进入一个循环,不断接收和处理WebSocket消息。在处理WebSocket消息时,我们可以根据业务逻辑进行相应的处理,并发送响应消息给客户端。
最后,我们需要创建一个BaseHTTPServer.HTTPServer对象,并指定处理HTTP请求的处理器为我们定义的MyHandler类。然后调用serve_forever方法来启动服务器。
if __name__ == '__main__':
server_address = ('', 8000)
httpd = BaseHTTPServer.HTTPServer(server_address, MyHandler)
print 'Server started on port 8000'
httpd.serve_forever()
完整的使用例子如下:
import BaseHTTPServer
import WebSocketServer
import hashlib
import base64
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('<html><head><title>WebSocket Server</title></head>')
self.wfile.write('<body><h1>WebSocket Server</h1></body></html>')
elif self.path == '/websocket':
self.send_response(101)
self.send_header('Upgrade', 'websocket')
self.send_header('Connection', 'Upgrade')
self.send_header('Sec-WebSocket-Accept', WebSocketServer.encrypt_key(self.headers.getheader('Sec-WebSocket-Key')))
self.end_headers()
WebSocketServer.handle_websocket(self)
else:
self.send_response(404)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write('Not Found
')
if __name__ == '__main__':
server_address = ('', 8000)
httpd = BaseHTTPServer.HTTPServer(server_address, MyHandler)
print 'Server started on port 8000'
httpd.serve_forever()
使用上述代码启动服务器后,可以访问http://localhost:8000来查看WebSocket服务器页面。同时,我们可以使用WebSocket客户端来与服务器进行通信。
以下是一个简单的WebSocket客户端的使用示例:
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Client</title>
<script>
var socket;
function connect() {
socket = new WebSocket("ws://localhost:8000/websocket");
socket.onopen = function(e) {
console.log("Connected to WebSocket server");
};
socket.onmessage = function(e) {
console.log("Received message:", e.data);
};
socket.onclose = function(e) {
console.log("WebSocket connection closed");
};
}
function send() {
var message = document.getElementById("message").value;
socket.send(message);
}
</script>
</head>
<body>
<button onclick="connect()">Connect</button>
<input type="text" id="message" placeholder="Type a message">
<button onclick="send()">Send</button>
</body>
</html>
在浏览器中打开以上代码,点击"Connect"按钮进行连接,然后可以在输入框中输入消息并点击"Send"按钮发送给服务器。服务器接收到消息后会将消息返回给客户端并在控制台中打印。
以上就是使用BaseHTTPServer实现WebSocket服务器的方法,并给出了一个简单的使用示例。
