/// <summary> /// 发送服务器列表Ping请求 /// </summary> /// <param name="hostname">主机名</param> /// <param name="port">端口</param> /// <returns></returns> public ServerListPingResult ServerListPing(string hostname, ushort port) { if (State != MinecraftClientState.InTitle) { throw new InvalidOperationException($"invalid client state {State}, it should be {MinecraftClientState.InTitle}."); } const int timeout = 10000; var timedOut = false; var handshaked = false; _logger.Info($"Pinging {hostname}, {port}"); var result = new ServerListPingResult { Delay = -1 }; DateTime time1; TcpClient client = null; ProtocolAdapter adapter = null; try { client = new TcpClient(); client.Connect(hostname, port); adapter = new ProtocolAdapter(client.GetStream(), PacketBoundTo.Server); adapter.Start(); _ = Task.Run(async() => // timeout { await Task.Delay(timeout); if (adapter.State != ProtocolState.Closed) { timedOut = true; client.Close(); _logger.Warn($"{hostname}:{port} timed out"); } }); adapter.WritePacket(new HandshakePacket //handshake { NextState = ProtocolState.Status, ProtocolVersion = _protocolVersion, ServerAddress = hostname, ServerPort = port }); adapter.WritePacket(new StatusRequestPacket()); var statusResponsePacket = (StatusResponsePacket)adapter.ReadPacket(); handshaked = true; result.LoadContent(statusResponsePacket.Content); time1 = DateTime.Now; adapter.WritePacket(new StatusPingPacket { Payload = time1.ToUnixTimeStamp() }); if ((StatusPongPacket)adapter.ReadPacket() != null) { result.Delay = (int)(DateTime.Now - time1).TotalMinutes; } adapter.Close(); } catch { if (!handshaked) { throw; } } finally { adapter?.Dispose(); client?.Dispose(); } if (timedOut) { _logger.Warn("Pinging timeout"); } return(result); }