串口客户端
定义
命名空间:TouchSocket.SerialPorts
程序集:TouchSocket.SerialPorts.dll
一、说明
SerialPortClient是串口系客户端,他直接参与串口的连接、发送、接收、处理、断开等。
二、特点
- 简单易用。
- 内存池支持
- 高性能
- 适配器预处理,一键式解决分包、粘包、对象解析(modbus)等。
- 超简单的同步发送、异步发送、接收等操作。
- 基于委托、插件驱动,让每一步都能执行AOP。
三、产品应用场景
- 所有串口基础使用场景:可跨平台、跨语言使用。
- 自定义协议解析场景:可解析任意数据格式的串口数据报文。
四、可配置项
可配置项
SetMaxPackageSize
数据包最大值(单位:byte),默认1024×1024×10。该值会在适当时间,直接作用DataHandlingAdapter.MaxPackageSize。
SetSerialPortOption
配置串口相关。例如:端口、波特率、数据位、校验位、停止位等。
UseDelaySender
使用延迟发送。众所周知,串口数据报文为了发送效率,会默认启用延迟算法。但是这种设置,只能一定程度的缓解小数据发送效率低的问题,因为它为了保证多线程发送的有序性,在send函数中设置了线程同步,所以说,每调用一次send,实际上都是巨大的性能消耗(此处用iocp发送亦然)。所以,要解决该问题, 最终还是要将小数据,组合成大数据,这样才能更高效率的发送。所以,DelaySender正是负责此类工作的。
使用DelaySender,会一定程度的降低发送的及时性,但是降低程度并不高,简单来说:
如果一个包大于512kb,则不会延迟,直接发送。 如果发送第一个包,与第二个包的时间间隔小于一个线程池线程调度的时间(这个时间极短,一般来说会在10微秒左右),则会将这两个包压缩为一个包发送。
五、支持插件
插件方法 | 功能 |
---|---|
ISerialConnectingPlugin | 在串口连接之前触发。 |
ISerialConnectedPlugin | 同意连接, 且成功启动接收后触发 |
ISerialDisconnectingPlugin | 当客户端主动调用Close时触发 |
ISerialDisconnectedPlugin | 当客户端断开连接后触发 |
ISerialReceivingPlugin | 在收到原始数据时触发,所有的数据均在ByteBlock里面。 |
ISerialReceivedPlugin | 在收到适配器数据时触发,根据适配器类型,数据可能在ByteBlock或者IRequestInfo里面。 |
ISerialSendingPlugin | 当即将发送数据时,调用该方法在适配器之后,接下来即会发送数据。 |
六、创建SerialPortClient
6.1 简单创建
简单的处理逻辑可通过Connecting、Connected、Received等委托直接实现。
代码如下:
var client = new SerialPortClient();
client.Connecting = (client, e) => { return EasyTask.CompletedTask; };//即将连接到端口
client.Connected = (client, e) => { return EasyTask.CompletedTask; };//成功连接到端口
client.Disconnecting = (client, e) => { return EasyTask.CompletedTask; };//即将从端口断开连接。此处仅主动断开才有效。
client.Disconnected = (client, e) => { return EasyTask.CompletedTask; };//从端口断开连接,当连接不成功时不会触发。
client.Received = async (c, e) =>
{
await Console.Out.WriteLineAsync(Encoding.UTF8.GetString(e.ByteBlock,0,e.ByteBlock.Len));
};
client.Setup(new TouchSocket.Core.TouchSocketConfig()
.SetSerialPortOption(new SerialPortOption()
{
BaudRate = 9600,//波特率
DataBits = 8,//数据位
Parity = System.IO.Ports.Parity.None,//校验位
PortName = "COM1",//COM
StopBits = System.IO.Ports.StopBits.One//停止位
}));
client.Connect();
Console.WriteLine("连接成功");
6.2 继承实现
一般继承实现的话,可以从SerialPortClientBase
继承。
class MySerialClient : SerialPortClientBase
{
protected override async Task ReceivedData(ReceivedDataEventArgs e)
{
//此处逻辑单线程处理。
//此处处理数据,功能相当于Received委托。
string mes = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 0, e.ByteBlock.Len);
Console.WriteLine($"已接收到信息:{mes}");
await base.ReceivedData(e);
}
}
var client = new MySerialClient();
client.Setup(new TouchSocket.Core.TouchSocketConfig()
.SetSerialPortOption(new SerialPortOption()
{
BaudRate = 9600,//波特率
DataBits = 8,//数据位
Parity = System.IO.Ports.Parity.None,//校验位
PortName = "COM1",//COM
StopBits = System.IO.Ports.StopBits.One//停止位
}));
client.Connect();//调用连接,当连接不成功时,会抛出异常。
七、接收数据
在串口中,接收数据的方式有很多种。多种方式可以组合使用。
7.1 Received委托处理
当使用SerialPortClient
创建客户端时,内部已经定义好了一个外置委托Received
,可以通过该委托直接接收数据。
var client = new SerialPortClient();
client.Received = (client, e) =>
{
//收到信息
string mes = Encoding.UTF8.GetString(e.ByteBlock.Buffer, 0, e.ByteBlock.Len);
Console.WriteLine($"接收到信息:{mes}");
return EasyTask.CompletedTask;
};