ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

HslCommunication 11.3.2 部署指南:.NET 4.5 环境配置与避坑

HslCommunication 11.3.2 部署指南:.NET 4.5 环境配置与避坑

简介:HslCommunication 11.3.2 版面向 .NET 4.5 环境下的工业通信与上位机开发人员,提供免激活码即可直接引用的通信组件,省去 SetAuthorizationCode 授权配置,运行 24 小时后也不会过期,适合需要快速搭建 PLC 与设备通信、做项目验证或学习通信协议封装的开发者使用。压缩包共 10 个文件,约 5.69MB,以 5 个 dll 类库为主,涵盖通信核心库、控件库、停靠布局与 JSON 序列化依赖,另附 2 个 exe 演示与升级程序、1 个 xml 文档、1 个 backup 备份及 1 个 txt 版本说明,解压后可直接提取 HslCommunication.dll 引用到工程中。目前已有 3866 人学习下载,说明其在工控通信场景中具备一定认可度。借助其中的演示程序与 XML 注释文档,读者可快速了解各通信对象的调用方式与参数含义,对照备份文件与版本说明排查兼容问题,减少自行摸索授权与依赖配置的时间成本。

1. 装 HslCommunication 11.3.2 前,先把 .NET 4.5 这关过了

上周帮一个做产线采集的哥们远程排障,他那边 HslCommunication 死活连不上 PLC,日志里全是超时。折腾半天发现不是库的问题,是他机器上 .NET Framework 版本太新,项目却按 4.5 编译,运行时加载的程序集版本对不上,属于典型的“环境没对齐,代码背锅”。HslCommunication 11.3.2 这个版本明确面向 .NET 4.5,工控现场大量老设备、老系统还卡在这个框架上,装对了就是一把顺手的通信瑞士军刀,装错了就是天天怀疑网线。这篇记录的是我实际部署这套环境的完整过程:版本怎么选、依赖怎么装、配置怎么写、跑不通怎么救,适合刚接手工控通信模块的开发者,也适合需要把老项目迁到新机器上的熟手。

2. 环境准备:.NET 4.5 与 HslCommunication 11.3.2 的版本对齐

2.1 为什么锁定 .NET 4.5 而不是更高版本

HslCommunication 11.3.2 的编译目标是 .NET Framework 4.5,这个选择不是随便定的。工控现场的采集主机、触摸屏一体机、老款工控机,大量还跑着 Windows 7 SP1 或 Windows Server 2008 R2,这些系统原生支持的最高框架版本就是 4.5 到 4.5.2 区间。你如果在开发机上用 4.8 编译,拿到现场机器上大概率报“未能加载文件或程序集”或者“此程序集由比当前加载的运行时更新的运行时生成”。

常见做法是开发机和部署机统一到 4.5,或者至少保证部署机的框架版本不低于编译目标。我一般会在项目文件里显式写死目标框架,而不是依赖 IDE 默认值:

<!-- 项目文件里显式锁定目标框架,避免不同机器编译结果不一致 --> <PropertyGroup> <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <!-- 关闭自动生成绑定重定向,防止运行时偷偷加载高版本程序集 --> <AutoGenerateBindingRedirects>false</AutoGenerateBindingRedirects> </PropertyGroup>

TargetFrameworkVersion决定编译时引用的框架程序集版本,AutoGenerateBindingRedirects关掉是为了让版本冲突在编译期就暴露,而不是运行时才炸。如果你确实需要在 4.8 机器上跑,那就得在 app.config 里手动加 bindingRedirect,把 4.5 的程序集请求重定向到 4.8,但这一步在工控场景里能不做就不做,版本越统一,现场越省心。

2.2 检查与安装 .NET Framework 4.5

先确认目标机器上到底装了什么版本。别信控制面板里的“已安装程序”列表,那个经常显示不全。用注册表查最准:

# 查询本机 .NET Framework 版本,Release 值对应具体版本号 reg query "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v Release

返回值对照:378389 对应 4.5,378675 对应 4.5.1,379893 对应 4.5.2,393295 对应 4.6。如果查出来是 4.5 以下或者压根没有 v4\Full 这个键,就得装。安装包从微软官方下载离线版,别用在线安装器,工控现场经常没外网。装完重启,再查一次注册表确认 Release 值到位。

这里有个血泪经验:Windows 7 上装 4.5 之前必须先装 Windows 7 SP1 补丁包,否则安装程序直接拒绝。另外如果机器上已经装了 4.6 以上,不要降级去装 4.5,降级会破坏系统组件,正确做法是保留高版本,在项目里做绑定重定向。

