feat: 添加大数据接收方法,以提高接受速度

This commit is contained in:
2025-07-13 11:40:41 +08:00
parent b913f58f13
commit 32b126b93f
3 changed files with 201 additions and 7 deletions

View File

@@ -380,6 +380,113 @@ public class UDPClientPool
}
/// <summary>
/// 从设备地址读取字节数组数据(支持大数据量分段传输,先发送所有地址包再接收所有数据包)
/// </summary>
/// <param name="endPoint">IP端点IP地址与端口</param>
/// <param name="taskID">任务ID</param>
/// <param name="devAddr">设备地址</param>
/// <param name="dataLength">要读取的数据长度4字节</param>
/// <param name="timeout">超时时间(毫秒)</param>
/// <returns>读取结果,包含接收到的字节数组</returns>
public static async ValueTask<Result<byte[]>> ReadAddr4BytesAsync(
IPEndPoint endPoint, int taskID, UInt32 devAddr, int dataLength, int timeout = 1000)
{
var optsList = new List<SendAddrPackOptions>();
var resultData = new List<byte>();
// Check Msg Bus
if (!MsgBus.IsRunning)
return new(new Exception("Message bus not working!"));
// Prepare options for each segment
var max4BytesPerRead = 0x80; // 512 bytes per read
var rest4Bytes = dataLength % max4BytesPerRead;
var readTimes = (rest4Bytes != 0) ?
(dataLength / max4BytesPerRead + 1) :
(dataLength / max4BytesPerRead);
for (var i = 0; i < readTimes; i++)
{
var isLastSegment = i == readTimes - 1;
var currentSegmentSize = (isLastSegment && rest4Bytes != 0) ? rest4Bytes : max4BytesPerRead;
var opts = new SendAddrPackOptions
{
BurstType = BurstType.FixedBurst,
CommandID = Convert.ToByte(taskID),
IsWrite = false,
BurstLength = (byte)(currentSegmentSize - 1),
Address = devAddr + (uint)(i * max4BytesPerRead)
};
optsList.Add(opts);
}
// Send all address packages first, but keep outstanding < 512
int sentCount = 0;
var startTime = DateTime.Now;
while (sentCount < optsList.Count)
{
// Check how many data packets have been received
var elapsed = DateTime.Now - startTime;
if (elapsed >= TimeSpan.FromMilliseconds(timeout))
break;
var timeleft = timeout - (int)elapsed.TotalMilliseconds;
var found = await MsgBus.UDPServer.GetDataCountAsync(endPoint.Address.ToString(), taskID, timeleft);
int outstanding = sentCount - (found.HasValue ? found.Value : 0);
// If outstanding >= 512, wait for some data to be received
if (outstanding >= 512)
continue;
// Send next address package
var ret = await UDPClientPool.SendAddrPackAsync(endPoint, new SendAddrPackage(optsList[sentCount]));
if (!ret) return new(new Exception($"Send address package failed at segment {sentCount}!"));
sentCount++;
}
// Wait until enough data is received or timeout
startTime = DateTime.Now;
List<UDPData>? udpDatas = null;
while (true)
{
var elapsed = DateTime.Now - startTime;
if (elapsed >= TimeSpan.FromMilliseconds(timeout)) break;
var timeleft = timeout - (int)elapsed.TotalMilliseconds;
var found = await MsgBus.UDPServer.GetDataCountAsync(endPoint.Address.ToString(), taskID, timeleft);
if (found.HasValue && found.Value >= readTimes)
{
var dataArr = await MsgBus.UDPServer.FindDataArrayAsync(endPoint.Address.ToString(), taskID, timeleft);
if (dataArr.HasValue)
{
udpDatas = dataArr.Value;
break;
}
}
}
if (udpDatas is null || udpDatas.Count < readTimes)
return new(new Exception($"Expected {readTimes} UDP data packets but received {udpDatas?.Count ?? 0}"));
// Collect and validate all received data
for (var i = 0; i < udpDatas.Count; i++)
{
var bytes = udpDatas[i].Data;
var expectedLen = ((optsList[i].BurstLength + 1) * 4);
if (bytes.Length != expectedLen)
return new(new Exception($"Expected {expectedLen} bytes but received {bytes.Length} bytes at segment {i}"));
resultData.AddRange(bytes);
}
// Validate total data length
if (resultData.Count != dataLength * 4)
return new(new Exception($"Expected total {dataLength * 4} bytes but received {resultData.Count} bytes"));
return resultData.ToArray();
}
/// <summary>
/// 向设备地址写入32位数据
/// </summary>