You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
11 KiB
11 KiB
通信协议
本文档详细介绍 Flash Send 使用的网络通信协议。
概述
Flash Send 使用三种协议进行通信:
| 协议 | 端口 | 用途 | 加密 |
|---|---|---|---|
| UDP | 53317 | 设备发现 | 无 |
| WebSocket | 53318 | 即时聊天 | 无(局域网) |
| HTTPS | 53319 | 文件传输 | TLS |
设备发现协议
广播机制
使用 UDP 广播在局域网内发现设备。
广播地址: 255.255.255.255:53317
广播频率: 每 3 秒一次
消息格式
所有消息使用 JSON 格式,以换行符 \n 结尾。
广播消息 (Announce)
设备向局域网广播自身信息:
{
"type": "announce",
"device": {
"device_id": "550e8400-e29b-41d4-a716-446655440000",
"device_name": "My Computer",
"ip": "192.168.1.100",
"ws_port": 53318,
"http_port": 53319,
"last_seen": 1701388800
}
}
响应消息 (Response)
收到广播后,设备回复自身信息:
{
"type": "response",
"device": {
"device_id": "661e9500-f30c-52e5-b827-557766551111",
"device_name": "Other PC",
"ip": "192.168.1.101",
"ws_port": 53318,
"http_port": 53319,
"last_seen": 1701388805
}
}
设备状态
- 在线: 每 3 秒收到广播/响应
- 离线: 超过 15 秒未收到任何消息
流程图
┌─────────────┐ ┌─────────────┐
│ Device A │ │ Device B │
└──────┬──────┘ └──────┬──────┘
│ │
│ UDP Broadcast (announce) │
│ 255.255.255.255:53317 │
│ ─────────────────────────────────────────▶ │
│ │
│ UDP Response │
│ ◀───────────────────────────────────────── │
│ │
│ Device A adds Device B to list │
│ │
│ Device B adds │
│ Device A to list │
│ │
WebSocket 聊天协议
连接建立
- 客户端连接到目标设备的 WebSocket 服务
- 发送握手消息
- 服务端确认后,连接建立
连接地址: ws://{ip}:{ws_port}
消息格式
所有消息使用 JSON 格式。
握手消息 (Handshake)
客户端首先发送握手消息:
{
"type": "handshake",
"device_id": "550e8400-e29b-41d4-a716-446655440000",
"device_name": "My Computer"
}
聊天消息 (Chat)
{
"type": "chat",
"message": {
"id": "msg-uuid-12345",
"from_device": "550e8400-e29b-41d4-a716-446655440000",
"to_device": "661e9500-f30c-52e5-b827-557766551111",
"content": "Hello, World!",
"message_type": "text",
"timestamp": 1701388800000
}
}
message_type 枚举:
text: 普通文本image: 图片(content 为 base64 或路径)file: 文件(content 为文件名)system: 系统消息
确认消息 (Ack)
{
"type": "ack",
"message_id": "msg-uuid-12345"
}
心跳消息 (Ping/Pong)
{
"type": "ping"
}
{
"type": "pong"
}
连接管理
- 心跳间隔: 30 秒
- 超时断开: 90 秒无响应
- 自动重连: 断开后尝试重连
流程图
┌─────────────┐ ┌─────────────┐
│ Client │ │ Server │
└──────┬──────┘ └──────┬──────┘
│ │
│ WebSocket Connect │
│ ─────────────────────────────────────────▶ │
│ │
│ Handshake │
│ ─────────────────────────────────────────▶ │
│ │
│ Connection OK │
│ ◀───────────────────────────────────────── │
│ │
│ Chat Message │
│ ─────────────────────────────────────────▶ │
│ │
│ Ack │
│ ◀───────────────────────────────────────── │
│ │
│ Ping │
│ ─────────────────────────────────────────▶ │
│ │
│ Pong │
│ ◀───────────────────────────────────────── │
│ │
HTTPS 文件传输协议
TLS 配置
- 证书类型: 自签名 RSA 2048
- 证书有效期: 365 天
- 客户端验证: 跳过(局域网内互信)
端点
POST /upload
上传文件到服务端。
Content-Type: multipart/form-data
表单字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| file_id | string | 文件传输 ID |
| from_device | string | 发送方设备 ID |
| file | binary | 文件内容 |
请求示例:
POST /upload HTTP/1.1
Host: 192.168.1.100:53319
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 12345
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file_id"
550e8400-e29b-41d4-a716-446655440000
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="from_device"
661e9500-f30c-52e5-b827-557766551111
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="document.pdf"
Content-Type: application/pdf
<binary data>
------WebKitFormBoundary7MA4YWxkTrZu0gW--
响应:
HTTP/1.1 200 OK
Content-Type: application/json
{
"success": true,
"file_id": "550e8400-e29b-41d4-a716-446655440000",
"file_name": "document.pdf",
"file_size": 12345
}
GET /download/{file_id}
从服务端下载文件(预留接口)。
传输流程
┌─────────────┐ ┌─────────────┐
│ Sender │ │ Receiver │
└──────┬──────┘ └──────┬──────┘
│ │
│ 1. Create FileTransfer record │
│ (status: pending) │
│ │
│ 2. TLS Handshake │
│ ─────────────────────────────────────────▶ │
│ │
│ 3. POST /upload (multipart) │
│ ─────────────────────────────────────────▶ │
│ [chunk 1] │
│ emit progress event │
│ ─────────────────────────────────────────▶ │
│ [chunk 2] │ 4. Save to disk
│ emit progress event │ emit progress event
│ ─────────────────────────────────────────▶ │
│ [chunk n] │
│ emit progress event │
│ │
│ HTTP 200 OK │
│ ◀───────────────────────────────────────── │
│ │
│ 5. Update status: completed │ 5. Update status: completed
│ emit final progress event │ emit final progress event
│ │
分块传输
大文件使用分块传输,每块大小为 64KB。
进度计算:
progress = transferred_bytes / total_bytes
进度事件:
- 每发送一个块后触发
- 包含当前进度、已传输字节数、总字节数
取消机制
- 发送方调用
cancel_transfer - 触发 CancellationToken
- 上传循环检测到取消,中断传输
- 更新状态为
cancelled - 发送进度事件通知前端
安全考虑
局域网信任模型
Flash Send 假设局域网内的设备是可信的:
- UDP 广播不加密(仅设备发现)
- WebSocket 不加密(聊天内容)
- HTTP 使用 TLS(文件传输)
TLS 证书
- 应用首次启动时生成自签名证书
- 证书存储在用户数据目录
- 客户端跳过证书验证(
dangerous_configuration)
建议
如果需要更高安全性:
- 添加设备配对/授权机制
- 使用端到端加密
- 添加消息签名验证
端口冲突处理
如果默认端口被占用:
- 检测: 启动时检查端口可用性
- 提示: 通知用户端口冲突
- 配置: 允许用户在设置中修改端口
端口范围建议: 53317 - 53399