using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using PCL.Core.IO.Net; namespace PCL.Core.Link; public class BroadcastLocal(string description, int localPort) : IDisposable { private Socket? _broadcastSocket; private CancellationTokenSource? _cts; private bool _isRunning; public void Start() { if (_isRunning) return; _cts = new CancellationTokenSource(); _isRunning = true; // 启动 UDP 广播任务 _ = Task.Run(() => _RunUdpBroadcastAsync(_cts.Token), _cts.Token); Console.WriteLine($"开始向本地 Minecraft 客户端广播,端口: {localPort}"); } public void Stop() { if (!_isRunning) return; _cts?.Cancel(); _isRunning = false; _broadcastSocket?.SafeClose(); Console.WriteLine("停止向本地 Minecraft 客户端广播"); } private async Task _RunUdpBroadcastAsync(CancellationToken cancellationToken) { try { _broadcastSocket = new Socket(SocketType.Dgram, ProtocolType.Udp) { DualMode = true }; var buffer = Encoding.UTF8.GetBytes($"[MOTD]{description}[/MOTD][AD]{localPort}[/AD]"); // 向本地地址发送,而不是广播地址 var localEndpoint = new IPEndPoint(IPAddress.Loopback, 4445); while (!cancellationToken.IsCancellationRequested) { try { await _broadcastSocket.SendToAsync(new ArraySegment(buffer), SocketFlags.None, localEndpoint); await Task.Delay(1500, cancellationToken); } catch (OperationCanceledException) { break; } catch (Exception ex) { Console.WriteLine($"UDP 本地广播错误: {ex.Message}"); await Task.Delay(5000, cancellationToken); // 出错后等待 5 秒再重试 } } } catch (Exception ex) { Console.WriteLine($"UDP 本地广播任务发生错误: {ex.Message}"); } } public void Dispose() { Stop(); _cts?.Dispose(); _broadcastSocket.SafeClose(); GC.SuppressFinalize(this); } }