Всем привет! Может ли кто-нибудь объяснить как на C# реализовать игровой сервер. Его задача: держать подключённых пользователей, когда пользователь шлёт сообщение на сервер, сервер должен подключённым пользователям отослать сообщение.
После многих часов гугла и большого количества примеров есть два консольных приложения - GameServer и TestService.
Идея была такая: клиент подключается с помощью метода TcpClient.Connect(), соответственно на сервере это отлавливается с помощью TcpListener.Accept(). На сервере сохраняется клиент - из его потока TcpClient().GetStream() читаются данные с помощью BeginRead(), а при прочтении их можно записать в NetworkStream других клиентов.
Что пошло не так:
В TestService удалось подключиться и отослать ОДНО! сообщение и получить ответ от сервера, после этого свойство TcpClient.Connected стало false со стороны TestService, соответственно я не могу больше использовать этот экземпляр TcpClient, но мне нужно чтобы именно в его stream приходили сообщения от сервера. Со стороны сервера метод BeginRead после получения одного сообщения начинает бесконечно читать пустые сообщения.
Сервер - только метод старт, потому что только он реализован
public void Start()
{
try
{
TcpListener tcpListener = new TcpListener(IPAddress.Parse(ipAddress), port);
tcpListener.Start();
ServerLogger.Log("Server has been started");
while(true)
{
TcpClient client = tcpListener.AcceptClient();
GameConnections.Add(new GameConnection(client, GameConnections.Count));
}
}
catch(Exception ex)
{
ServerLogger.Error(ex.Message);
}
}
GameConnection
class GameConnection
{
string GameID { get; set; }
string ConnectionID { get; set; }
TcpClient Client { get; set; }
byte[] acceptedData = new byte[1024];
byte[] sendData = new byte[1024];
byte[] buffer = new byte[1024];
NetworkStream stream;
static void HandleNewClient()
{
}
public GameConnection(TcpClient client, int id)
{
Client = client;
stream = client.GetStream();
ConnectionID = "connection" + id;
ServerLogger.Log(string.Format("Client connected. ConnectionID: {1}", GameID, ConnectionID));
stream.BeginRead(acceptedData, 0, acceptedData.Length, FirstReadCallback, null);
}
public void FirstReadCallback(IAsyncResult ar)
{
int bytesRead = stream.EndRead(ar);
if(bytesRead > 0)
{
Console.WriteLine(bytesRead);
GameID = Encoding.UTF8.GetString(acceptedData, 0, bytesRead);
Console.WriteLine("Game id - " + GameID);
stream.BeginRead(acceptedData, 0, acceptedData.Length, ReadCallback, null);
ServerLogger.Log(String.Format("{0} game id is {1}", ConnectionID, GameID));
}else
{
ServerLogger.Log(String.Format("Empty first read from client({0})", ConnectionID));
stream.BeginRead(acceptedData, 0, acceptedData.Length, FirstReadCallback, null);
}
}
public void ReadCallback(IAsyncResult ar)
{
int bytesRead = stream.EndRead(ar);
if(bytesRead > 0)
{
string command = Encoding.UTF8.GetString(acceptedData, 0, bytesRead);
ServerLogger.Log(String.Format("Command from client({0}): {1}", ConnectionID, command));
string serverAnswer = "some game command";
Encoding.UTF8.GetBytes(serverAnswer, 0, serverAnswer.Length, sendData, 0);
stream.Write(sendData, 0, serverAnswer.Length);
stream.BeginRead(acceptedData, 0, acceptedData.Length, ReadCallback, null);
}
else
{
ServerLogger.Log(String.Format("Empty read from client({0})", ConnectionID));
stream.BeginRead(acceptedData, 0, acceptedData.Length, ReadCallback, null);
}
}
}
TestService
class Program
{
static void Main(string[] args)
{
TcpClient client = new TcpClient();
try
{
Console.WriteLine("Connecting to server");
client.Connect(IPAddress.Parse("127.0.0.1"), 8888);
using (BinaryWriter writer = new BinaryWriter(client.GetStream()))
{
byte[] data = new byte[1024];
string gameID = "1000";
Encoding.UTF8.GetBytes(gameID, 0, gameID.Length, data, 0);
writer.Write(data, 0, gameID.Length);
Console.WriteLine(Encoding.UTF8.GetString(data, 0, gameID.Length));
}
while (true)
{
string command = Console.ReadLine();
if (command == "exit") break;
byte[] data = new byte[1024];
NetworkStream stream = client.GetStream();
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(command);
}
using (BinaryReader reader = new BinaryReader(stream))
{
reader.Read(data, 0, 1024);
Console.WriteLine("Server answer: {0}", Encoding.UTF8.GetString(data));
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
Console.ReadLine();
}
}