0

我正在制作一个简单的在线游戏,但我遇到了不同步的问题。服务器采用 IOCP 实现,由于游戏几乎总是在 LAN 中进行,因此延迟相对较小。

网络连接的核心算法可以描述如下:(一个fam有4个client)

  • 客户端每帧将他们的动作和自上一帧以来经过的时间发送到服务器,然后等待服务器的响应。
  • 服务器收集所有四个客户端的消息,将它们连接在一起,然后将其发送给所有四个客户端。
  • 收到响应后,客户端会使用响应中提供的消息更新他们的游戏。

现在,我可以看到一段时间后,这四场比赛不同步了。可以观察到我所控制的游戏与其他三个不同(这意味着其他三个是相同的),只是通过走动就会出现问题。

下面是代码,如果它可能有帮助:

首先,服务器。每条消息都将在单独的线程中处理。

    while(game_host[now_roomnum].Ready(now_playernum)) // wait for the last message to be taken away
    {
        Sleep(1);
    }

    game_host[now_roomnum].SetMessage(now_playernum, recv_msg->msg);
    game_host[now_roomnum].SetReady(now_playernum, true);
    game_host[now_roomnum].SetUsed(now_playernum, false);
    while(!game_host[now_roomnum].AllReady()) // wait for all clients' messages
    {
        Sleep(1);
    }

    string all_msg = game_host[now_roomnum].GetAllMessage();
    game_host[now_roomnum].SetUsed(now_playernum, true);
    while(!game_host[now_roomnum].AllUsed()) // wait for all four responses are ready to send
    {
        Sleep(1);
    }
    game_host[now_roomnum].SetReady(now_playernum, false);// ready for receiving the next message

    strcpy_s(ret.msg, all_msg.c_str());

和客户的CGame::Update(float game_time)方法:

CMessage msg = MakeMessage(game_time);//Make a message with the actions taken in the frame(pushed into a queue) and the elasped time between the two frames
CMessage recv = p_res_manager->m_Client._SendMessage(msg);//send the message and wait for the server's response
stringstream input(recv.msg);
int i;

rest_time -= game_time;
float game_times[MAX_PLAYER+1]={0};

//analyze recv operations
for(i=1; i<=MAX_PLAYER; i++)
{
    int n;
    input>>n;
    input>>game_times[i];//analyze the number of actions n, and player[i]'s elasped game time game_times[i]
    for(int oper_i = 1; oper_i <= n; oper_i++)
    {
        int now_event;
        UINT nchar;
        input>>now_event>>nchar;

        if(now_event == int(Event::KEY_UP))
            HandleKeyUpInUpdate(i, nchar);
        else //if(now_event == int(Event::KEY_DOWN))
            HandleKeyDownInUpdate(i, nchar);
    }
}

//update player
for(i=1; i<=MAX_PLAYER; i++)
{
    player[i].Update(game_times[i]);//something like s[i] = v[i] * game_time[i]
}

非常感谢。如果需要,我会提供更多细节。

4

1 回答 1

0

你的一般设计是错误的,这就是为什么你在某些时候会异步。服务器永远不应该处理客户端的 fps。这只是一个可怕的设计问题。通常,服务器会计算有关客户端发送到服务器的输入的所有内容。客户端只需请求服务器周围环境的当前状态。这样你就在服务器端独立于 fps。这意味着您可以尽快更新服务器上的场景,而客户端只需检索当前状态。

当您更新依赖于每个用户的服务器 fps 上的实体时,您必须为每个客户端保留每个实体的本地副本,否则无法传输不同的增量时间。

另一种设计可能是你的服务器只是同步客户端,所以每个客户端都自己计算场景,然后将它们的状态发送到服务器。然后服务器将其分发给其他客户端,客户端决定如何处理这些信息。

任何其他设计都会导致重大问题,我非常遗憾没有使用任何其他设计。

如果您有任何进一步的问题,请随时与我联系。

于 2015-06-17T12:48:02.373 回答