BDU/DeviceCommand/Base/Udp.cs

308 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Common.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using static Common.Attributes.ATSCommandAttribute;
namespace DeviceCommand.Base
{
[ATSCommand]
[DeviceCategory("全部驱动")] // 添加分类属性
public class Udp
{
public string RemoteIpAddress { get; set; } = "127.0.0.1";
public int RemotePort { get; set; } = 8080;
public int LocalPort { get; set; } = 0; // 0 表示系统自动分配
public int SendTimeout { get; set; } = 3000;
public int ReceiveTimeout { get; set; } = 3000;
public UdpClient UdpClient { get; set; } = new UdpClient();
/// <summary>
/// 创建UDP设备对象
/// </summary>
/// <param name="ipAddress">IP地址</param>
/// <param name="port">端口号</param>
/// <param name="sendTimeout">发送超时时间</param>
/// <param name="receiveTimeout">接收超时时间</param>
public Udp CreateDevice(string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
{
RemoteIpAddress = ipAddress;
RemotePort = port;
SendTimeout = sendTimeout;
ReceiveTimeout = receiveTimeout;
if (LocalPort > 0)
{
UdpClient = new UdpClient(LocalPort);
}
else
{
UdpClient = new UdpClient();
}
UdpClient.Client.SendTimeout = SendTimeout;
UdpClient.Client.ReceiveTimeout = ReceiveTimeout;
return this;
}
/// <summary>
/// 修改UDP连接参数
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="ipAddress">IP地址</param>
/// <param name="port">端口号</param>
/// <param name="sendTimeout">发送超时时间</param>
/// <param name="receiveTimeout">接收超时时间</param>
public static void ChangeDeviceConfig(Udp udp, string ipAddress, int port, int sendTimeout = 3000, int receiveTimeout = 3000)
{
udp.RemoteIpAddress = ipAddress;
udp.RemotePort = port;
if (sendTimeout > 0)
{
udp.SendTimeout = sendTimeout;
}
if (receiveTimeout > 0)
{
udp.ReceiveTimeout = receiveTimeout;
}
if (udp.UdpClient != null)
{
udp.UdpClient.Client.SendTimeout = udp.SendTimeout;
udp.UdpClient.Client.ReceiveTimeout = udp.ReceiveTimeout;
}
}
// ————————————————————————
// 功能 78
// ————————————————————————
/// <summary>
/// UDP连接功能78
/// UDP是无连接的此处主要进行初始化和设置默认远程端点
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="ct">取消令牌</param>
/// <returns>连接结果</returns>
public static async Task<bool> ConnectAsync(Udp udp, CancellationToken ct = default)
{
if (udp.UdpClient == null)
{
if (udp.LocalPort > 0)
{
udp.UdpClient = new UdpClient(udp.LocalPort);
}
else
{
udp.UdpClient = new UdpClient();
}
}
udp.UdpClient.Client.SendTimeout = udp.SendTimeout;
udp.UdpClient.Client.ReceiveTimeout = udp.ReceiveTimeout;
var remoteEndpoint = new IPEndPoint(IPAddress.Parse(udp.RemoteIpAddress), udp.RemotePort);
//await udp.UdpClient.ConnectAsync(remoteEndpoint, ct);
return true;
}
/// <summary>
/// 紧急停止功能78
/// </summary>
/// <param name="udp">UDP设备对象</param>
public static void EmergencyStop(Udp udp)
{
Close(udp); // 复用 Close 逻辑
}
// ————————————————————————
// 功能 79
// ————————————————————————
/// <summary>
/// 设备初始化功能79
/// </summary>
/// <param name="udp">UDP设备对象</param>
public static void InitializeDevice(Udp udp)
{
if (udp.UdpClient == null)
{
if (udp.LocalPort > 0)
{
udp.UdpClient = new UdpClient(udp.LocalPort);
}
else
{
udp.UdpClient = new UdpClient();
}
}
udp.UdpClient.Client.SendTimeout = udp.SendTimeout;
udp.UdpClient.Client.ReceiveTimeout = udp.ReceiveTimeout;
}
/// <summary>
/// 断开功能79
/// </summary>
/// <param name="udp">UDP设备对象</param>
public static void Disconnect(Udp udp)
{
Close(udp); // 复用 Close 逻辑
}
/// <summary>
/// 连接功能79
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="ct">取消令牌</param>
/// <returns>连接结果</returns>
public static async Task<bool> Connect(Udp udp, CancellationToken ct = default)
{
// 与 ConnectAsync 功能相同,可以复用
return await ConnectAsync(udp, ct);
}
// ————————————————————————
// 功能 80
// ————————————————————————
/// <summary>
/// 发送字符串功能80
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="str">要发送的字符串</param>
/// <param name="ct">取消令牌</param>
public static async Task SendString(Udp udp, string str, CancellationToken ct = default)
{
await SendAsync(udp, str, ct); // 复用 SendAsync 逻辑
}
/// <summary>
/// 发送字节功能80
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="bytes">要发送的字节数组</param>
/// <param name="ct">取消令牌</param>
public static async Task SendByte(Udp udp, byte[] bytes, CancellationToken ct = default)
{
await SendAsync(udp, bytes, ct); // 复用 SendAsync 逻辑
}
/// <summary>
/// 接收字节功能80
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="ct">取消令牌</param>
/// <returns>接收到的字节数组</returns>
public static async Task<byte[]> ReceiveByte(Udp udp, CancellationToken ct = default)
{
// UDP 接收通常不需要预先分配固定大小的 buffer直接返回整个数据报
if (udp.UdpClient == null) throw new InvalidOperationException("UDP Client 未初始化。");
var timeoutMs = udp.ReceiveTimeout;
if (timeoutMs <= 0)
{
var res = await udp.UdpClient.ReceiveAsync();
return res.Buffer;
}
var readTask = udp.UdpClient.ReceiveAsync();
var timeoutTask = Task.Delay(timeoutMs, ct);
var completedTask = await Task.WhenAny(readTask, timeoutTask);
if (completedTask == timeoutTask)
{
throw new TimeoutException($"UDP通讯异常读取操作在 {timeoutMs} ms内未完成");
}
var result = await readTask;
return result.Buffer;
}
/// <summary>
/// 接收字符串功能80
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="ct">取消令牌</param>
/// <returns>接收到的字符串</returns>
public static async Task<string> ReceiveString(Udp udp, CancellationToken ct = default)
{
var bytes = await ReceiveByte(udp, ct);
return Encoding.UTF8.GetString(bytes);
}
// ————————————————————————
// 内部辅助方法 (与 Tcp 风格一致)
// ————————————————————————
/// <summary>
/// 关闭UDP连接
/// </summary>
/// <param name="udp">UDP设备对象</param>
private static void Close(Udp udp)
{
udp.UdpClient?.Close();
// udp.UdpClient?.Dispose(); // 通常 Close 就足够了
}
/// <summary>
/// 发送字节数组到UDP设备 (内部核心方法)
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="bytes">要发送的字节数组</param>
/// <param name="ct">取消令牌</param>
public static async Task SendAsync(Udp udp, byte[] bytes, CancellationToken ct = default)
{
if (udp.UdpClient == null) throw new InvalidOperationException("UDP Client 未初始化。");
var timeoutMs = udp.SendTimeout;
if (timeoutMs <= 0)
{
await udp.UdpClient.SendAsync(bytes, bytes.Length);
return;
}
var sendTask = udp.UdpClient.SendAsync(bytes, bytes.Length);
var timeoutTask = Task.Delay(timeoutMs, ct);
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
if (completedTask == timeoutTask)
{
throw new TimeoutException($"UDP通讯异常写入操作在 {timeoutMs} ms内未完成");
}
await sendTask;
}
/// <summary>
/// 发送字符串到UDP设备 (内部核心方法)
/// </summary>
/// <param name="udp">UDP设备对象</param>
/// <param name="str">要发送的字符串</param>
/// <param name="ct">取消令牌</param>
private static async Task SendAsync(Udp udp, string str, CancellationToken ct = default)
{
await SendAsync(udp, Encoding.UTF8.GetBytes(str), ct);
}
// ————————————————————————
// 实例方法 (可选,便于链式调用)
// ————————————————————————
/// <summary>
/// 连接UDP设备实例方法
/// </summary>
/// <param name="ct">取消令牌</param>
/// <returns>连接结果</returns>
public async Task<bool> ConnectAsync(CancellationToken ct = default)
{
return await ConnectAsync(this, ct);
}
}
}