using System.Net;
using System.Net.Sockets;
using GServer.Common;
using GServer.Common.Networking.Messages;
namespace GServer.Server;
public class TCPGameServer : IDisposable
{
private readonly TcpListener _tcpListener;
private readonly IPEndPoint _endPoint;
private readonly GameServerOptions _options;
private readonly IMessageHandler _messageHandler;
public TCPGameServer(IPEndPoint endPoint, GameServerOptions options)
{
_endPoint = endPoint;
_options = options;
_tcpListener = new TcpListener(endPoint);
_messageHandler = new TCPMessageHandler();
}
///
/// Bind the server to the given endpoint.
///
public async Task Start(CancellationToken cancellationToken)
{
Console.WriteLine("Starting TCPGameServer listener...");
_tcpListener.Start();
_ = cancellationToken.Register(_tcpListener.Stop);
Console.WriteLine($"TCPGameServer listening on {_endPoint}");
while (!cancellationToken.IsCancellationRequested)
{
try
{
using TcpClient tcpClient = await _tcpListener.AcceptTcpClientAsync(cancellationToken);
await ProcessAsync(tcpClient);
}
catch (SocketException) when (cancellationToken.IsCancellationRequested)
{
Console.WriteLine("TcpListener stopped listening because cancellation was requested.");
}
catch
{
throw;
}
finally
{
_tcpListener.Stop();
}
}
}
///
/// Begin processing messages
///
///
public async Task ProcessAsync(TcpClient tcpClient)
{
try
{
using NetworkStream stream = tcpClient.GetStream();
byte[] data = new byte[tcpClient.ReceiveBufferSize];
int bytesRead = 0;
int chunkSize = 1;
// Read everything into the data buffer
while (bytesRead < data.Length && chunkSize > 0)
{
bytesRead +=
chunkSize =
await stream.ReadAsync(data.AsMemory(bytesRead, data.Length - bytesRead));
}
// Use the in-memory buffer to process the message
await _messageHandler.HandleMessageAsync(stream.Socket, new MessageMemoryStream(data));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}