多线程网络应用程序问题

时间:2019-03-14 08:43:35

标签: c# multithreading networking server

我看过至少一百个线程,到目前为止,没有一个给我特定问题的解决方案,而我已经厌倦了看,

我正在尝试在C#中模拟runescape游戏服务器,

我需要接收大量连接并解析请求并为它们发送响应,直到游戏加载了所有文件,然后继续执行实际的登录协议。这需要每秒能够处理多个连接,例如,我处理3个基本协议“ jaggrab”,“ ondemand”,然后处理常规游戏协议,即;登录,玩家更新等都在同一端口上处理

我的Server类侦听一个线程上的连接,而在另一个线程上,我的PipelineFactory尽可能快地一个一个地处理Queue中的连接,同时有一个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#,所以这就是为什么我的约定可能不完善的原因,并且我真的不知道如何/不理解智能文档,但有时会不了解

编辑:我只是想指出,在尝试使用线程将其多线程化之前,一切工作正常,当我将PipelineFactory设为PoolableTask对象实现时,它可以处理多个连接,等等,并且只有主线程调用2 while循环处理整个服务器中的所有内容,我都试图将负载分散到cpu上,但对我来说却不起作用

0 个答案:

没有答案