Netty TCP 中间件
包名: Snet.Netty | 类: NettyClientOperate | 基类: MqAbstract<NettyClientOperate, NettyClientData.Basics>
基于 DotNetty 库(Netty 的 .NET 移植版本)提供高性能 TCP 消息传递。支持自定义协议帧解析、编码器/解码器管道和长生命周期持久 TCP 连接。
概述
NettyClientOperate 封装了 DotNetty TCP 通道,并在原始 TCP 之上提供基于消息的发布/订阅语义。它继承自 MqAbstract<NettyClientOperate, NettyClientData.Basics> 并实现了 IMq。
当您需要通过自定义协议处理进行原始 TCP 消息传递时,这是正确的选择 -- 例如,与嵌入式设备、专有 PLC 接口或使用自定义有线协议的遗留系统通信。
安装
dotnet add package Snet.Netty
快速开始
using Snet.Netty.client;
var client = await NettyClientOperate.InstanceAsync(new NettyClientData.Basics
{
IpAddress = "127.0.0.1",
Port = 6688
});
await client.OnAsync();
// 绑定事件再消费
client.OnDataEventAsync += async (sender, e) =>
{
if (e.Status)
Console.WriteLine($"接收到数据: {e.ResultData}");
else
Console.WriteLine($"消费失败: {e.Message}");
};
await client.ConsumeAsync("command");
// 生产消息(可选)
await client.ProduceAsync("command", "STATUS", System.Text.Encoding.UTF8);
// 后续:取消消费
// await client.UnConsumeAsync("command");
// await client.DisposeAsync();
生产与消费
发布与订阅是 IMq 的一等操作——先绑定数据事件,再消费;发布可用字符串或原始字节:
// 1) 先绑定事件再消费——收到的消息在此到达
client.OnDataEventAsync += async (sender, e) =>
{
if (e.Status)
Console.WriteLine($"收到: {e.ResultData}");
else
Console.WriteLine($"消费失败: {e.Message}");
};
// 2) 消费:订阅主题
await client.ConsumeAsync("command");
// 3) 生产:发布字符串消息(UTF-8)
await client.ProduceAsync("command", "STATUS", System.Text.Encoding.UTF8);
// 4) 生产:发布原始字节
var bytes = System.Text.Encoding.UTF8.GetBytes("payload");
await client.ProduceAsync("command", bytes);
// 后续:停止消费
// await client.UnConsumeAsync("command");
ProduceAsync(topic, string, Encoding?)与ProduceAsync(topic, byte[])均可发布;ConsumeAsync/UnConsumeAsync管理主题订阅。事件见:事件。
配置
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
IpAddress |
string | "127.0.0.1" |
目标服务器 IP 地址 |
Port |
int | 6688 | 目标服务器 TCP 端口 |
SslFilePath |
string? | — | SSL 证书文件路径 |
SslFilePassword |
string? | — | SSL 证书文件密码 |
配置 SslFilePath 后客户端会校验服务器证书链与主机名——自签名或主机名不匹配的证书将被拒绝连接。
| TaskNumber | int | 5 | 并发任务数量 |
| ResponseType | enum | Content | 响应类型 |
协议管道
DotNetty 使用通道处理器管道进行协议处理。默认管道为:
LengthFieldPrepender(8)-- 为每个出站帧前置 8 字节长度字段LengthFieldBasedFrameDecoder-- 按 8 字节长度字段将入站字节流分割为消息帧NettyClientHandler-- 将消息分发到应用层
管道中没有字符串编解码器(消息以原始字节交换;长度字段固定为 8 字节),且管道由客户端内部构建——没有可扩展管道的公共 API。
支持的操作
| 操作 | 方法 | 描述 |
|---|---|---|
| 连接 | OnAsync() |
建立到服务器的 TCP 连接 |
| 断开 | OffAsync() |
关闭 TCP 连接 |
| 发送 | ProduceAsync(topic, string, Encoding?) |
通过 TCP 发送字符串消息 |
| 发送 | ProduceAsync(topic, byte[]) |
通过 TCP 发送原始字节 |
| 接收 | ConsumeAsync(topic) |
开始监听主题/通道上的消息 |
| 停止接收 | UnConsumeAsync(topic) |
停止监听主题/通道上的消息 |
事件
| 事件 | 签名 | 描述 |
|---|---|---|
OnDataEvent |
EventHandler<EventDataResult> |
从 TCP 连接收到数据时触发 |
OnDataEventAsync |
EventHandlerAsync<EventDataResult> |
OnDataEvent 的异步变体 |
OnInfoEvent |
EventHandler<EventInfoResult> |
收到连接状态和信息消息时触发 |
OnInfoEventAsync |
EventHandlerAsync<EventInfoResult> |
OnInfoEvent 的异步变体 |
OnLanguageEvent |
EventHandler<EventLanguageResult> |
语言变更时触发 |
OnLanguageEventAsync |
EventHandlerAsync<EventLanguageResult> |
OnLanguageEvent 的异步变体 |
连接异常处理
连接异常时,库会抛出信息事件(含远端 IP:Port 与异常消息),随后关闭通道并置空内部 Channel 引用——不调用 Off(true)、不会自动重连。断线后的清理与重连需由调用方通过 On/Off 生命周期管理;通道关闭期间 GetStatusAsync() 返回「未连接」。示例:
// 事件驱动的重连(由调用方管理)
client.OnInfoEventAsync += async (sender, result) =>
{
if (!result.Status)
{
await Task.Delay(2000);
await client.OnAsync(); // 尝试重连
}
};
