139 lines
4.3 KiB
C#
139 lines
4.3 KiB
C#
using PSO2SERVER.Models;
|
|
using PSO2SERVER.Protocol.Packets;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace PSO2SERVER
|
|
{
|
|
public enum QueryMode
|
|
{
|
|
ShipList,/*12100 - 12900*/
|
|
AuthList
|
|
}
|
|
|
|
public class QueryServer
|
|
{
|
|
public static List<Task> RunningServers = new List<Task>();
|
|
|
|
private readonly QueryMode _mode;
|
|
private readonly int _port;
|
|
|
|
public QueryServer(QueryMode mode, string desc, int port)
|
|
{
|
|
_mode = mode;
|
|
_port = port;
|
|
|
|
var queryTask = Task.Run(() => RunAsync());
|
|
RunningServers.Add(queryTask);
|
|
Logger.WriteInternal("[监听] 监听" + desc + "端口 " + port);
|
|
}
|
|
|
|
private bool IsPortInUse(int port)
|
|
{
|
|
try
|
|
{
|
|
// 创建一个 TcpListener 实例
|
|
TcpListener listener = new TcpListener(IPAddress.Any, port);
|
|
|
|
// 尝试启动监听
|
|
listener.Start();
|
|
listener.Stop();
|
|
|
|
return false; // 如果没有异常,说明端口没有被占用
|
|
}
|
|
catch (SocketException)
|
|
{
|
|
return true; // 捕获异常,说明端口已被占用
|
|
}
|
|
}
|
|
|
|
private async Task RunAsync()
|
|
{
|
|
Func<Socket, Task> connectionHandler;
|
|
switch (_mode)
|
|
{
|
|
case QueryMode.AuthList:
|
|
connectionHandler = DoBlockBalanceAsync;
|
|
break;
|
|
case QueryMode.ShipList:
|
|
connectionHandler = DoShipListAsync;
|
|
break;
|
|
default:
|
|
connectionHandler = DoShipListAsync;
|
|
break;
|
|
}
|
|
|
|
var serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
|
|
{
|
|
Blocking = true
|
|
};
|
|
|
|
if (IsPortInUse(_port))
|
|
{
|
|
Logger.WriteError($"端口 {_port} 已被占用.");
|
|
}
|
|
|
|
var ep = new IPEndPoint(IPAddress.Any, _port);
|
|
serverSocket.Bind(ep); // TODO: Custom bind address.
|
|
serverSocket.Listen(5);
|
|
|
|
while (true)
|
|
{
|
|
var newConnection = await Task.Factory.FromAsync(serverSocket.BeginAccept, serverSocket.EndAccept, null);
|
|
_ = connectionHandler(newConnection); // Fire-and-forget pattern for handling connections
|
|
}
|
|
}
|
|
|
|
public ShipStatus CheckShipStatus(int port)
|
|
{
|
|
//TODO 还有其他状态要判断
|
|
if (PortChecker.IsPortListening(port))
|
|
{
|
|
return ShipStatus.Online;
|
|
}
|
|
|
|
return ShipStatus.Offline;
|
|
}
|
|
|
|
private async Task DoShipListAsync(Socket socket)
|
|
{
|
|
var entries = new List<ShipEntry>();
|
|
|
|
for (var i = 1; i <= 10; i++)
|
|
{
|
|
var entry = new ShipEntry
|
|
{
|
|
order = (ushort)i,
|
|
number = (uint)i,
|
|
status = CheckShipStatus(ServerApp.ServerShipProt + (100 * (i - 1))), // Maybe move to Config?
|
|
name = String.Format("Ship{0:0#}", i),
|
|
ip = ServerApp.BindAddress.GetAddressBytes()
|
|
};
|
|
entries.Add(entry);
|
|
}
|
|
|
|
var shiplistpacket = new ShipListPacket(entries, (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds, 1).GetPacketBytes();
|
|
|
|
await Task.Factory.FromAsync(
|
|
(cb, state) => socket.BeginSend(shiplistpacket, 0, shiplistpacket.Length, SocketFlags.None, cb, state),
|
|
socket.EndSend,
|
|
null);
|
|
socket.Close();
|
|
}
|
|
|
|
private async Task DoBlockBalanceAsync(Socket socket)
|
|
{
|
|
var balancepacket = new BlockBalancePacket(ServerApp.ServerBlockBalanceName, ServerApp.ServerBlockBalanceProt).GetPacketBytes();
|
|
|
|
await Task.Factory.FromAsync(
|
|
(cb, state) => socket.BeginSend(balancepacket, 0, balancepacket.Length, SocketFlags.None, cb, state),
|
|
socket.EndSend,
|
|
null);
|
|
socket.Close();
|
|
}
|
|
}
|
|
}
|