Я просмотрел по меньшей мере сотню потоков, и ни один из них не дал мне решения моей конкретной проблемы, и я устал смотреть,
Я пытаюсь эмулировать игровой сервер runescape в C #,
Мне нужно получить множество соединений, проанализировать запросы и отправить ответы на них, пока игра не загрузит все файлы, а затем перейти к действительному протоколу входа в систему. это должно быть в состоянии обрабатывать несколько соединений в секунду, как, например, я обрабатываю 3 основных протокола: «jaggrab», «ondemand», а затем обычный протокол игры, т.е. вход в систему, обновление плеера и т. д. все они обрабатываются на одном и том же порту
Класс My Server прослушивает соединения в одном потоке, в то время как в другом потоке мой PipelineFactory обрабатывает соединения в очереди по очереди настолько быстро, насколько это возможно, в то время как существует поток TaskPool, который выполняет объекты PoolableTask через свои отдельные интервалы ... это работает нормально, за исключением того, что как только я принимаю соединение, потоки пула и сервера начинают блокироваться, и, более того, объект сервера перестает прослушивать соединения все вместе, но поток, кажется, продолжает работать .. Я предполагаю, что это потому, что TcpListener.Pending () не обновляется? но я не могу найти функцию для обновления этого списка в документах или в любом месте
Кажется, я использую потоки так, как все учебники по многопоточности объясняют их работу? я действительно не понимаю, что я делаю неправильно .. вот важные части моего кода:
MainEntry.cs:
using System;
using System.Threading;
using gameserver.evt;
using gameserver.io;
using gameserver;
using gameserver.io.player;
public static class MainEntry
{
public static void Main(string[] args)
{
Console.WriteLine("Starting game server...");
new Thread(new ThreadStart(Server.Run)).Start();
new Thread(new ThreadStart(TaskPool.Run)).Start();
new Thread(new ThreadStart(PipelineFactory.Run)).Start();
//TODO maybe pool these
}
}
Server.cs:
using gameserver.io.player;
using gameserver.io.sql;
using gameserver.model;
using gameserver.model.player;
using util;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using gameserver.io.player.pipeline;
using gameserver.evt;
using util.cache;
namespace gameserver.io
{
public class Server
{
public static TcpListener serverSocket;
public static Dictionary<int, Player> players = new Dictionary<int, Player>(Constants.MaxPlayers);
public static Database database;
public const int ListenPort = 43594;
public static bool running = true;
public static readonly Cache cache = new Cache(Constants.CacheDir);
public static void Bind()
{
serverSocket = new TcpListener(IPAddress.Parse("0.0.0.0"), ListenPort);
serverSocket.Start();
Console.WriteLine("Server started at 0.0.0.0:" + ListenPort);
}
public static void Run()
{
if (serverSocket == null)
Bind();
while(IsRunning())
{
Console.Write("serve");
var incoming = serverSocket.AcceptTcpClient();
if (incoming != null)
{
PipelineFactory.queue.Enqueue(new PlayerSocket(incoming));
}
Thread.Sleep(25);
}
}
private static void Destroy()
{
serverSocket.Stop();
//saveall players
//Environment.Exit(0);
}
public static bool Online(Player player)
{
if(player == null)
{
return false;
}
for (int i = 0; i < players.Count; i++)
{
if (player.username == players[i].username)
{
return true;
}
}
return false;
}
public static Database Database => database ?? (database = new Database());
public static bool IsRunning() => running;
}
}
TickPool.cs:
using gameserver.io;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace gameserver.evt
{
public class TaskPool
{
public static bool running = true;
public static List<PoolableTask> tasks = new List<PoolableTask>();
public static void Run()
{
do
{
long cur = Environment.TickCount;
Console.Write("tick");
foreach (PoolableTask t in tasks)
{
if (cur - t.last >= t.interval)
{
if (t == null)
continue;
t.Execute();
t.last = cur;
}
}
Thread.Sleep(100);
} while (Server.IsRunning());
}
public static void Add(PoolableTask task)
{
if(!tasks.Contains(task))
tasks.Add(task);
}
public static void Stop(PoolableTask task)
{
if(tasks.Contains(task))
tasks.Remove(task);
}
}
}
PipelineFactory.cs:
using gameserver.evt;
using gameserver.io.player.pipeline;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace gameserver.io.player
{
// simple but effective state machine for all non player model related protocol
public class PipelineFactory
{
public static Queue<PlayerSocket> queue = new Queue<PlayerSocket>(100);
private static readonly LoginPipe loginPipe = new LoginPipe();
private static readonly JaggrabPipe jgpipe = new JaggrabPipe();
private static readonly HandshakePipe handshake = new HandshakePipe();
private static readonly OnDemandPipe ondemand = new OnDemandPipe();
public static void Run()
{
while (Server.IsRunning())
{
Console.Write("pipe");
if (queue.Count() > 0)
{
var socket = queue.First();
if (socket == null || !socket.GetSocket().Connected
|| socket.state == PipeState.Play)
{
queue.Dequeue();
return;
}
switch (socket.state)
{
case PipeState.Handshake:
socket.currentPipeline = handshake;
break;
case PipeState.Jaggrab:
socket.currentPipeline = jgpipe;
break;
case PipeState.OnDemand:
socket.currentPipeline = ondemand;
break;
case PipeState.LoginResponse:
case PipeState.Block:
case PipeState.Finalize:
socket.currentPipeline = loginPipe;
break;
case PipeState.Disconnect:
//TODO: Database.saveForPlayer
socket.Close();
break;
}
try
{
if (socket.currentPipeline != null)
socket.state = socket.currentPipeline.HandleSocket(socket);
}
catch (Exception)
{
socket.Close();
queue.Dequeue();
}
}
Thread.Sleep(20);
}
}
}
}
Сам протокол действительно не должен иметь значения, просто знайте, что он обрабатывается асинхронно
В глубине души я программист на Java, но сначала пытаюсь углубиться в C # head, поэтому мои соглашения могут быть не идеальными, и я действительно не знаю, как / не понимаю документацию на intellisense, но в какой-то момент плохо изучаю ее
РЕДАКТИРОВАТЬ: я просто хочу отметить, что все работало отлично, прежде чем я попытался использовать потоки для многопоточности, когда у меня была реализация объекта PipelineFactory PoolableTask, он мог обрабатывать несколько соединений и т. Д., И был только основной поток, вызывающий 2 во время обработки циклов все на всем сервере, я пытаюсь распределить нагрузку на процессор, но это не работает для меня LOL