feat: wip: use TcpClient

This commit is contained in:
Aaron Yarborough 2024-05-22 17:31:06 +01:00
parent a7344f5a7b
commit 35755eb7ec
9 changed files with 138 additions and 32 deletions

View file

@ -32,7 +32,7 @@ internal class Program
{ {
byte[] bytes = udpClient.Receive(ref serverEP); byte[] bytes = udpClient.Receive(ref serverEP);
MessageMemoryStream stream = new(bytes); MessageNetworkStream stream = new(bytes);
ClientPacketIn packetIn = (ClientPacketIn)stream.ReadByte(); ClientPacketIn packetIn = (ClientPacketIn)stream.ReadByte();
switch (packetIn) switch (packetIn)

View file

@ -4,10 +4,6 @@ namespace GServer.Common;
public class MessageMemoryStream : MemoryStream public class MessageMemoryStream : MemoryStream
{ {
public MessageMemoryStream()
{
}
public MessageMemoryStream(byte[] buffer) : base(buffer) public MessageMemoryStream(byte[] buffer) : base(buffer)
{ {
} }

View file

@ -30,7 +30,7 @@ public class AuthResponseMessage : BaseMessage, IMessage<AuthResponseMessage>
FailureReason = failureReason; FailureReason = failureReason;
} }
public AuthResponseMessage(MessageMemoryStream stream) : base((byte)ClientPacketIn.AUTH_RESPONSE) public AuthResponseMessage(MessageNetworkStream stream) : base((byte)ClientPacketIn.AUTH_RESPONSE)
{ {
IsSuccessful = stream.ReadBoolean(); IsSuccessful = stream.ReadBoolean();
@ -47,7 +47,7 @@ public class AuthResponseMessage : BaseMessage, IMessage<AuthResponseMessage>
public byte[] Serialize() public byte[] Serialize()
{ {
using MessageMemoryStream stream = new(); using MessageNetworkStream stream = new();
stream.WriteByte(PacketId); stream.WriteByte(PacketId);
stream.WriteBoolean(IsSuccessful); stream.WriteBoolean(IsSuccessful);

View file

@ -12,7 +12,7 @@ public class ListServersResponseMessage : BaseMessage, IMessage<ListServersRespo
ServerListings = serverListings; ServerListings = serverListings;
} }
public ListServersResponseMessage(MessageMemoryStream stream) : base((byte)ClientPacketIn.LIST_SERVERS_RESPONSE) public ListServersResponseMessage(MessageNetworkStream stream) : base((byte)ClientPacketIn.LIST_SERVERS_RESPONSE)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

View file

@ -14,7 +14,7 @@ public class AuthMessage : BaseMessage, IMessage<AuthMessage>
Password = password; Password = password;
} }
public AuthMessage(MessageMemoryStream stream) : base((byte)ServerPacketIn.AUTH) public AuthMessage(MessageNetworkStream stream) : base((byte)ServerPacketIn.AUTH)
{ {
byte usernameLen = (byte)stream.ReadByte(); byte usernameLen = (byte)stream.ReadByte();
string username = stream.ReadUTF8String(usernameLen); string username = stream.ReadUTF8String(usernameLen);

View file

@ -0,0 +1,6 @@
namespace GServer.Server;
public class GameServerOptions
{
public int PacketLength { get; set; }
}

View file

@ -0,0 +1,116 @@
using System.Net;
using System.Net.Sockets;
using GServer.Common;
using GServer.Common.Networking.Enums;
using GServer.Common.Networking.Messages.Client;
using GServer.Common.Networking.Messages.Server;
namespace GServer.Server;
public class TCPGameServer : IDisposable
{
private readonly TcpListener _tcpListener;
private readonly IPEndPoint _endPoint;
private readonly GameServerOptions _options;
public TCPGameServer(IPEndPoint endPoint, GameServerOptions options)
{
_endPoint = endPoint;
_options = options;
_tcpListener = new TcpListener(endPoint);
}
/// <summary>
/// Bind the server to the given endpoint.
/// </summary>
public async void Start()
{
Console.WriteLine("Starting TCPGameServer listener...");
_tcpListener.Start();
Console.WriteLine($"TCPGameServer listening on {_endPoint}");
try
{
while (true)
{
await ProcessAsync(await _tcpListener.AcceptTcpClientAsync());
}
}
catch
{
throw;
}
finally
{
_tcpListener.Stop();
}
}
/// <summary>
/// Begin processing messages
/// </summary>
/// <returns></returns>
public async Task ProcessAsync(TcpClient tcpClient)
{
try
{
using NetworkStream stream = tcpClient.GetStream();
byte[] data = new byte[_options.PacketLength];
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 HandleMessageAsync(stream.Socket, new MessageMemoryStream(data));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private async Task HandleMessageAsync(Socket clientSocket, MessageMemoryStream messageStream)
{
ServerPacketIn serverPacketIn = (ServerPacketIn)messageStream.ReadByte();
Console.WriteLine($"Handling message {serverPacketIn} from {client}...");
switch (serverPacketIn)
{
case ServerPacketIn.AUTH:
AuthMessage msg = new(messageStream);
AuthResponseMessage resp = msg.Username == "aaronyarbz" && msg.Password == "password123"
? new(true, Guid.NewGuid().ToString(), null)
: new(false, null, AuthResponseFailure.IncorrectLoginOrPassword);
byte[] buffer = resp.Serialize();
_ = await TcpClient.Client.SendAsync(buffer,
break;
case ServerPacketIn.LIST_SERVERS:
throw new NotImplementedException();
default:
Console.WriteLine($"Received unsupported packet.");
break;
}
}
public void Dispose()
{
TcpClient.Close();
TcpClient.Dispose();
GC.SuppressFinalize(this);
}
}

View file

@ -2,8 +2,6 @@ using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using GServer.Common; using GServer.Common;
using GServer.Common.Networking.Enums; using GServer.Common.Networking.Enums;
using GServer.Common.Networking.Messages.Client;
using GServer.Common.Networking.Messages.Server;
namespace GServer.Server; namespace GServer.Server;
@ -43,7 +41,7 @@ public class UDPGameServer : IDisposable
{ {
UdpReceiveResult res = await UdpClient.ReceiveAsync(); UdpReceiveResult res = await UdpClient.ReceiveAsync();
byte[] bytes = res.Buffer; byte[] bytes = res.Buffer;
MessageMemoryStream stream = new(bytes); MessageNetworkStream stream = new(bytes);
await HandleMessageAsync(stream, res.RemoteEndPoint); await HandleMessageAsync(stream, res.RemoteEndPoint);
} }
catch (Exception ex) catch (Exception ex)
@ -52,32 +50,17 @@ public class UDPGameServer : IDisposable
} }
} }
private async Task HandleMessageAsync(MessageMemoryStream stream, IPEndPoint remoteEndPoint) private async Task HandleMessageAsync(MessageNetworkStream stream, IPEndPoint remoteEndPoint)
{ {
ServerPacketIn serverPacketIn = (ServerPacketIn)stream.ReadByte(); byte serverPacketInByte = (byte)stream.ReadByte();
ServerPacketIn serverPacketIn = (ServerPacketIn)serverPacketInByte;
Console.WriteLine($"Handling message {serverPacketIn} from {remoteEndPoint}..."); Console.WriteLine($"Handling UDP message {serverPacketInByte} from {remoteEndPoint}...");
switch (serverPacketIn) switch (serverPacketIn)
{ {
case ServerPacketIn.AUTH:
AuthMessage msg = new(stream);
AuthResponseMessage resp = msg.Username == "aaronyarbz" && msg.Password == "password123"
? new(true, Guid.NewGuid().ToString(), null)
: new(false, null, AuthResponseFailure.IncorrectLoginOrPassword);
byte[] buffer = resp.Serialize();
_ = await UdpClient.SendAsync(buffer, buffer.Length, remoteEndPoint);
break;
case ServerPacketIn.LIST_SERVERS:
throw new NotImplementedException();
default: default:
Console.WriteLine($"Received unsupported packet."); throw new NotImplementedException($"Received unsupported packet {serverPacketInByte}");
break;
} }
} }

5
notes Normal file
View file

@ -0,0 +1,5 @@
potentially move flag type to short from byte
single thread accept
- spin up multiple threads to deal with actions