Skip to main content

一个Python WebSocket服务端框架,支持零配置多文件路由管理,实现高效、模块化的实时通信开发。

Project description

NoWebsocket 库 使用文档

一个Python WebSocket服务端框架,支持零配置多文件路由管理,实现高效、模块化的实时通信开发。

安装指南

环境要求

  • Python 3.7+
  • 依赖库:无额外依赖

安装步骤

  1. 将库代码克隆到项目目录:
    git clone git@github.com:dzy-china/NoWebsocket.git
    
  2. pip安装:
    pip install NoWebsocket
    

快速开始

创建一个简单的WebSocket服务器

from NoWebsocket import WebSocketServer, WebSocketRouter, WebSocketApplication

# 定义应用类
class EchoApp(WebSocketApplication):
    def on_message(self, message):
        self.connection.send_text(f"Echo: {message}")

# 配置路由
router = WebSocketRouter()
router.add_route("/echo", EchoApp)

# 启动服务器
server = WebSocketServer(("0.0.0.0", 8765), router)
print("Server running on ws://localhost:8765/echo")
server.serve_forever()

测试连接

使用WebSocket客户端工具(如websocat)连接:

websocat ws://localhost:8765/echo

优雅开始

入口文件:main.py

from NoWebsocket import WebSocketServer, WebSocketRouter, Blueprint


def create_app():
    router = WebSocketRouter()

    # 自动注册所有蓝图
    Blueprint.auto_register(
        router,
        package_path='blueprints',
        bp_suffix='_bp'
    )

    return WebSocketServer(("0.0.0.0", 9000), router)


if __name__ == "__main__":
    server = create_app()
    print("WebSocket server running on ws://localhost:9000")
    try:
        server.serve_forever()  # 启动服务
    except KeyboardInterrupt:
        server.shutdown()  # 优雅关闭
        print("\n🛑 Server stopped")

路由控制器处理文件:blueprints/chat/Uer.py

blueprints包下必须存在__init__.py,该文件可以为空, 一个目录必须包含__init__.py文件才能被识别为(Package),这是Python模块系统的约定

from NoWebsocket import WebSocketApplication, Blueprint

chat_bp = Blueprint(prefix='/chat')

@chat_bp.route("/youmi")
class User(WebSocketApplication):
    def on_open(self):
        """连接建立时触发"""
        pass

    def on_message(self, message):
        print(message)
        self.connection.send_text(f"你好,我是悠米系统服务,收到了你的信息:\'{message}\'")

    def on_binary(self, data):
        """收到二进制消息时触发"""
        print(data)

    def on_close(self):
        """连接关闭时触发"""
        print("on_close")

测试连接 index.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <title>WebSocket 示例</title>
</head>
<body>
<div>
    <p>连接状态: <span id="status">未连接</span></p>
    <input type="text" id="messageInput" placeholder="输入消息">
    <button onclick="sendMessage()">发送</button>
</div>
<div id="messages"></div>

<script>
    // 创建 WebSocket 连接
    const socket = new WebSocket('ws://localhost:9000/chat/youmi'); // 使用公开测试服务器

    // 连接打开时触发
    socket.addEventListener('open', (event) => {
        updateStatus('已连接');
        logMessage('系统: 连接已建立');

        // 发送初始测试消息
        socket.send('你好,服务器!');
    });

    // 接收消息时触发
    socket.addEventListener('message', (event) => {
        logMessage(`服务器: ${event.data}`);
    });

    // 错误处理
    socket.addEventListener('error', (event) => {
        updateStatus('连接错误');
        console.error('WebSocket 错误:', event);
    });

    // 连接关闭时触发
    socket.addEventListener('close', (event) => {
        updateStatus('连接已关闭');
        logMessage(`系统: 连接关闭 (代码 ${event.code})`);
    });

    // 发送消息
    function sendMessage() {
        const input = document.getElementById('messageInput');
        const message = input.value;

        if (message) {
            socket.send(message);
            logMessage(`你: ${message}`);
            input.value = '';
        }
    }

    // 更新状态显示
    function updateStatus(status) {
        document.getElementById('status').textContent = status;
    }

    // 记录消息到页面
    function logMessage(message) {
        const messagesDiv = document.getElementById('messages');
        const p = document.createElement('p');
        p.textContent = message;
        messagesDiv.appendChild(p);
    }
</script>
</body>
</html>

配置选项

在服务器初始化时设置:

server = WebSocketServer(
    ("0.0.0.0", 8765),
    router,
    max_header_size=8192,       # 最大请求头大小
    max_message_size=4*1024*1024, # 最大消息大小(4MB)
    read_timeout=60              # 等待读取信息超时(秒)
)

