207 lines
5.2 KiB
Markdown
207 lines
5.2 KiB
Markdown
# `BroadcastServer` 技术文档
|
||
|
||
本模块实现了一个基于 UDP 广播的发现服务,可用于局域网内设备或玩家的自动发现。主要包括一个广播服务器(`BroadcastServer`)和一个客户端发现函数(`find_players`)。
|
||
|
||
---
|
||
|
||
## 模块依赖
|
||
|
||
```python
|
||
from socket import *
|
||
import json
|
||
from appPublic.sockPackage import get_free_local_addr
|
||
from appPublic.background import Background
|
||
```
|
||
|
||
### 外部依赖说明:
|
||
|
||
- `socket`: 提供底层网络通信支持。
|
||
- `json`: 用于序列化/反序列化服务信息。
|
||
- `appPublic.sockPackage.get_free_local_addr`: 获取本地可用 IP 地址。
|
||
- `appPublic.background.Background`: 在后台线程中运行任务。
|
||
|
||
> ⚠️ 注意:`appPublic` 是自定义公共库,请确保其已安装并可导入。
|
||
|
||
---
|
||
|
||
## 常量定义
|
||
|
||
```python
|
||
BUFSIZE = 1024
|
||
```
|
||
|
||
- `BUFSIZE`: UDP 数据包最大接收缓冲区大小,单位为字节(1KB),适用于大多数局域网小数据传输场景。
|
||
|
||
---
|
||
|
||
## 类:`BroadcastServer`
|
||
|
||
一个 UDP 服务器,监听广播请求,并返回预设的服务信息(如主机名、端口等)给请求方。
|
||
|
||
### 构造函数:`__init__(self, port, info)`
|
||
|
||
#### 参数:
|
||
| 参数 | 类型 | 描述 |
|
||
|------|------|------|
|
||
| `port` | int | 服务器绑定的 UDP 端口号 |
|
||
| `info` | dict | 要广播的服务信息(例如:`{"name": "GameServer", "game_port": 8000}`) |
|
||
|
||
#### 功能:
|
||
1. 创建 UDP 套接字(IPv4, UDP)。
|
||
2. 设置套接字为阻塞模式(默认行为)。
|
||
3. 绑定到所有本地地址的指定端口 (`''` 表示 `0.0.0.0`)。
|
||
4. 启动后台线程运行 `run()` 方法。
|
||
|
||
#### 示例初始化:
|
||
```python
|
||
server_info = {
|
||
"name": "Player1",
|
||
"game_port": 6000,
|
||
"status": "waiting"
|
||
}
|
||
bc_server = BroadcastServer(9999, server_info)
|
||
```
|
||
|
||
---
|
||
|
||
### 方法:`run()`
|
||
|
||
在后台持续运行,处理来自客户端的广播探测请求。
|
||
|
||
#### 流程:
|
||
1. 循环等待接收 UDP 数据包(最多 `BUFSIZE` 字节)。
|
||
2. 收到任意数据后,将 `self.info` 序列化为 JSON 并编码为 UTF-8 发送回请求者的地址。
|
||
3. 异常捕获打印日志但不中断服务。
|
||
|
||
> 📌 协议约定:任何发往该端口的数据都会触发响应 —— 即“有问必答”模型。
|
||
|
||
#### 响应格式(JSON):
|
||
```json
|
||
{
|
||
"name": "Player1",
|
||
"game_port": 6000,
|
||
"status": "waiting"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 方法:`stop()`
|
||
|
||
安全停止服务器。
|
||
|
||
#### 功能:
|
||
- 设置运行标志 `run_flg = False`,终止 `run()` 循环。
|
||
- 关闭 UDP 套接字资源。
|
||
- 不主动等待线程结束(需业务层控制时序)。
|
||
|
||
#### 示例调用:
|
||
```python
|
||
bc_server.stop()
|
||
```
|
||
|
||
---
|
||
|
||
## 函数:`find_players(port)`
|
||
|
||
向局域网广播查询消息,寻找活跃的广播服务节点(如游戏主机)。
|
||
|
||
### 参数:
|
||
| 参数 | 类型 | 描述 |
|
||
|------|------|------|
|
||
| `port` | int | 目标广播服务器监听的端口号 |
|
||
|
||
### 返回值:
|
||
- `list[dict]`: 找到的设备信息列表,每个元素包含原始信息 + `'ip'` 字段。
|
||
|
||
```python
|
||
[
|
||
{
|
||
"name": "Player1",
|
||
"game_port": 6000,
|
||
"status": "waiting",
|
||
"ip": "192.168.1.105"
|
||
},
|
||
...
|
||
]
|
||
```
|
||
|
||
### 实现细节:
|
||
|
||
1. 使用 `get_free_local_addr()` 获取本机 IP,用于过滤自身响应。
|
||
2. 创建 UDP 客户端套接字并启用广播权限:
|
||
```python
|
||
udpCliSock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
|
||
```
|
||
3. 绑定任意端口(`('', 0)`)。
|
||
4. 向 `255.255.255.255:{port}` 发送广播消息 `'findplayers'`。
|
||
5. 接收响应,超时时间为 5 秒。
|
||
6. 对每条有效响应:
|
||
- 过滤非本地回环且非自身的 IP;
|
||
- 解码 JSON 数据;
|
||
- 添加来源 IP 到结果中;
|
||
7. 超时或异常时退出循环,返回收集结果。
|
||
|
||
> ✅ 支持跨子网?仅限局域网内支持广播的环境(通常不可跨路由)。
|
||
|
||
---
|
||
|
||
## 使用示例
|
||
|
||
### 启动广播服务(服务端)
|
||
|
||
```python
|
||
info = {"name": "MyGameHost", "game_port": 8888}
|
||
server = BroadcastServer(port=9999, info=info)
|
||
|
||
# ... 保持运行一段时间
|
||
# server.stop() # 显式关闭
|
||
```
|
||
|
||
### 搜索局域网中的服务(客户端)
|
||
|
||
```python
|
||
players = find_players(9999)
|
||
for p in players:
|
||
print(f"Found {p['name']} at {p['ip']}:{p['game_port']}")
|
||
```
|
||
|
||
输出示例:
|
||
```
|
||
Found MyGameHost at 192.168.1.105:8888
|
||
Found Player2 at 192.168.1.106:8889
|
||
```
|
||
|
||
---
|
||
|
||
## 注意事项与限制
|
||
|
||
| 项目 | 说明 |
|
||
|------|------|
|
||
| **协议** | UDP,不可靠传输,适合低延迟发现 |
|
||
| **广播地址** | 固定使用 `255.255.255.255`,适用于大多数局域网 |
|
||
| **安全性** | 无认证机制,仅适用于受信任内网 |
|
||
| **性能** | 单线程处理,适合轻量级发现场景 |
|
||
| **编码** | 默认使用 UTF-8 编码传输 JSON |
|
||
| **异常处理** | 已捕获异常防止崩溃,但建议上层监控 |
|
||
|
||
---
|
||
|
||
## 可能的改进方向
|
||
|
||
- ✅ 添加日志系统替代 `print`
|
||
- 🔧 支持多播替代广播以提高效率
|
||
- ⏱️ 可配置超时时间与重试次数
|
||
- 🛡️ 加入消息校验(如 magic header)
|
||
- 🔄 支持定期心跳广播(主动宣告)
|
||
|
||
---
|
||
|
||
## 版权与许可
|
||
|
||
© 2025 作者保留所有权利。
|
||
仅供内部学习与开发使用,遵循项目整体开源协议(如有)。
|
||
|
||
---
|
||
|
||
📌 **提示**:部署前请测试网络环境是否允许广播通信。 |