欢迎访问宙启技术站
智能推送

使用BaseHTTPServer实现WebSocket服务器

发布时间:2023-12-25 10:34:30

WebSocket服务器是一种与客户端进行全双工通信的通信协议。在Python中,可以使用BaseHTTPServer模块来实现WebSocket服务器。

首先,我们需要导入BaseHTTPServerWebSocketServerBaseHTTPServer模块提供了一个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服务器的方法,并给出了一个简单的使用示例。