308 lines
11 KiB
C#
308 lines
11 KiB
C#
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);
|
||
}
|
||
}
|
||
} |