# 通信协议

本文档详细介绍 Flash Send 使用的网络通信协议。

## 概述

Flash Send 使用三种协议进行通信：

| 协议 | 端口 | 用途 | 加密 |
|------|------|------|------|
| UDP | 53317 | 设备发现 | 无 |
| WebSocket | 53318 | 即时聊天 | 无（局域网） |
| HTTPS | 53319 | 文件传输 | TLS |

## 设备发现协议

### 广播机制

使用 UDP 广播在局域网内发现设备。

**广播地址**: `255.255.255.255:53317`

**广播频率**: 每 3 秒一次

### 消息格式

所有消息使用 JSON 格式，以换行符 `\n` 结尾。

#### 广播消息 (Announce)

设备向局域网广播自身信息：

```json
{
  "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)

收到广播后，设备回复自身信息：

```json
{
  "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 聊天协议

### 连接建立

1. 客户端连接到目标设备的 WebSocket 服务
2. 发送握手消息
3. 服务端确认后，连接建立

**连接地址**: `ws://{ip}:{ws_port}`

### 消息格式

所有消息使用 JSON 格式。

#### 握手消息 (Handshake)

客户端首先发送握手消息：

```json
{
  "type": "handshake",
  "device_id": "550e8400-e29b-41d4-a716-446655440000",
  "device_name": "My Computer"
}
```

#### 聊天消息 (Chat)

```json
{
  "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)

```json
{
  "type": "ack",
  "message_id": "msg-uuid-12345"
}
```

#### 心跳消息 (Ping/Pong)

```json
{
  "type": "ping"
}
```

```json
{
  "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 | 文件内容 |

**请求示例**:
```http
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
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
```

**进度事件**:
- 每发送一个块后触发
- 包含当前进度、已传输字节数、总字节数

### 取消机制

1. 发送方调用 `cancel_transfer`
2. 触发 CancellationToken
3. 上传循环检测到取消，中断传输
4. 更新状态为 `cancelled`
5. 发送进度事件通知前端

---

## 安全考虑

### 局域网信任模型

Flash Send 假设局域网内的设备是可信的：
- UDP 广播不加密（仅设备发现）
- WebSocket 不加密（聊天内容）
- HTTP 使用 TLS（文件传输）

### TLS 证书

- 应用首次启动时生成自签名证书
- 证书存储在用户数据目录
- 客户端跳过证书验证（`dangerous_configuration`）

### 建议

如果需要更高安全性：
1. 添加设备配对/授权机制
2. 使用端到端加密
3. 添加消息签名验证

---

## 端口冲突处理

如果默认端口被占用：

1. **检测**: 启动时检查端口可用性
2. **提示**: 通知用户端口冲突
3. **配置**: 允许用户在设置中修改端口

**端口范围建议**: 53317 - 53399
