ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

飞机试飞数据处理管理系统:C/S三层架构与SQL Server 2005落地实践

飞机试飞数据处理管理系统:C/S三层架构与SQL Server 2005落地实践 简介这份文档面向飞行试验数据处理人员、系统管理员及软件开发者围绕飞机试飞数据处理管理系统FTDPMS展开完整的设计方案论述重点解决飞行数据种类繁多、命名不一致、检索困难以及安全性与完整性难以保障等问题。内容涵盖需求分析、C/S三层架构设计、系统开发与运行环境、数据库表结构组成以及客户端与应用服务器端的数据库访问流程并涉及DCOM、MTS等关键技术的实现思路。资源包内为1个docx文档大小约15KB属于纯文档型技术资料适合作为课程设计、毕业设计或工程方案撰写的参考模板。文中对机型机号表、飞行数据表、用户权限表等8个数据库表的设计以及服务器热备、负载均衡、任务调度等部署模式均有具体说明可帮助读者快速理解试飞数据管理系统的整体框架与落地要点。目前已有129人学习下载适合具备一定数据库与C/S开发基础的技术人员研读。1. 飞机试飞数据处理管理系统从数据孤岛到统一管控的落地拆解试飞数据管理最头疼的不是数据量大而是同一架次的数据散落在不同人的硬盘里命名规则各搞一套三个月后连原始文件都找不到。飞机试飞数据处理管理系统FTDPMS就是冲着这个问题去的——它把机型机号、飞行数据、处理软件、用户权限、上传下载记录全部收进一个基于 C/S 三层架构的数据库里用统一入口管起来。这套方案适合试飞院、飞行试验基地的数据管理员和事后数据处理工程师尤其是那些还在用共享文件夹加 Excel 台账管数据的团队。它不解决实时遥测只干事后的分类、索引、存储和权限控制但恰恰是这块最容易被忽视也最容易在型号任务密集时翻车。2. C/S 三层架构选型为什么不用 B/S 而用 DCOM 加 MTS2.1 三层架构的职责切分与试飞场景的匹配逻辑试飞数据处理有个硬约束单次架次产生的原始数据动辄几十 GBPCM、视频、遥测参数混在一起客户端需要直接访问磁盘阵列上的大文件。B/S 架构下浏览器没法高效处理这种量级的本地文件操作而 C/S 的客户端可以拿到文件系统句柄直接做分块读取和本地缓存。FTDPMS 把系统切成三层界面层跑在客户端负责用户交互和本地文件操作中间层跑在应用服务器上用 DCOM 做远程调用、MTS 做事务管理数据层就是 SQL Server 2005管元数据和索引。这种切法的好处是界面层改版不影响业务逻辑业务逻辑调整不动数据库结构。试飞院常见的情况是不同型号的数据处理流程有差异但底层数据表结构可以复用。把业务逻辑抽到中间层换型号时只改中间层的处理模块客户端和数据层基本不动。代价是 DCOM 配置在跨网段时容易出玄学问题后面避坑章节会细说。2.2 应用服务器端的 DCOM 与 MTS 配置实操中间层的核心是 DCOM 通信和 MTS 事务。DCOM 负责把客户端的请求序列化后传到应用服务器MTS 负责保证多个数据库操作要么全成功要么全回滚。配置分两步先注册 DCOM 组件再在 MTS 里配置事务属性。# 在应用服务器上注册 DCOM 组件以管理员身份运行 regsvr32 C:\FTDPMS\Server\FTDPMSSvr.dll # 打开组件服务管理器配置 DCOM 权限 dcomcnfg # 在组件服务 - 计算机 - 我的电脑 - DCOM 配置中找到 FTDPMSSvr # 右键属性 - 标识选项卡 - 选择交互式用户或指定专用账户 # 安全选项卡 - 启动和激活权限 - 自定义 - 添加客户端运行账户注册完成后在 MTS 里新建包把 FTDPMSSvr 组件拖进去设置事务属性为“需要事务”。这一步决定了数据上传时如果文件写入磁盘阵列成功但数据库记录失败MTS 会自动回滚文件写入操作避免出现“有文件没记录”的脏数据。-- 在 SQL Server 2005 中创建上传下载记录表用于 MTS 事务跟踪 CREATE TABLE UploadDownloadLog ( LogID INT IDENTITY(1,1) PRIMARY KEY, UserID INT NOT NULL, FileName NVARCHAR(255) NOT NULL, FileSize BIGINT, UploadTime DATETIME DEFAULT GETDATE(), Status TINYINT DEFAULT 0 -- 0:进行中 1:成功 2:失败 );参数说明UserID 关联用户表的用户编号FileName 存原始文件名含架次号和参数类型Status 字段配合 MTS 事务在文件写入前插入状态 0写入成功后更新为 1失败则 MTS 回滚整个事务。常见做法是再加一个触发器当 Status 变为 2 时自动清理磁盘上的残留文件。2.3 客户端数据访问流程与连接管理客户端不直接连数据库所有 SQL 请求都通过 DCOM 发给应用服务器。这样做的好处是数据库连接池集中在中间层管理客户端数量增加时不会把 SQL Server 的连接数打满。客户端的数据模块用 Delphi 2007 的 MIDAS 技术通过 TClientDataSet 和 TDataSetProvider 做数据传递。// Delphi 客户端通过 DCOM 连接应用服务器的核心代码 procedure TfrmMain.ConnectToAppServer; var Proxy: IFTDPMSSvr; begin try // 创建 DCOM 代理指定应用服务器 IP Proxy : CoFTDPMSSvr.CreateRemote(192.168.1.100); // 设置连接超时试飞院网络环境复杂建议 30 秒 Proxy.SetTimeout(30000); // 验证用户权限传入加密后的用户凭证 if Proxy.ValidateUser(edtUser.Text, edtPass.Text) then FConnected : True else ShowMessage(用户验证失败请检查权限配置); except on E: Exception do ShowMessage(连接应用服务器失败 E.Message); end; end;逻辑说明CreateRemote 指定应用服务器的 IP 地址ValidateUser 在中间层做权限校验返回布尔值。参数 30000 是超时毫秒数试飞院内部网络如果跨了防火墙或者走了光纤通道建议调到 60000。注意 DCOM 调用失败时异常信息往往很模糊常见的是“拒绝访问”或“RPC 服务器不可用”前者查 DCOM 权限配置后者查网络和防火墙的 135 端口。3. 八个核心数据表的设计与 SQL Server 2005 落地3.1 机型机号表与飞行数据表的主外键关系机型机号表是整条数据链的起点飞行数据表通过机号外键关联到具体飞机。试飞数据的特点是同一架飞机在不同架次、不同科目下产生的数据要能按机号聚合所以机号表的主键设计成“机型代码机号”的复合主键避免不同机型出现相同机号时冲突。-- 机型机号表 CREATE TABLE AircraftInfo ( AircraftType CHAR(4) NOT NULL, -- 机型代码如 Y20、J20 AircraftNo CHAR(6) NOT NULL, -- 机号如 001、002 Description NVARCHAR(200), CONSTRAINT PK_Aircraft PRIMARY KEY (AircraftType, AircraftNo) ); -- 飞行数据表通过复合外键关联机型机号表 CREATE TABLE FlightData ( DataID INT IDENTITY(1,1) PRIMARY KEY, AircraftType CHAR(4) NOT NULL, AircraftNo CHAR(6) NOT NULL, FlightDate DATE NOT NULL, SortieNo INT NOT NULL, -- 架次号 DataType TINYINT NOT NULL, -- 1:PCM 2:视频 3:遥测参数 4:其他 FilePath NVARCHAR(500) NOT NULL, -- 磁盘阵列上的相对路径 FileSize BIGINT, UploadUserID INT NOT NULL, CONSTRAINT FK_FlightData_Aircraft FOREIGN KEY (AircraftType, AircraftNo) REFERENCES AircraftInfo(AircraftType, AircraftNo) );参数说明DataType 用 TINYINT 而不是字符串是为了在索引和查询时减少 I/O。FilePath 存相对路径比如\2024\Y20\001\sortie_015\这样磁盘阵列迁移时不用改数据库。UploadUserID 关联用户表用于追溯数据来源。常见做法是在 FlightData 表上建一个组合索引(AircraftType, AircraftNo, FlightDate)试飞数据查询十有八九是按机号加日期范围来的。3.2 用户权限表与软件库信息表的联动设计用户处理权限表控制的是“谁能处理哪架飞机的数据”这个粒度在试飞院很关键——不同型号的数据处理人员往往有严格的隔离要求。权限表不直接存用户 ID 和机号的笛卡尔积而是用角色做中间层减少数据量。-- 用户表 CREATE TABLE UserInfo ( UserID INT IDENTITY(1,1) PRIMARY KEY, UserName NVARCHAR(50) NOT NULL UNIQUE, PasswordHash NVARCHAR(128) NOT NULL, -- SHA1 加盐哈希 RoleID INT NOT NULL, -- 1:管理员 2:数据处理员 3:只读用户 IsActive BIT DEFAULT 1 ); -- 用户处理权限表按角色机型授权 CREATE TABLE UserPermission ( PermissionID INT IDENTITY(1,1) PRIMARY KEY, RoleID INT NOT NULL, AircraftType CHAR(4) NOT NULL, CanUpload BIT DEFAULT 0, CanDownload BIT DEFAULT 1, CanDelete BIT DEFAULT 0, CONSTRAINT FK_Permission_Role FOREIGN KEY (RoleID) REFERENCES UserInfo(RoleID) );逻辑说明RoleID 在 UserInfo 里是单个值在 UserPermission 里可以有多条记录实现“一个角色对多个机型有不同权限”。CanUpload、CanDownload、CanDelete 三个位控制具体操作。软件库信息表则存上传的算法控件和处理软件字段包括软件名称、版本、适用机型、上传用户、文件路径。这两张表通过 RoleID 和 AircraftType 联动客户端登录后先查权限表再决定界面上哪些按钮可点。3.3 上传下载信息表与 CA 提示信息表的审计用途上传下载信息表是审计的核心每次文件操作都要留痕。CA 提示信息表用于在网用户之间的广播或点对点消息比如“Y20 第 15 架次数据已上传请处理人员注意查收”。这两张表在试飞任务密集时写入频率很高需要注意索引和分区。-- 上传下载信息表按月分区存储 CREATE TABLE UploadDownloadLog ( LogID BIGINT IDENTITY(1,1) PRIMARY KEY, UserID INT NOT NULL, DataID INT, -- 关联 FlightData可为空软件上传时为空 OperationType TINYINT NOT NULL, -- 1:上传 2:下载 3:删除 OperationTime DATETIME DEFAULT GETDATE(), ClientIP VARCHAR(15), Remark NVARCHAR(200) ); -- 按操作时间建索引审计查询通常按时间范围 CREATE NONCLUSTERED INDEX IX_UploadDownload_Time ON UploadDownloadLog(OperationTime DESC) INCLUDE (UserID, OperationType);参数说明ClientIP 存客户端 IP用于追溯操作来源。Remark 字段留给用户填备注比如“补传第 3 段 PCM 数据”。索引用了 DESC 排序因为审计查询通常看最近的操作。CA 提示信息表结构类似多了 TargetUserID 字段区分广播和点对点。常见做法是给这两张表设一个定期归档作业比如每月 1 号把 3 个月前的记录移到历史表避免主表过大影响写入性能。4. 避坑与排查DCOM 配置、权限继承和大文件上传的五个血泪教训4.1 坑一DCOM 跨网段调用报“RPC 服务器不可用”现象客户端和服务器在同一网段时正常跨到另一个 VLAN 后连接超时事件查看器里报 RPC 错误。原因DCOM 默认使用动态端口范围跨网段时防火墙只开了 135 端口后续的动态端口被拦了。解决在应用服务器上把 DCOM 的端口限制为固定值。打开 dcomcnfg找到 FTDPMSSvr 的属性在“终结点”里添加一个固定端口比如 50001然后在防火墙里放行 135 和 50001。客户端不需要改配置DCOM 会自动协商。4.2 坑二MTS 事务超时导致大文件上传回滚现象上传超过 2GB 的 PCM 文件时数据库记录写入成功但文件没传完MTS 报事务超时。原因MTS 默认事务超时是 60 秒大文件传输时间远超这个值。解决在 MTS 包的属性里把事务超时改成 0无限等待或者在代码里把文件传输和数据库写入拆成两个阶段——先传文件到临时目录传完后在一个短事务里做文件移动和记录插入。我一般用后者因为无限等待会把应用服务器的线程占死。4.3 坑三用户权限表更新后客户端不生效现象管理员在数据库里改了某个角色的下载权限但客户端用户重新登录后还是能下载。原因客户端在登录时把权限查出来缓存在本地内存后续操作不再查库。解决在中间层加一个权限版本号每次权限表更新时版本号加一。客户端每次操作前对比本地版本号和服务器版本号不一致就重新拉取权限。这个改动很小但能避免很多“我明明改了权限怎么还能用”的扯皮。4.4 坑四磁盘阵列路径变更导致所有文件链接失效现象磁盘阵列扩容后挂载点从D:\Data变成E:\Data数据库里存的绝对路径全部失效。原因FlightData 表的 FilePath 字段存了绝对路径。解决改成存相对路径客户端拼接时用一个配置文件里的根路径。如果已经存了绝对路径写一个批量更新脚本把D:\Data替换成E:\Data。从那以后我每次设计文件存储表都强制用相对路径这个后悔药吃一次就够了。4.5 坑五SQL Server 2005 连接池被客户端耗尽现象同时在线客户端超过 50 个后新客户端连接报“超时时间已到但是尚未从池中获取连接”。原因客户端直连数据库每个客户端开多个连接SQL Server 默认最大连接数不够用。解决强制所有客户端走中间层的连接池中间层配置最大连接数为 100客户端数量再多也只消耗中间层的连接。另外检查客户端代码里有没有忘记关闭 TClientDataSet 的情况这种泄漏在 Delphi 里很常见。5. 进阶技巧用视图和存储过程把数据处理效率再提一档5.1 用分区视图按机型拆分飞行数据查询试飞数据积累到一定量后FlightData 表会变得很大按机型查询时全表扫描很慢。一个实用的技巧是按机型建分区视图把不同机型的数据物理上分到不同的表里逻辑上用视图合并。-- 为 Y20 和 J20 分别建表结构同 FlightData CREATE TABLE FlightData_Y20 (...); CREATE TABLE FlightData_J20 (...); -- 建分区视图客户端查询时不用改 SQL CREATE VIEW v_FlightData AS SELECT * FROM FlightData_Y20 UNION ALL SELECT * FROM FlightData_J20; -- 查询 Y20 的数据时SQL Server 会自动只扫 FlightData_Y20 SELECT * FROM v_FlightData WHERE AircraftType Y20;逻辑说明分区视图的关键是每个子表上要有 CHECK 约束比如CHECK (AircraftType Y20)这样 SQL Server 才能做分区消除。参数上注意 UNION ALL 不要写成 UNION后者会去重性能差很多。这个技巧在试飞院这种机型固定的场景下特别好用新机型来了就加一张表视图改一下就行。5.2 用存储过程封装上传事务减少网络往返客户端上传文件时如果分多步调用中间层先插记录、再传文件、再更新状态网络往返次数多失败概率也大。把整个流程封装成一个存储过程在数据库端一次调用完成。CREATE PROCEDURE sp_UploadFlightData AircraftType CHAR(4), AircraftNo CHAR(6), FlightDate DATE, SortieNo INT, DataType TINYINT, FilePath NVARCHAR(500), FileSize BIGINT, UserID INT, NewDataID INT OUTPUT AS BEGIN BEGIN TRANSACTION; BEGIN TRY INSERT INTO FlightData (AircraftType, AircraftNo, FlightDate, SortieNo, DataType, FilePath, FileSize, UploadUserID) VALUES (AircraftType, AircraftNo, FlightDate, SortieNo, DataType, FilePath, FileSize, UserID); SET NewDataID SCOPE_IDENTITY(); INSERT INTO UploadDownloadLog (UserID, DataID, OperationType, ClientIP) VALUES (UserID, NewDataID, 1, CONVERT(VARCHAR(15), CONNECTIONPROPERTY(client_net_address))); COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW; END CATCH END;参数说明NewDataID 是输出参数返回新插入的 DataID客户端拿到后可以立即用于后续操作。CONNECTIONPROPERTY 函数在 SQL Server 2005 里可能不支持如果报错就改成从中间层传客户端 IP 进来。存储过程的好处是把事务边界放在数据库端中间层只负责调用减少了 DCOM 往返次数。我一般会在中间层加一个重试机制存储过程调用失败时自动重试两次间隔 500 毫秒能解决大部分网络抖动导致的偶发失败。从那以后我每次设计数据管理系统都强制把文件路径存相对值、把事务封装在存储过程里、把权限校验放在中间层这三条已经成了肌肉记忆。希望帮到你。本文还有配套的精品资源点击获取
返回列表