Skip to content

文件传输系统

概述

cs-auther 的文件传输系统基于 TCP 独立连接 实现,与主消息通道分离,支持大文件的分片传输、断点续传、进度监控和安全验证。


架构设计

┌─────────────────────────────────────────────────────────────────────────────┐
│                              文件传输架构图                                   │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────────────┐                    ┌─────────────────────┐       │
│   │     客户端           │                    │      服务端          │       │
│   │  ┌───────────────┐  │      TCP:801       │  ┌───────────────┐  │       │
│   │  │  cFileClient  │◄─┼───────────────────►┼─►│  cFileServer  │  │       │
│   │  │  (发送/接收)   │  │   独立文件传输通道  │  │  (接收/发送)   │  │       │
│   │  └───────┬───────┘  │                    │  └───────┬───────┘  │       │
│   │          │          │                    │          │          │       │
│   │  ┌───────▼───────┐  │                    │  ┌───────▼───────┐  │       │
│   │  │  业务事件      │  │                    │  │  bFileManage  │  │       │
│   │  │ OnSending     │  │                    │  │  (文件管理)    │  │       │
│   │  │ OnRecving     │  │                    │  │  自动归档存储   │  │       │
│   │  │ OnSendFinish  │  │                    │  │  日志记录      │  │       │
│   │  │ OnRecvFinish  │  │                    │  └───────────────┘  │       │
│   │  └───────────────┘  │                    │                     │       │
│   └─────────────────────┘                    └─────────────────────┘       │
│                                                                             │
│   ┌─────────────────────────────────────────────────────────────────────┐  │
│   │                         主消息通道 (TCP:800)                        │  │
│   │                    用于控制命令和文件列表查询                        │  │
│   └─────────────────────────────────────────────────────────────────────┘  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

端口分配

服务端口说明
消息服务800JSON 协议,处理业务逻辑
文件服务801分片传输,处理文件数据

核心组件

1. cFileClient (客户端)

位于 share/cFileClient.cls,封装了客户端文件传输的所有功能。

主要属性

属性类型说明
ChunkSizeLong分片大小,默认 32KB
LastErrorString最后一次错误信息

主要方法

vb
' 连接到文件服务器
Public Sub StartConnectTo(ByVal Server As String, Optional ByVal Port As Long = 803)

' 断开连接
Public Sub Disconnect()

' 发送文件到服务端
Public Function SendToServer(ByVal FileName As String) As Boolean

' 服务端回调:接收文件分片
Public Sub RecvFromServer(Inst As cWinsock, Data As cJson)

' 服务端回调:请求下一个分片
Public Sub SendMeNextFileChunk(Inst As cWinsock, Data As cJson)

' 服务端回调:发送完成确认
Public Sub OnSendComplete(Inst As cWinsock, Data As cJson)

事件

vb
' 正在发送文件
Event OnSending(ByVal FileName As String, ByVal CurrentChunk As Long, ByVal TotalChunks As Long, ByVal Percent As Long)

' 正在接收文件
Event OnRecving(ByVal FileName As String, ByVal CurrentChunk As Long, ByVal TotalChunks As Long, ByVal Percent As Long)

' 发送完成
Event OnSendFinish(ByVal FileName As String)

' 接收完成
Event OnRecvFinish(ByVal FileName As String, ByVal FilePath As String)

2. cFileServer (服务端)

位于 share/cFileServer.cls,处理多客户端并发文件传输。

主要属性

属性类型说明
ChunkSizeLong分片大小,默认 32KB
LastErrorString最后一次错误信息

主要方法

vb
' 启动文件服务
Public Sub StartMe(Optional Port As Long = 801, Optional IP As String = "0.0.0.0")

' 停止服务
Public Sub StopServer()

' 发送文件给指定用户
Public Function SendToClient(ByVal User As String, ByVal FileName As String) As Boolean

' 客户端回调:绑定Token
Public Sub BindClientToken(Inst As cWinsock, Data As cJson)

' 客户端回调:接收文件分片
Public Sub RecvFromClient(Inst As cWinsock, Data As cJson)

' 客户端回调:请求下一个分片
Public Sub SendMeNextFileChunk(Inst As cWinsock, Data As cJson)

事件

