A modern, high-performance .NET library for Modbus TCP and RTU communication. Provides a unified API for reading/writing coils, discrete inputs, holding registers, and input registers with built-in connection pooling, DI integration, and full async support.
Protocols: Modbus TCP (via Ethernet) · Modbus RTU (via Serial Port)
Target Framework: .NET 8.0+ · Language: C# 13 · License: MIT
communication.modbus/
├── Core/ # 核心抽象与领域模型
│ ├── IModbus.cs # 统一通信接口(TCP/RTU)
│ ├── ModbusRequest.cs # 请求数据载体
│ ├── ModbusResult.cs # 泛型操作结果(IsSuccess / ErrorMessage)
│ ├── ModbusFunctionCode.cs # 标准功能码枚举 (0x01–0x10)
│ ├── ModbusProtocolType.cs # 协议类型 (TCP / RTU)
│ ├── ModbusException.cs # 统一异常类型(含 ModbusErrorCode)
│ └── ResponseParser.cs # 响应报文解析与校验
├── TCP/ # TCP 传输实现
│ ├── ModbusTCP.cs # Socket + PipeReader 通信引擎
│ └── ModbusTCPConfig.cs # TCP 配置(IP、Port、超时)
├── RTU/ # RTU 传输实现
│ ├── ModbusRTU.cs # SerialPort 通信引擎
│ └── ModbusRTUConfig.cs # RTU 配置(端口、波特率、校验位)
├── Extensions/ # 面向用户的便捷 API
│ ├── ModbusExtensions.cs # 8 个功能码的同步 + 异步扩展方法
│ ├── ByteHelper.cs # 大端序 / 十六进制 byte[] 辅助
│ └── LogExtentions.cs # 结构化日志扩展
├── Factory/ # 多实例管理与 DI
│ ├── IModbusFactory.cs # 工厂接口(含 IDisposable/IAsyncDisposable)
│ └── ModbusFactory.cs # 工厂实现(ConcurrentDictionary 缓存池)
├── Utils/ # 底层工具
│ ├── ModbusHelper.cs # 帧构建、解析、校验
│ └── Crc16Helper.cs # CRC-16 计算与验证
├── DependencyInjection/ # DI 扩展
│ └── ModbusServiceCollectionExtensions.cs # AddModbusFactory() 注册方法
└── Communication.ModBus.csproj # 项目文件
| 包名 | 最低版本 | 用途 |
|---|---|---|
Microsoft.Extensions.DependencyInjection.Abstractions |
6.0.0 | DI 容器接口(IServiceCollection) |
Microsoft.Extensions.Logging.Abstractions |
6.0.0 | 结构化日志接口(ILogger<T>) |
System.IO.Pipelines |
6.0.0 | TCP 高性能零拷贝 I/O(PipeReader) |
System.IO.Ports |
6.0.0 | RTU 串口通信(SerialPort) |
测试项目依赖:
xUnit、Moq、Microsoft.Extensions.DependencyInjection
# NuGet(发布后)
dotnet add package Communication.Modbus
# 或本地引用
dotnet add reference ../communication.modbus/Communication.ModBus.csprojusing Communication.Modbus.Core;
using Communication.Modbus.Extensions;
using Communication.Modbus.TCP;
// 创建 TCP 客户端
using var tcp = new ModbusTCP(new ModbusTCPConfig
{
Address = "192.168.1.100",
Port = 502
});
tcp.Connect();
// 同步读取线圈 0–4
var coils = tcp.ReadCoils(slaveId: 1, start: 0, length: 5);
if (coils.IsSuccess)
Console.WriteLine($"Coils: {string.Join(", ", coils.Data!)}");
else
Console.WriteLine($"Error: {coils.ErrorMessage}");
tcp.Disconnect();using var rtu = new ModbusRTU(new ModbusRTUConfig
{
PortName = "COM3",
BaudRate = 9600,
Parity = Parity.None,
DataBits = 8,
StopBits = StopBits.One
});
rtu.Connect();
// 异步读取 3 个保持寄存器,起始地址 0
var result = await rtu.ReadHoldingRegistersAsync(slaveId: 1, start: 0, length: 3);
Console.WriteLine(result.IsSuccess
? $"Registers: {string.Join(", ", result.Data!)}"
: $"Error: {result.ErrorMessage}");// Program.cs
using Communication.Modbus.DependencyInjection;
using Communication.Modbus.Factory;
// 1) Get or set Container
var container = new ServiceCollection();
// 1.1) Add logger if you want (Implement ILogger<T> interface, you can add any ILogger<T> obejct.)
// Log.Logger = new LoggerConfiguration()
// .MinimumLevel.Debug()
// .WriteTo.File(
// path: "logs/app-.log",
// outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss}] [{Level:u3}] {Message:1j}{NewLine}",
// rollingInterval: RollingInterval.Day,
// fileSizeLimitBytes: 5 * 1024 * 1024,
// rollOnFileSizeLimit: true,
// retainedFileCountLimit: 31,
// encoding: System.Text.Encoding.UTF8)
// .CreateLogger();
// container.AddLogging( builder =>
// {
// builder.ClearProviders();
// builder.AddSerilog();
// });
// 2) Register factory
container.AddModbusFactory(); // 单例注册
var Provider = container.BuildServiceProvider();
// 3) Get factory from container
var factory = Provider.GetRequiredService<IModbusFactory>();
// 4) Get or add ModbusTCP instance from factory
var tcp = factory.GetOrAdd("test", new ModbusTCPConfig());
// 5) Use ModbusTCP instance
tcp.Connect();
var coils = tcp.ReadCoils(1, 0, 5);
if (coils.IsSuccess)
Console.WriteLine($"Coils: {string.Join(", ", coils.Data!)}");
else
Console.WriteLine($"Error: {coils.ErrorMessage}");
tcp.Disconnect();
// 容器释放时自动 Dispose 所有连接| 功能码 | 同步方法 | 异步方法 | 返回值 |
|---|---|---|---|
| 0x01 Read Coils | ReadCoils(slaveId, start, length) |
ReadCoilsAsync(…, ct) |
ModbusResult<bool[]> |
| 0x02 Read Discrete Inputs | ReadDiscreteInputs(slaveId, start, length) |
ReadDiscreteInputsAsync(…, ct) |
ModbusResult<bool[]> |
| 0x03 Read Holding Registers | ReadHoldingRegisters(slaveId, start, length) |
ReadHoldingRegistersAsync(…, ct) |
ModbusResult<ushort[]> |
| 0x04 Read Input Registers | ReadInputRegisters(slaveId, start, length) |
ReadInputRegistersAsync(…, ct) |
ModbusResult<ushort[]> |
| 0x05 Write Single Coil | WriteSingleCoil(slaveId, start, value) |
WriteSingleCoilAsync(…, ct) |
ModbusResult<byte[]> |
| 0x06 Write Single Register | WriteSingleRegister(slaveId, start, value) |
WriteSingleRegisterAsync(…, ct) |
ModbusResult<byte[]> |
| 0x0F Write Multiple Coils | WriteMultipleCoils(slaveId, start, values) |
WriteMultipleCoilsAsync(…, ct) |
ModbusResult<byte[]> |
| 0x10 Write Multiple Registers | WriteMultipleRegisters(slaveId, start, values) |
WriteMultipleRegistersAsync(…, ct) |
ModbusResult<byte[]> |
同步方法返回
ModbusResult<T>· 异步方法返回ValueTask<ModbusResult<T>>·ct=CancellationToken
| 参数 | 默认值 | 说明 |
|---|---|---|
Address |
"127.0.0.1" |
从站 IP 地址 |
Port |
502 |
TCP 端口(仅支持 1024–65535) |
ConnectTimeout |
2000 ms |
连接超时 |
ReadTimeOut |
2000 ms |
读取超时 |
WriteTimeOut |
2000 ms |
写入超时 |
RetryCount |
3 |
重试次数 |
Reconnect |
false |
是否自动重连 |
| 参数 | 默认值 | 说明 |
|---|---|---|
PortName |
"COM20" |
串口名称 |
BaudRate |
9600 |
波特率 |
Parity |
None |
校验位 (None/Odd/Even/Mark/Space) |
DataBits |
8 |
数据位 (5–8) |
StopBits |
One |
停止位 |
ReadTimeOut |
2000 ms |
读取超时 |
WriteTimeOut |
2000 ms |
写入超时 |
RetryCount |
3 |
重试次数 |
IntervalTime |
30 ms |
帧间等待间隔 |
成功日志片段(ILogger 输出):
info: ModbusFactory[0]
GetOrAdd TCP: key=plc-1, address=192.168.1.100:502
info: ModbusRTU[0]
[Request] Build Execute Tx: {"SlaveId":1,"FunctionCode":"ReadCoils","Start":0,"Length":5}
dbug: ModbusRTU[0]
[TX] [192.168.1.100] --> 00 01 00 00 00 06 01 01 00 00 00 05
dbug: ModbusRTU[0]
[RX] [192.168.1.100] <-- 00 01 00 00 00 04 01 01 01 02 (+15 ms)
- TCP: 内部使用
SemaphoreSlim(1, 1)保证同一连接上一次仅有一个请求在飞行。多个设备请使用ModbusFactory创建多个实例。 - RTU: 串口天然为单线程半双工通信。同样通过
SemaphoreSlim串行化,避免帧冲突。
- Modbus 协议标准为大端序(Big-Endian)。本库内部已处理
ushort与byte[]的转换,用户无需关心字节序。 - 寄存器地址为 0-based(协议层自动转为 1-based)。
ReadTimeOut/WriteTimeOut默认 2000 ms。RTU 额外有IntervalTime用于帧间等待。CheckConnection()基于Socket.Connected判断,非心跳检测,建议在长时间空闲后自行调用Connect()重建连接。
- 输入校验失败抛出
ModbusException,附带标准ModbusErrorCode。 - 通信失败返回
ModbusResult<T>.Fail(errorMessage),不抛异常。 - 从站异常功能码(0x80+)自动识别并填充
errorMessage。
本项目基于 MIT License 开源。
Copyright (c) 2025 Junevy