路由管理

装饰器路由

blueprints/chat/Uer.py

from NoWebsocket import WebSocketApplication, Blueprint

chat_bp = Blueprint(prefix='/chat')  # 蓝图实例


@chat_bp.route("/youmi")
class User(WebSocketApplication):
    def on_open(self):
        """连接建立时触发"""
        pass

    def on_message(self, message):
        print(message)
        self.connection.send_text(f"你好,我是悠米服务,收到了你的信息:\'{message}\'")

    def on_binary(self, data):
        """收到二进制消息时触发"""
        print(data)

    def on_close(self):
        """连接关闭时触发"""
        print("on_close")

约定配置

main.py

from NoWebsocket import Blueprint

Blueprint.auto_register(
    router,
    package_path="blueprints", # 指定路由文件存放的包,包内必须存在`__init__.py`文件,该文件可以为空
    # 指定蓝图实例变量后缀,不写默认为'_bp'
    # 如:'chat_bp = Blueprint(prefix='/chat')'
    bp_suffix="_bp"
)

bp_suffix参数的存在是为了平衡灵活性与规范性,它通过命名约定帮助开发者更精确地控制哪些蓝图实例应被自动注册

目录结构示例

project/
├── blueprints/
	__init__.py  # 必须存在,可以为空
│   └── chat/
│       └── User.py   # 包含 chat_bp = Blueprint()
└── main.py

高级配置

自定义路由前缀

api_bp = Blueprint(prefix="/api/v2")

@api_bp.route("/status")
class StatusHandler(WebSocketApplication):
    def on_open(self):
        self.connection.send_text("API v2 Ready")

参数化路由

定义动态路径

router.add_route("/user/{user_id:int}", UserHandler)

在应用中获取参数

class UserHandler(WebSocketApplication):
    def on_open(self):
        user_id = self.path_params["user_id"]
        self.connection.send_text(f"User ID: {user_id}")

示例应用

聊天应用

# blueprints/chat/handlers.py
from NoWebsocket import WebSocketApplication, Blueprint

chat_bp = Blueprint(prefix="/chat")


@chat_bp.route("/public")
class PublicChat(WebSocketApplication):
    def on_message(self, message):
        self.connection.send_text(f"[Public] {message}")


@chat_bp.route("/private/{room}")
class PrivateChat(WebSocketApplication):
    def on_message(self, message):
        room = self.path_params["room"]
        self.connection.send_text(f"[{room}] {message}")

文件传输

# blueprints/file/handlers.py
from NoWebsocket import WebSocketApplication, Blueprint

file_bp = Blueprint(prefix="/file")


@file_bp.route("/upload")
class FileUpload(WebSocketApplication):
    def on_binary(self, data):
        with open("received_file.bin", "ab") as f:
            f.write(data)

常见问题

1. 如何处理连接中断?

  • 现象:客户端意外断开。
  • 解决:在on_close中清理资源:
    class MyApp(WebSocketApplication):
        def on_close(self):
            print("Connection closed")
    

2. 如何调试协议错误?

  • 步骤
    1. 启用详细日志:
      import logging
      logging.basicConfig(level=logging.DEBUG)
      
    2. 检查握手头和帧格式是否符合RFC6455。

3. 如何扩展应用基类?

  • 示例:添加身份验证:

    class AuthApp(WebSocketApplication):
        def on_open(self):
            token = self.connection.request.headers.get("token")
            if not validate_token(token):
                self.connection.close(1008, "Invalid token")
    

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nowebsocket-2.0.0.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nowebsocket-2.0.0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

File details

Details for the file nowebsocket-2.0.0.tar.gz.

File metadata

  • Download URL: nowebsocket-2.0.0.tar.gz
  • Upload date:
  • Size: 11.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.1

File hashes

Hashes for nowebsocket-2.0.0.tar.gz
Algorithm Hash digest
SHA256 0736d6b08bf010015aaeceb5d76d9db4d9af035a56a909fb999dc460c91a273d
MD5 d3e807838b3be93e462dde5f0b7f4c5a
BLAKE2b-256 d2e3a2595a374f1603e509001720ddb92c769f9cf3eab81d6eec5394108c6d3d

See more details on using hashes here.

File details

Details for the file nowebsocket-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: nowebsocket-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 13.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.1

File hashes

Hashes for nowebsocket-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3aca7faf26acff311f1f011af3b2fcf54f48186d114c19914a30acfa3d0aedee
MD5 af60ea687917f87dc3581566a250bf4e
BLAKE2b-256 6c2e517da1170e6c190e60c6e8e7f250ae90dfb3f705a4f1739c1a5b2cadd24f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page