2.3 获取 HslCommunication 11.3.2 并核对文件

拿到 11.3.2 的发布包后,先别急着引用。解压出来应该能看到针对不同框架的目录,认准 net45 那个文件夹,里面的 DLL 才是给 .NET 4.5 用的。常见做法是建一个统一的 lib 目录放第三方库,而不是散落在各个项目里:

# 建立统一的第三方库目录,按库名和版本分层 mkdir -p libs/HslCommunication/11.3.2/net45 # 把 net45 目录下的 DLL 拷进去,保留原始文件名 cp HslCommunication.dll libs/HslCommunication/11.3.2/net45/

目录结构按“库名/版本/框架”三层组织,好处是以后升级到 11.x 其他版本时,旧版本还在,回滚只需要改引用路径。引用时用相对路径,别用绝对路径,否则换台机器就找不到。在项目里添加引用后,记得把 DLL 的“复制到本地”属性设为 True,不然发布时漏掉这个文件,现场运行直接报找不到程序集。

3. 安装与引用配置:把 DLL 正确挂进项目

3.1 通过 NuGet 还是手动引用

HslCommunication 在 NuGet 上有包,但工控现场经常是内网环境,NuGet 还原走不通。我的习惯是双轨制:开发阶段用 NuGet 方便管理依赖,交付前把包导出成本地 DLL 手动引用。如果你走 NuGet,注意包版本要精确锁定到 11.3.2,别用浮动版本:

<!-- packages.config 里锁定精确版本,避免还原时拉到不兼容的新版 --> <package id="HslCommunication" version="11.3.2" targetFramework="net45" />

targetFramework="net45"这个属性很关键,它告诉 NuGet 还原时选 net45 目录下的程序集。如果写成 net48,还原出来的 DLL 在 4.5 机器上跑不了。手动引用的话,直接在项目引用里指向 libs 目录下的 DLL,同样要确认引用属性里的“特定版本”设为 True,防止运行时加载到 GAC 里的其他版本。

3.2 配置文件的必要项

HslCommunication 本身不需要复杂的配置文件,但工控项目通常要把连接参数外置,方便现场调试时改。我一般会在 app.config 里加一个自定义配置节,把 PLC 的 IP、端口、站号这些放进去:

<configuration> <appSettings> <!-- PLC 连接参数,现场调试时直接改这里,不用重新编译 --> <add key="PlcIp" value="192.168.1.10" /> <add key="PlcPort" value="5000" /> <add key="PlcStation" value="1" /> <!-- 读写超时,单位毫秒,工控网络抖动大,别设太短 --> <add key="ReadTimeout" value="3000" /> </appSettings> </configuration>

PlcPort要按实际协议填,三菱 MC 协议常见 5000 或 6000,西门子 S7 是 102,欧姆龙 FINS 是 9600。ReadTimeout设 3000 毫秒是经验值,现场交换机质量差的时候 1000 毫秒经常误报超时。读取配置用标准 API 就行,别硬编码在代码里,否则每次改 IP 都要重新发版。

3.3 初始化连接的最小代码

引用配好后,写一段最小可运行代码验证库能不能正常加载。以三菱 MC 协议为例:

using HslCommunication.Profinet.Melsec; // 用配置文件里的参数初始化,别在代码里写死 IP var plc = new MelsecMcNet("192.168.1.10", 5000); plc.ConnectTimeOut = 3000; // 连接超时,单位毫秒 plc.ReceiveTimeOut = 3000; // 接收超时,和配置文件保持一致 // 读 D100 开始的 10 个字,返回 OperateResult 对象 var result = plc.ReadInt16("D100", 10); if (result.IsSuccess) { // 成功时 Content 是 short 数组 Console.WriteLine($"读到 {result.Content.Length} 个寄存器"); } else { // 失败时一定要打 Message,这是排障的第一手信息 Console.WriteLine($"读取失败: {result.Message}"); }

ConnectTimeOut和ReceiveTimeOut是两个独立参数,前者管 TCP 握手,后者管数据往返。工控现场经常是握手成功但数据回不来,这时候调大ReceiveTimeOut才有用。ReadInt16返回的OperateResult是 HslCommunication 的统一返回结构,IsSuccess判断成败,Message带错误描述,排障时先看这个字段,比抓包快。

4. 避坑与排查:五个装完就翻车的典型场景

4.1 报“未能加载文件或程序集 HslCommunication”

