系统架构
整体架构图
┌─────────────────────────────────────────────────────────────────┐
│ 客户端 (Client) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ fLogin │ │ Form1 │ │ fSetting │ │ bCalc/bUser │ │
│ │ (登录窗) │ │ (主窗体) │ │ (配置窗) │ │ (业务类) │ │
│ └────┬─────┘ └────┬─────┘ └──────────┘ └──────┬───────┘ │
│ │ │ │ │
│ └──────────────┴───────────────┬───────────────┘ │
│ │ │
│ ┌────────────▼────────────┐ │
│ │ cWinsock (TcpClient) │ │
│ └────────────┬────────────┘ │
└──────────────────────────────────────┼──────────────────────────┘
│ TCP / JSON
┌──────────────────────────────────────┼──────────────────────────┐
│ ┌────────────▼────────────┐ │
│ │ cWinsock (TcpServer) │ │
│ └────────────┬────────────┘ │
│ │ │
│ ┌──────────────┬───────────────┼───────────────┐ │
│ │ │ │ │ │
│ ┌────┴─────┐ ┌────┴─────┐ ┌─────┴──────┐ ┌────┴─────┐ │
│ │ mAuth │ │ bUser │ │ bNotify │ │ bCalc │ │
│ │(中间件) │ │(登录业务)│ │(公告业务) │ │(参数计算)│ │
│ └──────────┘ └──────────┘ └────────────┘ └──────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────────────┐ │
│ │ Form1 │ │ fNotify │ │ cDataBase (Access .mdb) │ │
│ │(主监控窗)│ │(公告编辑)│ │ users 表 │ │
│ └──────────┘ └──────────┘ └───────────────────────────┘ │
│ 服务端 (Server) │
└─────────────────────────────────────────────────────────────────┘运行流程
1. 服务端启动流程
- 启动
Server.exe,加载Form1 - 创建
cWinsock实例,监听 TCP 800 端口 - 连接同目录下的
data.mdb(Access 数据库) - 从数据库加载用户列表到左侧
ListBox - 注册中间件(
mAuth)与业务路由(bUser,bNotify,bCalc,cMessage) - 等待客户端接入
2. 客户端启动流程
- 启动
Client.exe,首先加载fLogin(登录窗体) - 读取
config.ini中的服务器 IP 和端口 - 若配置不存在,弹出
fSetting强制用户配置 - 注册业务路由(
bUser,bNotify,cMessage) - 尝试连接服务端
- 连接成功后启用登录按钮
3. 用户登录流程
┌─────────┐ ┌─────────┐
│ Client │ │ Server │
└────┬────┘ └────┬────┘
│ │
│ ─────── TCP 连接建立 ─────────────>│
│ │
│ {action:"User/Login", data:{...}} │
│ ──────────────────────────────────>│
│ │
│ │──┐ 查询 Access 数据库
│ │ │ 验证用户名/密码
│ │<-┘
│ │ 生成 Token
│ │ 绑定用户到连接实例
│ │
│ {action:"User/Info", token:"xxx"} │
│ <──────────────────────────────────│
│ │
│ 显示主窗体 Form1 │
│ 请求公告 Notify/CheckNew │
│ ──────────────────────────────────>│
│ │4. 中间件校验流程
所有非白名单请求在执行业务逻辑前,都会经过中间件链:
- 收到客户端数据 →
Common.HandleReciver - 解析 JSON,提取
action和token - 判断是否在白名单(如
User/Login)→ 跳过中间件 - 遍历所有中间件,执行
Entry方法 - 任一中间件返回
False→ 中断流程,向客户端发送错误提示 - 全部通过 →
CallByName调用对应的业务类方法
模块关系
| 层级 | 客户端 | 服务端 | 说明 |
|---|---|---|---|
| UI 层 | fLogin, Form1, fSetting | Form1, fNotify | 窗体界面与事件响应 |
| 业务层 | bUser, bNotify, bCalc | bUser, bNotify, bCalc | 处理具体业务逻辑 |
| 中间件层 | — | mAuth | 权限校验、前置拦截 |
| 通信层 | cWinsock | cWinsock | TCP 连接、数据收发 |
| 数据层 | CurrentUser (cJson) | cDataBase (Access) | 数据持久化与缓存 |
| 公共层 | Common.bas, cMessage.cls | Common.bas, cMessage.cls | 路由、发送、消息处理 |
关键设计模式
路由分发模式
采用字符串分割 + CallByName 实现轻量级路由:
vb
' action = "User/Login" → 拆分为类名 "User" 和方法名 "Login"
Dim Action As Variant: Action = Split(.Root("action"), "/")
CallByName Router.Item(Action(0)), Action(1), VbMethod, Client, DataRouter是一个cCollection,以类名为 Key 存储业务类实例- 新增业务只需:新建类 → 实现
Public Sub Xxx(Inst, Data)→ 注册到 Router
全局实例共享
通过标准模块中的 Public 变量实现跨模块共享:
客户端 (Insts.bas):
vb
Public TcpClient As cWinsock ' TCP 连接实例
Public CurrentUser As New cJson ' 当前登录用户信息服务端 (Insts.bas):
vb
Public TcpServer As cWinsock ' TCP 监听实例
Public Db As cDataBase ' 数据库连接实例事件驱动通信
客户端与服务端的窗体均通过 WithEvents 监听 cWinsock 事件:
vb
Dim WithEvents Tcp As cWinsock
Private Sub Tcp_Connect(Client As cWinsock)
' 连接成功
End Sub
Private Sub Tcp_DataArrival(Client As cWinsock, ByVal bytesTotal As Long)
Common.HandleReciver Client, bytesTotal
End Sub
Private Sub Tcp_CloseEvent(Client As cWinsock)
' 连接断开
End Sub