引言
modbus tcp通讯Java的方案之前已经讲解过一种,modbus4j实现Java语言的modbus tcp协议通讯。从上一个方案中我们不难发现modbus4j的通讯实现方式是同步的。实际应用中可能会读取大量的数据。同步处理对于应用的响应还是不太友好的。本博客主要讲解另外一种Java语言的modbux tcp通讯方案。那就是modbus-master-tcp。一.创建一个demo项目
创建一个简单的maven项目,项目结构图如下:
二.pom.xml maven依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.leftso.demo.modbus</groupId>
<artifactId>demo-modbus-master-slave</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>com.digitalpetri.modbus</groupId>
<artifactId>modbus-master-tcp</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
pom.xml注意,需要将java的编译版本指定到1.8.因为只有1.8以后才支持lambda表达式。
配置完成后,我们观察引入的依赖包:
观察可以发现,modbus-master-tcp项目的底层是基于netty框架开发。天然的支持异步处理。在性能方面有很好的提升。
三.编写modbus tcp读取案例
package com.leftso.demo.modbus;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import com.digitalpetri.modbus.codec.Modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import com.digitalpetri.modbus.requests.ReadCoilsRequest;
import com.digitalpetri.modbus.requests.ReadDiscreteInputsRequest;
import com.digitalpetri.modbus.requests.ReadHoldingRegistersRequest;
import com.digitalpetri.modbus.requests.ReadInputRegistersRequest;
import com.digitalpetri.modbus.responses.ReadCoilsResponse;
import com.digitalpetri.modbus.responses.ReadDiscreteInputsResponse;
import com.digitalpetri.modbus.responses.ReadHoldingRegistersResponse;
import com.digitalpetri.modbus.responses.ReadInputRegistersResponse;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;
/***
* modbus TCP协议Java通讯读取例子
*
* @author xqlee
*
*/
public class SimpleMasterExample {
static ModbusTcpMaster master;
/**
* 获取TCP协议的Master
*
* @return
*/
public static void initModbusTcpMaster() {
if (master == null) {
// 创建配置
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder("localhost").setPort(502).build();
master = new ModbusTcpMaster(config);
}
}
/***
* 释放资源
*/
public static void release() {
if (master != null) {
master.disconnect();
}
Modbus.releaseSharedResources();
}
/**
* 读取HoldingRegister数据
*
* @param address
* 寄存器地址
* @param quantity
* 寄存器数量
* @param unitId
* id
* @return 读取结果
* @throws InterruptedException
* 异常
* @throws ExecutionException
* 异常
*/
public static Number readHoldingRegisters(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Number result = null;
CompletableFuture<ReadHoldingRegistersResponse> future = master
.sendRequest(new ReadHoldingRegistersRequest(address, quantity), unitId);
ReadHoldingRegistersResponse readHoldingRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (readHoldingRegistersResponse != null) {
ByteBuf buf = readHoldingRegistersResponse.getRegisters();
result = buf.readFloat();
ReferenceCountUtil.release(readHoldingRegistersResponse);
}
return result;
}
/**
* 读取InputRegisters模拟量数据
*
* @param address
* 寄存器开始地址
* @param quantity
* 数量
* @param unitId
* ID
* @return 读取值
* @throws InterruptedException
* 异常
* @throws ExecutionException
* 异常
*/
public static Number readInputRegisters(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Number result = null;
CompletableFuture<ReadInputRegistersResponse> future = master
.sendRequest(new ReadInputRegistersRequest(address, quantity), unitId);
ReadInputRegistersResponse readInputRegistersResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (readInputRegistersResponse != null) {
ByteBuf buf = readInputRegistersResponse.getRegisters();
result = buf.readFloat();
ReferenceCountUtil.release(readInputRegistersResponse);
}
return result;
}
/**
* 读取Coils开关量
*
* @param address
* 寄存器开始地址
* @param quantity
* 数量
* @param unitId
* ID
* @return 读取值
* @throws InterruptedException
* 异常
* @throws ExecutionException
* 异常
*/
public static Boolean readCoils(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Boolean result = null;
CompletableFuture<ReadCoilsResponse> future = master.sendRequest(new ReadCoilsRequest(address, quantity),
unitId);
ReadCoilsResponse readCoilsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (readCoilsResponse != null) {
ByteBuf buf = readCoilsResponse.getCoilStatus();
result = buf.readBoolean();
ReferenceCountUtil.release(readCoilsResponse);
}
return result;
}
/**
* 读取readDiscreteInputs开关量
*
* @param address
* 寄存器开始地址
* @param quantity
* 数量
* @param unitId
* ID
* @return 读取值
* @throws InterruptedException
* 异常
* @throws ExecutionException
* 异常
*/
public static Boolean readDiscreteInputs(int address, int quantity, int unitId)
throws InterruptedException, ExecutionException {
Boolean result = null;
CompletableFuture<ReadDiscreteInputsResponse> future = master
.sendRequest(new ReadDiscreteInputsRequest(address, quantity), unitId);
ReadDiscreteInputsResponse discreteInputsResponse = future.get();// 工具类做的同步返回.实际使用推荐结合业务进行异步处理
if (discreteInputsResponse != null) {
ByteBuf buf = discreteInputsResponse.getInputStatus();
result = buf.readBoolean();
ReferenceCountUtil.release(discreteInputsResponse);
}
return result;
}
public static void main(String[] args) {
try {
// 初始化资源
initModbusTcpMaster();
// 执行操作
// 读取模拟量
System.out.println(readHoldingRegisters(0, 4, 1));
System.out.println(readInputRegisters(0, 4, 1));
// 读取开关量
System.out.println(readCoils(0, 1, 1));
System.out.println(readDiscreteInputs(0, 1, 1));
System.out.println(readDiscreteInputs(2, 1, 1));
// 释放资源
release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
上面的代码中模拟量的读取需要注意,根据实际类型来读取相应的类型,例子中读取的double类型数据
四.运行上面的案例演示modbus tcp数据读取
首先打开软件Modbus Slave(没有的可以百度下载)。启动连接:连接完成后,创建四个文档如下图所示:
好了,现在运行我们刚才编写的Java demo程序,SimpleMasterExample:
通过执行结果可以看到与Modbus Slave软件中的文档数据一致。
modbus tcp项目源码下载:demo-modbus-master-slave.zip (访问密码:9987)
版权申明:本文为博主原创文章,未经博主允许不得转载。
https://www.leftso.com/blog/310.html
时效提示:本文最后更新于【 2021-10-08 09:20:00 】,某些文章具有时效性,若有错误或已失效,请在下方留言。
时效提示:本文最后更新于【 2021-10-08 09:20:00 】,某些文章具有时效性,若有错误或已失效,请在下方留言。
评论区域
评论功能已关闭. 提示:评论功能虽已关闭,关闭之前的评论仍然会展示。
f
如何实现批量读取寄存器
y
An illegal reflective access operation has occurred
WARNING: Illegal reflective access by io.netty.util.internal.PlatformDependent0
WARNING: Illegal reflective access by io.netty.util.internal.PlatformDependent0
暗
断开重连后,再次查询会报以下错误:
WARN 41836 --- [ scheduling-1] io.netty.channel.AbstractChannel : Force-closing a channel whose registration task was not accepted by an event loop: [id: 0x40ad37a9]
java.util.concurrent.RejectedExecutionException: event executor terminated
at io.netty.util.concurrent.SingleThreadEventExecutor.reject(SingleThreadEventExecutor.java:845)
at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:328)
at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:321)
WARN 41836 --- [ scheduling-1] io.netty.channel.AbstractChannel : Force-closing a channel whose registration task was not accepted by an event loop: [id: 0x40ad37a9]
java.util.concurrent.RejectedExecutionException: event executor terminated
at io.netty.util.concurrent.SingleThreadEventExecutor.reject(SingleThreadEventExecutor.java:845)
at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:328)
at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:321)
l
由于最近项目未使用,没做深入研究了.建议查看下官方文档,传送门: https://github.com/infiniteautomation/modbus4j
求
为啥我照着第一个运行结果是 65536啊
l
以前数据监测需要读取modbus数据tcp方式项目用过,最近没研究了,可以去https://github.com/infiniteautomation/modbus4j 看看这个项目有没有最新的内容,modbus4j我之前也试过可以获取数据。

路
modbus 在Java得领域中使用还是太少了,翻遍了百度谷歌相关文章少得可怜。楼主讲的这个开源项目也是在孵化阶段。不过作为基本得modbus tcp通讯使用还算可以,至于高频使用还得斟酌。

l
一篇不错的Java 入门 modbus tcp通信文章

l
jar包导不进来,怎么解决
l
maven是用的那个仓库?阿里的还是中央仓库?