现象是程序一启动就抛异常,提示找不到指定版本的程序集。原因通常是编译时引用的 DLL 和运行时目录里的 DLL 版本不一致,或者发布时漏拷了 DLL。解决分三步:先确认输出目录里有没有 HslCommunication.dll,再看它的文件版本是不是 11.3.2,最后检查 app.config 里有没有多余的 bindingRedirect 指向别的版本。我一般会在程序启动时加一行日志,把typeof(MelsecMcNet).Assembly.FullName打出来,一眼就能看到实际加载的版本号。

4.2 连接超时但 ping 得通

现象是能 ping 通 PLC 的 IP,但 HslCommunication 连接一直超时。原因多半是端口不对或者协议选错。三菱 MC 协议有 TCP 和 UDP 两种,端口也不一样,用MelsecMcNet连 UDP 端口当然连不上。解决方法是先用 telnet 测端口通不通,再核对 PLC 侧配置的协议类型。另外有些 PLC 开了“仅允许指定 IP 访问”,采集机的 IP 不在白名单里也会表现为超时,这个坑我在现场踩过,查了半天网络,最后是 PLC 侧加白名单解决的。

4.3 读到的数据全是 0 或者乱码

现象是连接成功、读取也返回成功,但数据不对。原因通常是寄存器地址格式写错,或者数据类型不匹配。三菱的 D 寄存器用"D100",西门子的 DB 块要写成"DB1.100",格式不对时库可能不报错但返回默认值。解决方法是先用 PLC 编程软件确认地址和数据类型,再对照 HslCommunication 的地址文档逐个核对。读浮点数用ReadFloat,读 32 位整数用ReadInt32,别用ReadInt16去读浮点,读出来必然是乱的。

4.4 在 4.8 机器上编译,拿到 4.5 机器上运行报错

现象是开发机一切正常,部署到现场机器就报“此程序集由比当前加载的运行时更新的运行时生成”。原因是开发机装了 4.8,编译时虽然目标框架写的是 4.5,但某些引用程序集实际链接到了 4.8 的版本。解决方法是在开发机上用 4.5 的引用程序集编译,或者干脆在虚拟机里装一个纯净的 4.5 环境做编译。我现在的习惯是交付前在一台只装 4.5 的测试机上完整跑一遍,这步不能省。

4.5 多线程并发读写导致连接断开

现象是单线程读写正常,一上多线程就频繁断连。原因是 HslCommunication 的单个连接对象不是线程安全的,多个线程同时调用同一个实例会打乱数据帧。解决方法是每个线程用独立的连接实例,或者加锁串行化访问。我一般用连接池的思路,按线程数预建几个实例,用的时候取、用完还,比全局加锁性能好。如果现场设备不多,最简单的做法就是全局一把锁,虽然丑但稳。

5. 装完怎么验证:三步确认环境真的跑通了

验证这套环境不能只看“能编译”,得从框架、库加载、实际通信三个层面逐级确认。第一步查框架版本,用前面那条注册表命令,确认 Release 值在 378389 及以上,这一步不过后面全是白搭。第二步写一个只加载不通信的测试程序,把typeof(MelsecMcNet).Assembly.FullName打出来,确认加载的是 11.3.2 且来自你的 libs 目录而不是 GAC。第三步才是实际通信测试,建议用下面这段带重试的验证代码:

// 三步验证:加载确认、连接确认、数据确认 var plc = new MelsecMcNet("192.168.1.10", 5000); plc.ConnectTimeOut = 3000; plc.ReceiveTimeOut = 3000; // 第一步:确认程序集版本 Console.WriteLine($"加载版本: {typeof(MelsecMcNet).Assembly.GetName().Version}"); // 第二步:确认连接,带三次重试 bool connected = false; for (int i = 0; i < 3; i++) { var conn = plc.ConnectServer(); if (conn.IsSuccess) { connected = true; break; } Console.WriteLine($"第 {i + 1} 次连接失败: {conn.Message}"); System.Threading.Thread.Sleep(1000); } // 第三步:确认数据,读一个已知值的寄存器做比对 if (connected) { var read = plc.ReadInt16("D100"); Console.WriteLine(read.IsSuccess ? $"D100 当前值: {read.Content}" : $"读取失败: {read.Message}"); }

这段代码的价值在于把失败点分层暴露:版本不对在第一步就现形,网络不通在第二步重试日志里能看到具体错误,数据不对在第三步单独暴露。现场排障最怕的就是“连不上”三个字,分层之后每个环节都有明确输出,省去大量猜测。

验证通过后,我还会做一件事:把整个 libs 目录、app.config 模板、这段验证代码打包成一个部署包,下次换机器直接解压就能复现环境。从那以后我每次交付工控项目,都强制走一遍“查框架、验加载、测通信”这三步,再也没出现过到了现场才发现环境不对的情况。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进