Hallo Community,
ich habe gerade ein kleines Mühlespiel fertiggestellt und beim Multiplayer im lokalen netzwerk ist ein fehler aufgetreten bei dem ich nicht weiß wie ich ihn behandeln soll.
Ich habe im Spiel verschiedene Befehle die ich senden kann in einem "Command" enum.
Allgemeiner Stringaufbau:
Command, String[] parameter
nach jedem parameter und nach dem Kommando ist immer eine Pipe "|" um die einzelnen strings klar zu trennen
Also beispielsweise:
"SetStone|true|In|5"
(SetStone ist das kommando was getan werden soll | true (farbe ist schwarz bei false farbe ist weiß | In (Innerer ring) | 5 (Position auf dem ring))
Nun das Problem:
Ich habe folgenden String empfangen:
"SetStone|true|Out|6NextPlayer"
Dies hat natürlich eine Exception außgelößt da man den letzten parameter nicht in einen integer umwandeln kann.
"NextPlayer" ist das Kommando das Übertragen wird wenn ein Spieler seinen Zug beendet hat.
Es ist also passiert dass 2 Kommandos gesendet wurden aber diese 2 Kommandos als 1 Kommando von meinem Spiel empfangen wurde. Wie kann das Passieren bzw. wie kann ich es lößen dass dieses verhalten nicht mehr vorkommen kann?
Meistens funktioniert es ja einwandfrei jedoch kann es passieren.
Hier der Quellcode meiner Netzwerkklassen:
ConnectionClient und ConnectionHost erben von ConnectionBase.
ich habe gerade ein kleines Mühlespiel fertiggestellt und beim Multiplayer im lokalen netzwerk ist ein fehler aufgetreten bei dem ich nicht weiß wie ich ihn behandeln soll.
Ich habe im Spiel verschiedene Befehle die ich senden kann in einem "Command" enum.
Allgemeiner Stringaufbau:
Command, String[] parameter
nach jedem parameter und nach dem Kommando ist immer eine Pipe "|" um die einzelnen strings klar zu trennen
Also beispielsweise:
"SetStone|true|In|5"
(SetStone ist das kommando was getan werden soll | true (farbe ist schwarz bei false farbe ist weiß | In (Innerer ring) | 5 (Position auf dem ring))
Nun das Problem:
Ich habe folgenden String empfangen:
"SetStone|true|Out|6NextPlayer"
Dies hat natürlich eine Exception außgelößt da man den letzten parameter nicht in einen integer umwandeln kann.
"NextPlayer" ist das Kommando das Übertragen wird wenn ein Spieler seinen Zug beendet hat.
Es ist also passiert dass 2 Kommandos gesendet wurden aber diese 2 Kommandos als 1 Kommando von meinem Spiel empfangen wurde. Wie kann das Passieren bzw. wie kann ich es lößen dass dieses verhalten nicht mehr vorkommen kann?
Meistens funktioniert es ja einwandfrei jedoch kann es passieren.
Hier der Quellcode meiner Netzwerkklassen:
ConnectionClient und ConnectionHost erben von ConnectionBase.
Code:
public delegate void ConnectedDelegate(bool Connected);
public delegate void DataReceived(String data);
public abstract class ConnectionBase
{
protected Socket _clientSocket;
protected int _port;
protected byte[] _buffer = new byte[1024];
public virtual event ConnectedDelegate Connected;
public virtual event DataReceived DataReceived;
public ConnectionBase()
{
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
}
protected void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
try
{
Shutdown();
}
catch { }
}
public void Shutdown()
{
try
{
if (_clientSocket != null)
{
String shutdown = "Shutdown";
byte[] bdata = GetBytes(shutdown);
_clientSocket.Send(bdata);
}
//shutdown Fehler
ShutSocketsDown();
}
catch (Exception ex){ }
}
protected byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
protected string GetString(byte[] bytes)
{
char[] chars = new char[bytes.Length / sizeof(char)];
System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
return new string(chars);
}
protected void ReceiveCallback(IAsyncResult AR)
{
if(Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "Connection Receive Callback Thread";
Socket socket = (Socket)AR.AsyncState;
int received = socket.EndReceive(AR);
byte[] dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
String text = GetString(dataBuf);
if (text.Equals("Shutdown"))
{
ShutSocketsDown();
return;
}
if (DataReceived != null)
DataReceived(text);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
}
public void Send(String data)
{
byte[] bdata = GetBytes(data);
_clientSocket.BeginSend(bdata, 0, bdata.Length, SocketFlags.None, new AsyncCallback(SendCallback), _clientSocket);
}
protected void SendCallback(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
}
protected virtual void ShutSocketsDown()
{
if (_clientSocket != null)
{
ShutdownSocket(_clientSocket);
try {
//_clientSocket.Dispose();
}
catch (Exception ex){ }
_clientSocket = null;
}
}
protected void ShutdownSocket(Socket socket)
{
byte[] buffer = new byte[1024];
if (socket.Connected)
{
socket.Shutdown(SocketShutdown.Send);
try
{
int read = 0;
while ((read = socket.Receive(buffer)) > 0)
{ }
}
catch
{
//ignore
}
}
socket.Close();
}
}
Code:
public class ConnectionHost : ConnectionBase
{
private Socket _serverSocket;
public override event ConnectedDelegate Connected;
public ConnectionHost(int Port) : base()
{
this._port = Port;
}
public void StartServer()
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, _port));
_serverSocket.Listen(10);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
protected void AcceptCallback(IAsyncResult AR)
{
Socket socket = _serverSocket.EndAccept(AR);
_clientSocket = socket;
Connected(true);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
}
protected override void ShutSocketsDown()
{
base.ShutSocketsDown();
if (_serverSocket != null)
{
ShutdownSocket(_serverSocket);
try
{
//_serverSocket.Dispose();
}
catch (Exception ex) { }
//_serverSocket = null;
}
}
}
Code:
public class ConnectionClient : ConnectionBase
{
private IPAddress _ipAdress;
public override event ConnectedDelegate Connected;
public ConnectionClient(String IPorName, int Port) : base()
{
this._port = Port;
bool isIP = IPAddress.TryParse(IPorName.Trim(), out _ipAdress);
if(!isIP)
_ipAdress = Dns.GetHostEntry(IPorName).AddressList[0];
}
public bool Connect()
{
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//bool connect = ConnectAsync(_ipAdress).Result;
bool connect = ConnectSocket(_ipAdress);
Connected(connect);
if(connect)
_clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), _clientSocket);
return connect;
}
private async Task<bool> ConnectAsync(IPAddress ipserver)
{
return await Task.Factory.StartNew(() => LoopConnect(ipserver));
}
private bool ConnectSocket(IPAddress ipserver)
{
return LoopConnect(ipserver);
}
private bool LoopConnect(IPAddress ipserver)
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
_clientSocket.Connect(ipserver, _port);
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
if (attempts >= 10 && !_clientSocket.Connected)
return false;
}
return false;
}
}