等待响应时保持游戏运行?

时间:2013-07-07 21:41:09

标签: c opengl udp winsock glut

我正在进行多人游戏,每一帧,玩家的位置必须被发送到服务器,在那里它将接收所有其他玩家的位置作为回应。

我添加了这一行以使我的代码无阻塞:

u_long one = 1; // Giggety
ioctlsocket(sock, FIONBIO, &one);

但现在问题是,除非我启用自己的阻止代码(循环),否则我无法从服务器接收其他玩家的位置。

while(recvfrom(sock, receiveBuffer, 255, 0, (struct sockaddr *)&server, &sockaddr_in_sizePtr) <= 0) {
}
// Do stuff with response

但是自从我这样做以来,游戏的效果非常糟糕,因为本地游戏在我得到回复之前没有运行。

我认为解决方案只是在while循环中调用我的显示函数,但这似乎没有做任何事情。

另一个问题是我使用UDP套接字,这意味着数据甚至可能无法到达我,在这种情况下,它需要超时。所以我补充说:

time_t timer;
time(&timer);
while(recvfrom(sock, receiveBuffer, 255, 0, (struct sockaddr *)&server, &sockaddr_in_sizePtr) < 0) {
    display(); // Doesn't stop lag
    if(timer != time(NULL)) return; 
}

但是现在,我得到的时间实际上是每秒1帧。这太糟糕了。

有人可以了解如何让游戏继续运行,让它同时收听套接字吗?

1 个答案:

答案 0 :(得分:1)

每个交互式仿真程序都会运行一些非阻塞主循环。在该循环中的某个时刻,您将收集从外部到达的所有数据。如果通过网络到达某些新数据,则会将其读取并将其处理为您的程序状态。如果什么都没有到,你就像往常一样继续主循环。

然而,要使此方案正常工作,您的SO接收缓冲区必须足够大,以便它们可以累积大量传入的数据包供您接收。

所以你做的就像是

while(running) {
    if( hasDataArrivedOn(socket) ) {
        receiveFrom(socket);
    }

    if( isThereUserInput(mouse) ) {
        processMouseMovement();
    }

    if( isThereUserInput(keyboard) ) {
        processKeypresses();
    }

    simulate();

    display();
}

“hasDataArrivedOn”函数实际上是另一个ioctl,即FIONREAD,它返回最后一个数据包中接收到的八位字节数,如果没有数据包未决,则返回0(如果最后收到的UDP数据包确实不包含有效负载,则也是如此)返回一个0;你的程序必须能够处理这个,否则它可以通过被不包含有效负载的UDP数据包溢出来进行DoSed。)


更新 - GLUT空闲回调变体

void idle()
{
    if( hasDataArrivedOn(socket) ) {
        receiveFrom(socket);
    }

    simulate();

    glutPostRedisplay();
}