vb
' 客户端正在上传
Event OnClientSending(ByVal User As String, ByVal FileName As String, ByVal CurrentChunk As Long, ByVal TotalChunks As Long, ByVal Percent As Long)

' 客户端上传完成
Event OnClientSendFinish(ByVal User As String, ByVal FileName As String, ByVal FilePath As String)

' 正在发送给客户端
Event OnClientRecving(ByVal User As String, ByVal FileName As String, ByVal CurrentChunk As Long, ByVal TotalChunks As Long, ByVal Percent As Long)

' 发送给客户端完成
Event OnClientRecvFinish(ByVal User As String, ByVal FileName As String)

3. bFileManage (业务管理层)

位于 src-server/bFileManage.cls,在 cFileServer 之上封装业务逻辑。

主要功能

  • 自动归档:接收的文件自动按用户/年月分类存储
  • 独立日志:文件传输日志与系统日志分离
  • 文件管理:提供文件列表查询、删除等接口

存储结构

Server.exe 同目录
└── files/
    └── {用户名}/
        └── {年}/
            └── {月}/
                └── 文件名_年月日_时分秒.ext

路由接口

vb
' 获取当前用户的文件列表
Public Sub GetMyFilesList(Inst As cWinsock, Data As cJson)
    → 响应: FileManage/OnFilesList

' 删除指定文件
Public Sub DeleteMyFile(Inst As cWinsock, Data As cJson)
    → 响应: FileManage/OnFileDeleted

传输协议

分片数据结构

文件传输使用 JSON 协议,每个分片包含以下字段:

json
{
  "FileID": "GUID字符串",
  "FileName": "原始文件名",
  "FileSize": 1048576,
  "ChunkSize": 32768,
  "TotalChunks": 32,
  "CurrentChunk": 5,
  "NextChunk": 6,
  "ChunkData": "Base64编码的数据...",
  "IsLastChunk": false
}

传输流程

客户端 → 服务端(上传)

┌─────────┐                                          ┌─────────┐
│ Client  │                                          │ Server  │
└────┬────┘                                          └────┬────┘
     │                                                  │
     │  1. 发送第1片 (CurrentChunk=1)                   │
     │ ────────────────────────────────────────────────>│
     │     action: "FileServer/RecvFromClient"          │
     │                                                  │
     │                                                  │──┐ 写入临时文件
     │                                                  │  │ files/tmp/{FileID}.tmp
     │                                                  │<-┘
     │                                                  │
     │  2. 请求第2片                                    │
     │ <────────────────────────────────────────────────│
     │     action: "FileClient/SendMeNextFileChunk"     │
     │     { "NextChunk": 2 }                           │
     │                                                  │
     │  3. 发送第2片                                    │
     │ ────────────────────────────────────────────────>│
     │     ...                                          │
     │                                                  │
     │  n. 发送最后一片 (IsLastChunk=true)              │
     │ ────────────────────────────────────────────────>│
     │                                                  │
     │  n+1. 发送完成确认                               │
     │ <────────────────────────────────────────────────│
     │     action: "FileClient/OnSendComplete"          │
     │                                                  │──┐ 归档到目标目录
     │                                                  │  │ files/{user}/{yyyy}/{mm}/
     │                                                  │<-┘

服务端 → 客户端(下发)

┌─────────┐                                          ┌─────────┐
│ Client  │                                          │ Server  │
└────┬────┘                                          └────┬────┘
     │                                                  │
     │  1. 发送第1片                                    │
     │ <────────────────────────────────────────────────│
     │     action: "FileClient/RecvFromServer"          │
     │                                                  │
     │──┐ 写入临时文件                                  │
     │  │ {FileID}.tmp                                  │
     │<-┘                                               │
     │                                                  │
     │  2. 请求下一片                                   │
     │ ────────────────────────────────────────────────>│
     │     action: "FileServer/SendMeNextFileChunk"     │
     │                                                  │
     │  3. 发送下一片                                   │
     │ <────────────────────────────────────────────────│
     │     ...                                          │
     │                                                  │
     │  n. 发送完成                                     │
     │ <────────────────────────────────────────────────│
     │     (服务端清理资源)                              │

身份验证

