Skip to content

服务端模块详解

工程概览

  • 工程文件: src-server/Server.vbp
  • 启动对象: Form1
  • 输出文件: dist/服务端/Server.exe
  • 数据库文件: data.mdb (Access)

全局模块

Insts.bas — 全局实例与系统日志

定义服务端全局共享的实例:

vb
Public TcpServer As cWinsock   ' TCP 监听对象
Public Db As cDataBase         ' 数据库连接对象
Public FileServer As cFileServer  ' 文件服务器对象

全局日志函数:

vb
Public Sub AddLog(ByVal Msg As String, Optional Level As EnumLogLevel = LvInfo, Optional Title As String)
参数类型说明
MsgString日志内容
LevelEnumLogLevel日志级别:LvInfo, LvWarning, LvDanger
TitleString日志标题/分类

功能特点:

  • 日志同时输出到文件(通过 VBMAN.Logs)和主窗体 List2 列表
  • 列表最多保留 1000 条记录,超出自动移除最早记录
  • 日志文件按日期自动分目录存储

窗体模块

Form1.frm — 服务端主窗体

界面布局:

  • List1 — 左侧用户列表(显示昵称,在线用户前缀 [ 在线 ] 并置顶)
  • List2 — 右侧操作日志/信息列表
  • Label1 — 右上角在线客户端数量

菜单:

  • 文件 → 开机启动 — 切换 Windows 开机启动状态
  • 刷新用户 — 重新从数据库加载用户列表
  • 推送公告 — 打开 fNotify 编辑并推送公告

