多线程服务器设计

Multithread server design

本文关键字:服务器 多线程      更新时间:2023-10-16

我目前正在编写一个游戏服务器。我使用boost::asio与io_service。我遇到了一个会话类超出范围的问题(我不确定何时安全地删除它),并向多个客户端发送数据包。这是我当前的代码

class io_pool
{
    void Run(int threads)
    {
        // make as much threads as user wants + call io_service.run from all threads
        // so I have one io_service, which consumes more than 1 thrread
    }
}
// the server that accepts
class server
{
    void Accept()
    {
        // create new session and wait for session to connect
    }
    void OnAccept()
    {
        // call session start, and call accept again to wait for more
    }
}
// a connection from a client
class session
{
    // keep track of a client
    // holds SendPacket, RecvPacket and stuff like that
        // here is no problem with multithread since the callback frmo a socket can't be called at the same time
}
// the basic class
class client
{
    // holds info about character, map etcetc
    // has also a SendPacket() function which calls the session one.
}
// keeps track of all players in maps
class world_server
{
    std::map<dword /* map id*/, std::vector<std::shared_ptr<client>>>; // to hold info about the players in a map
    void AddPlayer(dword map id, client);
        void RemovePlayer(dword map id, client);
    std::vector<std::shared_ptr<client>>& GetPlayersdword (map_id);
}

在Io_service池中,我创建了一个Io_service,并在整个程序中传递。

当用户或I关闭套接字时问题开始。boost中的read_async()函数调用回调函数时会出现如下错误代码:

void Session::Stop()
    {
        m_socket.shutdown(boost::asio::socket_base::shutdown_both);
        m_socket.close();
        m_time_out.Stop();
        // call here the delete function in tcp_server class?
    }
if (e || bytes_transferred != 4)
    {
            if (e == boost::asio::error::operation_aborted)
                return;
            Stop();
            return;
        }

但是当我调用socket.close/shutdown()时,有时错误代码不是operation_aborted。这在我的Stop()函数中给出了一个错误,因为我在调用delete函数(调用服务器DeleteClient())时两次中止同一个套接字,我得到了访问冲突,导致类超出了作用域。

这也带来了我的下一个问题,当另一个会话,正在更新自己的运动,并希望将信息发送到同一地图中的所有其他会话时,会发生什么。我用客户机调用io_service.post()。SendPacket作为信息。但是,如果在此之前删除了会话,则不会以与上面相同的错误结束。

我想出了一个丑陋的解决方案是在30秒后用计时器删除会话类。因为我猜没有一个处理程序需要30秒才能被调用,所以这应该是可行的。虽然在我看来很丑。

谢谢你的阅读,我很欣赏任何对设计的批评

Gr

听起来您可以通过添加一些状态标志和测试来解决大部分或所有这些问题。当你有一些停止或关闭服务的操作时,设置状态标志,例如:

HasBeenShutDown = true;

当你要做一些依赖于服务未被关闭(包括关闭它)的事情时,测试标志,例如:

if (HasBeenShutDown) return;//或者DoAppropriateCleanup();

但更大的问题将是理解在这些情况下需要发生什么,而不仅仅是避免崩溃。当你的部分系统已经关闭,但你想要恢复并继续运行,需要发生什么才能再次回到有序的工作状态,而不会打乱你的游戏状态。