文件传输通道使用 Token 绑定机制进行身份验证:

连接建立流程

vb
' 客户端连接成功后,自动发送 Token 绑定
Private Sub mTcp_Connect(Client As VBMANLIB.cWinsock)
    With New cJson
        .Item("token") = Common.UserToken           ' 从登录获取的凭证
        Set .Item("user") = Insts.CurrentUser.Root  ' 当前用户信息
        Common.SendTo Client, "FileServer/BindClientToken", .Root
    End With
End Sub

服务端绑定处理

vb
Public Sub BindClientToken(Inst As cWinsock, Data As cJson)
    Inst.CurrentUserToken = Data("token")
    Inst.CurrentUserInfo.Decode Data("user")
    Inst.CurrentUser = Data("user")("UserName")
End Sub

注意:文件传输通道继承主消息通道的 Token,连接时需要显式绑定才能通过中间件验证。


使用示例

客户端发送文件

vb
Dim WithEvents FileClient As cFileClient

' 初始化并连接
Set FileClient = New cFileClient
FileClient.StartConnectTo "192.168.1.100", 801

' 发送文件
If FileClient.SendToServer("C:\Documents\report.pdf") Then
    Debug.Print "开始发送..."
Else
    Debug.Print "发送失败: " & FileClient.LastError
End If

' 监听进度
Private Sub FileClient_OnSending(ByVal FileName As String, ByVal CurrentChunk As Long, ByVal TotalChunks As Long, ByVal Percent As Long)
    ProgressBar1.Value = Percent
    Label1.Caption = "发送中: " & Percent & "%"
End Sub

' 发送完成
Private Sub FileClient_OnSendFinish(ByVal FileName As String)
    MsgBox "文件发送完成: " & FileName
End Sub

服务端主动下发文件

vb
' 在 bFileManage 中调用
Public Sub SendFileToUser_Click()
    Dim UserName As String
    UserName = "zhangsan"

    If bFileManage.SendFileToUser(UserName, "C:\Files\notice.pdf") Then
        Debug.Print "开始发送给 " & UserName
    End If
End Sub

获取文件列表

vb
' 客户端请求
With New cJson
    Common.SendTo Insts.TcpClient, "FileManage/GetMyFilesList", .Root
End With

' 客户端接收响应 (在 bFileManage 中实现)
Public Sub OnFilesList(Data As cJson)
    ' Data.Root 包含文件列表数组
    For Each FileItem In Data.Root
        ListView.AddItem FileItem("Name")
    Next
End Sub

配置说明

分片大小调整

vb
' 客户端
FileClient.ChunkSize = 64& * 1024&  ' 设置为 64KB

' 服务端
bFileManage.StartMe Port
mFileServer.ChunkSize = 1024& * 1024&  ' 设置为 1MB

建议

  • 局域网环境:64KB ~ 1MB
  • 互联网环境:16KB ~ 32KB
  • 超大文件:增大分片可减少协议开销

错误处理

常见错误

错误信息原因解决方案
当前有正在发送的文件同时发起多个发送请求等待当前传输完成或创建新的 cFileClient 实例
用户不在线服务端下发时用户已断开检查用户在线状态后再发送
临时文件不存在文件被清理或权限问题检查目录权限和磁盘空间

事件中的错误处理

vb
Private Sub FileClient_OnSendFinish(ByVal FileName As String)
    If FileClient.LastError <> "" Then
        MsgBox "传输出错: " & FileClient.LastError
    Else
        MsgBox "传输成功!"
    End If
End Sub

性能优化

  1. 并发传输:每个用户独立维护传输状态,支持多用户同时传输
  2. 分片缓存:接收时直接追加写入临时文件,减少内存占用
  3. Base64 编码:兼容 JSON 传输,相比二进制略增 33% 体积
  4. 独立通道:文件传输与业务消息分离,避免阻塞

安全建议

  1. 文件类型过滤:在 bFileManage.OnClientSendFinish 中检查扩展名
  2. 大小限制:在发送前检查 FileSize 是否超过限制
  3. 路径校验DeleteMyFile 中已包含安全校验,确保只能删除自己的文件
  4. Token 过期:与主通道 Token 生命周期保持一致

VB6及其LOGO版权为微软公司所有