核心逻辑:

  1. Form_Load:

    • 创建 cWinsock 实例,监听 TCP 800 端口
    • 连接 data.mdb Access 数据库
    • 首次加载用户列表 LoadUsersFromDB True
    • 注册路由和中间件 RegRouter
    • 设置 Common.IsServer = True
  2. RegRouter — 注册中间件与路由:

    vb
    ' 中间件
    Common.MiddleWares.Add New mAuth, "Auth"
    
    ' 白名单(无需验证 Token)
    Common.MiddleWaresWhiteList.Add 1, "User/Login"
    
    ' 业务路由
    Common.Router.Add New bUser, "User"
    Common.Router.Add New cMessage, "Message"
    Common.Router.Add New bNotify, "Notify"
    Common.Router.Add New bCalc, "Calc"
  3. LoadUsersFromDB — 加载用户列表:

    • 参数 Force=True 时重新执行 SQL 查询
    • 使用静态变量 Users 缓存查询结果,避免频繁查库
    • 遍历用户,通过 mTcp.ExistsUser(x("UserName")) 判断在线状态
    • 在线用户添加 [ 在线 ] 前缀并插入到列表顶部(AddItem ..., 0
  4. Tcp 事件:

    • ConnectionRequest — 新客户端接入(可用于 IP 白名单控制)
    • ClientCountChange — 客户端数量变化时更新状态栏和在线列表
    • DataArrival — 调用 Common.HandleReciver 分发请求
    • CloseEvent — 客户端断开

fNotify.frm — 公告编辑器

界面元素:

  • Text1 — 公告标题
  • Text2 — 公告内容(多行文本)
  • Command1 — 立即推送按钮
  • Command2 — 清空按钮
  • Label3 — 显示上次推送时间

核心逻辑:

  1. Form_Load:

    • config.ini 读取已保存的公告内容并填充
  2. Command1_Click (推送):

    vb
    VBMAN.Ini.Section("Notify")("Time") = Format(Now, "yyyy年MM月dd日 hh:mm:ss")
    VBMAN.Ini.Section("Notify")("Title") = Text1.Text
    VBMAN.Ini.MultiLineText("Notify", "Content") = Text2.Text
    VBMAN.Ini.SaveTo
    Common.SendToAll Insts.TcpServer, "Notify/Show", VBMAN.Ini("Notify")

    公告保存到 INI 文件后,向所有在线客户端广播。

  3. Command2_Click (清空):

    • 删除 INI 中的公告节点
    • 发送空公告到所有客户端,实现"撤回"效果

日志系统

服务端采用多级日志设计,分为全局系统日志业务专用日志两类:

  • 全局系统日志: Insts.AddLog — 记录系统启动、客户端连接/断开、登录认证等事件
  • 业务专用日志: 各模块独立的 cLogs 实例 — 记录业务数据(如文件传输、计算参数、公告推送等)

详细说明请参考 日志系统详解


业务类

bUser.cls — 用户登录验证

方法说明
Login(Inst, Data)处理客户端登录请求,验证账号密码,生成 Token,绑定用户
ChangePassword(Inst, Data)处理客户端修改密码请求,验证旧密码并更新数据库

登录验证流程:

  1. Data 中提取 usernamepassword
  2. 查询数据库: select * from users where username='xxx'
  3. 验证用户名是否存在、密码是否设置、密码是否匹配
  4. 如果该账号已在线 → 向旧客户端发送"账号在另外一个地方登录",并强制断开 (CloseUser)
  5. 生成 GUID 作为 Token
  6. 绑定用户到连接: TcpServer.BindUser UserName, Inst, Token, UserData
  7. 刷新服务端用户列表 Form1.LoadUsersFromDB
  8. 返回用户信息给客户端: SendTo Inst, "User/Info", .Row

修改密码流程 (ChangePassword):

  1. Data 中提取 oldPasswordnewPassword
  2. 获取当前连接绑定的用户名 Inst.CurrentUser 和客户端 IP
  3. 参数验证:
    • 旧密码或新密码为空 → 拒绝,记录日志
  4. 数据库验证:
    • 查询用户信息,用户不存在 → 拒绝,记录详细日志(包含提交的账号、密码、IP)
    • 验证旧密码,不匹配 → 拒绝,记录日志(包含提交的密码、IP)
  5. 更新密码:
    • 执行 SQL: update users set password='xxx' where ID=xxx
    • 发送 Toast 通知客户端"密码修改成功"
    • 记录成功日志(包含用户名、IP)
    • 返回更新后的用户信息

安全日志记录:

场景日志级别记录内容
参数为空Warn用户名、IP
用户不存在Danger提交的账号、旧密码、新密码、IP
旧密码错误Warn用户名、提交的旧密码、IP
修改成功Info用户名、IP

数据库表结构 (users):

字段类型说明
IDAutoNumber主键
UserNameText登录账号
NickNameText显示昵称
PasswordText哈希后的密码

bNotify.cls — 公告查询

方法说明
CheckNew(Inst, Data)客户端启动后调用,查询是否有离线期间的公告

逻辑:

  • 如果 INI 中存在公告 → 将公告内容发送给请求客户端
  • 如果没有公告 → 发送空对象,客户端显示"暂无公告..."

bCalc.cls — 参数计算处理

方法说明
Submit(Inst, Data)接收客户端发送的 50 个参数,模拟修改后回传

模拟修改示例:

vb
Data("id") = 1000
Data("memo") = Data("memo") & vbCrLf & "这是服务端追加的备注内容"
Data("remark") = "你可以修改更多的字段"
Common.SendTo Inst, "Calc/Show", Data.Root

实际业务中可以在此进行真实的计算、数据校验、持久化等操作。


中间件

mAuth.cls — 授权验证中间件

设计理念: 中间件是前置拦截器,所有请求(除白名单外)在进入业务逻辑前都必须通过中间件校验。

接口定义:

vb
Public Function Entry(Inst As cWinsock, Req As cJson, Optional LastError As String) As Boolean
参数说明
Inst当前客户端连接实例
Req客户端发来的完整 JSON 请求对象
LastError若返回 False,此参数携带错误信息回传给客户端

校验规则:

  1. Req("token") = "" → 错误: "凭证为空"
  2. Inst.CurrentUserToken = "" → 错误: "当前客户端未绑定用户"
  3. Inst.CurrentUserToken <> Req("token") → 错误: "凭证验证失败"
  4. 全部通过 → 返回 True

扩展中间件: 可按相同模式新增中间件类,在 Form1.RegRouter 中添加到 MiddleWares 集合即可实现链式调用。


数据库操作

服务端使用 VBMAN 的 cDataBase 对象操作 Access 数据库:

vb
Dim mDB As New cDataBase
mDB.Connect Access, App.Path & "\data.mdb"

' 查询单条记录
mDB.Sql("select * from users where username='wangli'").Fetch
If mDB.Row.Count > 0 Then
    Debug.Print mDB.Row("NickName")
End If

' 查询多条记录
mDB.Sql("select * from users").Query
Dim Users As New cJson
Users.Decode mDB.Rs

常用方法:

方法说明
.Connect Access, 路径连接 Access 数据库
.Sql("...")设置 SQL 语句
.Fetch执行并获取单条记录到 .Row
.Query执行并获取记录集到 .Rs
.Row.Count返回记录数(0 表示无记录)

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