资讯详情

HslCommunication实战:用Java/Python远程读写PLC的完整指南

📅 2026/9/16 15:16:10 | 华诺云谱 👁 阅读
HslCommunication实战:用Java/Python远程读写PLC的完整指南
简介这份资源是一套基于HslCommunication实现远程读写PLC的多语言示例代码覆盖C#、Java、Python三种技术栈适合正在做毕设、课程设计或工程实训的开发者参考。示例包含C#控制台服务端与Windows窗体客户端、Java工程及Python脚本可以对照学习不同语言下调用HslCommunication库、建立通信并读写PLC数据的基本流程。资源共27个文件压缩包仅1.54MB以C#源码.cs、配置文件.config、Java依赖包.jar及.csproj工程文件为主同时包含.py与.java示例脚本目录按语言和工程模块划分便于检索。目前已有549人学习下载。需要留意的是代码定位为参考资料而非开箱即用的成品读者需具备一定基础能自行调试报错并根据实际PLC型号修改通信参数。1. 远程读写PLC先从通信链路说起工业现场有个很常见的需求设备在三楼车间数据要进二楼的服务器人在办公室喝着咖啡看产线状况。传统做法是站到触摸屏前抄数稍微现代一点是在工控机上装组态软件但这些都绕不开一个事实——你得先和PLC把话通上。HslCommunication这类通信库解决的就是这个“通上”的问题它把三菱、西门子、欧姆龙、台达、Modbus TCP等一二线PLC的上位机通信协议封装成了统一的读写接口让JAVA、Python这类非工控语言也能像读本地变量一样操作PLC的软元件地址。对IT从业者来说这意味着不再需要懂梯形图也不需要买专用网关只要网线能到PLC就能用熟悉的语言把数据读出来、写进去。这篇文章我会按照自己做过的路径先把通信模型讲清楚再给出JAVA和Python的最小可运行示例最后把远程部署时最容易翻车的网络问题和坑点逐个说透。2. HslCommunication的通信模型与JAVA端最小实现2.1 它做了什么从字节流到软元件地址PLC本身并不认识HTTP或者JSON它只认特定格式的二进制帧。三菱MC协议有Qna-3E、Qna-1E之分西门子S7协议基于COTP和S7-Comm欧姆龙Fins又是另一套包头结构。HslCommunication做得最核心的一件事是把这些帧的组包、校验、超时重发、拆包解包全部封装成统一的方法调用读哪个站、从哪个地址读、读出来是short还是int还是string都是调用方传入参数。常见做法是选JAVA版本作为上位机主服务因为它天然跨平台部署在Linux服务器上很稳。HslCommunication的JAVA版包名是com.github.hslcommunication旧版本在Maven中央仓库可以搜到新版本一般直接引JAR包。我这里用Maven坐标引入依赖dependency groupIdcom.github.hslcommunication/groupId artifactIdhslcommunication/artifactId version1.0.0/version /dependency如果你用的是自己构建的JAR记得把依赖一起引进去因为HslCommunication底层会用到一些commons-logging之类的库。版本不同包路径可能从com.hslcommunication变成com.github.hslcommunication引包报错时先检查这一处。2.2 用JAVA读取三菱PLC的完整代码下面这段是连接三菱Q系列或FX5U、读取D100寄存器并写入M100线圈的最小示例import com.github.hslcommunication.melsec.MelsecTcpNet; public class MitsubishiReadWriteExample { public static void main(String[] args) throws Exception { // 1. 创建三菱MC协议TCP连接对象参数是PLC的IP地址和端口号 MelsecTcpNet plc new MelsecTcpNet(192.168.1.10, 6000); plc.setConnectTimeOut(3000); // 连接超时3秒 plc.setTimeOut(5000); // 读写超时5秒 // 2. 打开连接 try { plc.open(); if (!plc.isOpen()) { System.out.println(连接失败 plc.getErrorCode()); return; } // 3. 读取D100开始的5个int值32位 int[] dValues plc.readInt32(D100, 5); for (int i 0; i dValues.length; i) { System.out.println(D (100 i) dValues[i]); } // 4. 写单个int值到D200 plc.write(D200, 4567); // 5. 置位M100线圈为ON plc.write(M100, true); } finally { plc.close(); } } }逻辑说明MelsecTcpNet构造参数第一个是PLC的IP地址第二个是端口号三菱默认是6000不要随意改成其他值。readInt32读取的是32位整数对应PLC里的DINT或32位D寄存器组合如果你PLC里存的是16位整数要改用readInt16。写线圈时布尔值true对应ONfalse对应OFF。getErrorCode()返回的数字不是HTTP状态码是HslCommunication内部定义的错误编号比如60表示远程设备无响应。2.3 参数怎么调端口、超时和掉线重连JAVA实测中必调的参数有三个。第一个是端口号三菱MC协议一般走6000西门子S7-1200走102Modbus TCP走502。第二个是超时时间connectTimeOut和timeOut都不能设成0否则连接线程会无限阻塞我一般放3到5秒产线网络抖动严重时放到8秒。第三个是重连策略HslCommunication自带内置重连逻辑异地PLC按轮询周期调一次读写方法时如果连接断开下一次调用会自动尝试重新连接。提示不要在每个线程里都new一个连接对象。一台PLC维持一个长连接即可多线程共享同一个实例时HslCommunication内部对读写方法做了锁处理但同一时间只有一个线程能执行读写高并发场景要加队列或者用Task异步提交。3. 用Python远程读写PLC的三种落地方式3.1 JAVA版做服务Python走HTTP这是最稳的组合HslCommunication官方没有纯Python的三菱/西门子通信库Modbus库除外常见的做法是让JAVA上位机把HslCommunication包装一个HTTP接口Python作为业务端通过requests或httpx调用。这个模式在Python自动化脚本、AI数据采样场景中非常实用Python只负责业务逻辑不碰底层协议。下面用Spring Boot风格的Controller片段说明这个桥接层怎么写RestController RequestMapping(/plc) public class PlcController { GetMapping(/read) public MapString, Object read(RequestParam String address, RequestParam int length) { MapString, Object result new HashMap(); try { int[] values plcInstance.readInt32(address, length); result.put(code, 0); result.put(data, values); } catch (Exception e) { result.put(code, -1); result.put(error, e.getMessage()); } return result; } }Python端的调用就是三行代码import requests resp requests.get(http://192.168.1.100:8080/plc/read, params{address: D100, length: 10}, timeout5) data resp.json() if data[code] 0: print(D100~D109:, data[data]) else: print(读取失败:, data[error])逻辑说明HTTP桥接的好处是让Python端完全没有通信依赖你换了PLC品牌也只用改JAVA端。requests.get的timeout字段一定要设否则JAVA服务端线程池被拖垮时Python端会一直挂住。3.2 Python直接连西门子S7系列pyl Beckhoff的替代路线如果你的PLC是西门子S7-200SMART或S7-1200有另一个选择是用python-snap7。这个库不走HslCommunication是专门针对S7协议的Python绑定。import snap7 from snap7.util import get_int, set_int plc snap7.client.Client() plc.connect(192.168.1.10, 0, 1, timeout3) if plc.get_connected(): # 读取DB1.DBW0开始的2个字节解释为int area 0x84 # DB块标识 db_number 1 start_offset 0 size 2 data plc.read_area(area, db_number, start_offset, size) value get_int(data, 0) # 字节序按西门子高位在前 print(DB1.DBW0 , value) # 写入DB1.DBW4为999 new_data bytearray(2) set_int(new_data, 0, 999) plc.write_area(area, db_number, 4, new_data) else: print(连接失败)参数说明plc.connect(ip, rack, slot, timeout)第三个参数slot很关键S7-300/400的CPU一般在槽位2S7-1200/1500是槽位1不同PLC型号这俩参数组合不一样。read_area第一个参数0x84代表DB块如果是输入区则用0x81输出区用0x82M区用0x83。字节序默认是大端西门子风格这和Modbus TCP默认大端一致但和JAVA的HslCommunication默认小端处理有差异两边对同一地址读出来是short还是int时要重点检查字节序。3.3 直接给Python装HslCommunication的Modbus TCP通道很多国产PLC台达、汇川、信捷和部分欧系PLC都支持Modbus TCP这类设备可以直接用Python的pymodbus库读写不经过任何桥接。下面是一个读保持寄存器、写线圈的完整示例from pymodbus.client import ModbusTcpClient client ModbusTcpClient(192.168.1.20, port502, timeout3) if client.connect(): # 读从站1的保持寄存器地址40001映射为0读5个寄存器 rr client.read_holding_registers(address0, count5, slave1) if not rr.isError(): print(寄存器值:, rr.registers) # 写线圈地址0为ON wr client.write_coil(address0, valueTrue, slave1) if not wr.isError(): print(线圈写入成功) client.close()逻辑说明Modbus地址有“零基地址”和“一基地址”的区别HslCommunication里写热词40001表示第一路保持寄存器而pymodbus的address0对应同一路中间减1的偏移是新手最常踩的坑。slave参数在TCP模式下通常忽略但很多网关设备挂着多个从站时要用它区分。4. 远程访问的组网方式VMware、TIA和防火墙的配合4.1 本地跑虚拟机连PLC网络模式怎么选很多人第一次在VMware里装好博途TIA Portal和HslCommunication测试程序后发现虚拟机和PLC物理设备之间ping不通。这个问题的根源在网络连接模式上。VMware有三种模式仅主机模式Host-Only只与宿主机通信NAT模式通过宿主机共享IP出网桥接模式Bridged会直接占用宿主机物理网卡的同网段IP。连接真正的PLC必须选桥接模式并且要卡在正确的物理网卡上。VMware桥接模式的具体配置路径是虚拟机设置 - 网络适配器 - 选择“桥接模式” - 复制物理网络连接状态。如果宿主机有无线网卡和有线网卡两块还需要在“编辑”-“虚拟网络编辑器”里把桥接目标明确指定到连着PLC的那块物理网卡上。PLC一般接在有线网卡Wi-Fi经常搜不到设备信号。4.2 跨网段访问PLC时路由和防火墙要一起看生产网络的PLC IP往往是192.168.0.x或10.0.0.x服务器在另一个网段JAVA程序访问PLC必须经过三层路由。我建议先把连接链路拆成两段来排查服务器同网段的交换机能不能ping通PLC的网关服务器本身能不能ping通PLC的IP。防火墙是最常见的拦路虎。Linux服务器上通常开着firewalld或ufw即使你确认应用层代码没问题单个UDP或TCP端口被屏蔽会让所有超时白白浪费。三菱MC协议需要放行TCP 6000西门子S7需要放行TCP 102Modbus TCP需要放行TCP 502firewall-cmd --permanent --add-port6000/tcp firewall-cmd --permanent --add-port102/tcp firewall-cmd --permanent --add-port502/tcp firewall-cmd --reload如果是Windows服务器在“高级安全Windows防火墙”里添加入站规则时要注意“作用域”选项卡尽量限定远程IP地址为PLC所在的子网不要直接放行所有来源。这里有个容易被忽略的点PLC的CPU模块本身也常带“允许来自远程的PUT/GET通信访问”这类开关尤其是西门子S7-1200默认情况下DB块优化访问开启HslCommunication或snap7直接按绝对地址读写会报“无法访问DB块”需要在博途里关闭DB块的优化块访问属性。4.3 远程PLC报警和端到端连通性验证HslCommunication读不到数据时先不要怀疑代码按照下面三步验证链路。第一步宿主机命令telnet 192.168.1.10 6000能通说明端口开放。第二步下载一个Modbus Poll或Packet Sender做裸通信测试直接看响应帧。第三步检查PLC程序里的通信设置三菱需要开启MC协议西门子需要配置连接机制为“允许来自远程对象的通信访问”。用脚本定时做端到端验证是保证远程读写可靠的手段我常用下面这段Pythonimport subprocess import json result subprocess.run( [curl, -s, -m, 3, http://127.0.0.1:8080/plc/health], capture_outputTrue, textTrue ) if result.returncode 0: data json.loads(result.stdout) if data.get(connected): print(fPLC连接正常, 当前RSSI: {data.get(signal, N/A)}) else: print(PLC连接异常) else: print(HTTP桥接服务不可达)注意这里RSSI字段不是所有PLC都返回仅当你的JAVA封装的健康检查接口里有这个字段才打印。端到端验证的频率不用太高每30秒到1分钟一次就够了频繁的连接断开会占满PLC的通信资源严重时触发PLC报警。日志里出现Link-100一类编号时不是PLC程序故障而是通信模块断线重连的提示排查重点应放在物理链路而不是逻辑代码。5. 一个能落地的技巧读点位分组打包写点位统一提交远程读写的性能瓶颈往往不在通信库而在调用模型。假设你有一个监控页面需要同时显示D100、D200、D300共三组数据分开三次readInt32调用会产生三次网络往返。PLC通信是按“一帧一请求一响应”走的每次调用都要等待响应超时后释放连接资源三次调用就是三倍延迟和三倍失败概率。更好的做法是按块读取。三菱PLC的D区是连续的西门子系统DB块内部也是连续的所以推荐每次都把请求封装成“起始地址长度”的形式一次拉取一大块数据到本地缓存然后由JAVA或Python解析读多组数据时只发起一轮请求// 一次读D100~D199共100个int避免100次网络往返 int[] bigChunk plc.readInt32(D100, 100); // 本地解析需要D105就取bigChunk[5]需要D130就取bigChunk[30]写入也一样能连续写的不要拆开。HslCommunication支持write批量写数组例如一次写入D200到D204五个float值。float[] fiveValues {1.1f, 2.2f, 3.3f, 4.4f, 5.5f}; plc.write(D200, fiveValues);参数说明write的第二个参数传入数组时内部会自动计算寄存器个数不需要额外传长度。注意float在HslCommunication里默认对应32位寄存器如果你的PLC组态用的是16位字存两个float要使用writeFloat并注意起始地址对齐偶数。分块打包的第二个好处是异常定位简单。如果整块读成功你就知道链路是通的问题只在数据内容如果整块读失败日志里记录的起始地址和长度已经足够判断是地址越界还是通信中断不需要对每个点位单独打点排查。最后说一个验证读写正确性的自检方式。临时在PLC程序里加一个计数器位每收到一次写入请求就累加一次然后在JAVA或Python端监听返回值的增量。如果写入次数远大于计数器增量说明你的上位机程序有重复提交逻辑如果写入次数小于计数器增量说明有其它上位机软件在跟你抢同一批地址。这个验证手段在远程读写场景下帮人省过大量排查时间比单看通信库的返回值更接近真相。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。