我正在进行多人游戏,每一帧,玩家的位置必须被发送到服务器,在那里它将接收所有其他玩家的位置作为回应。
我添加了这一行以使我的代码无阻塞:
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帧。这太糟糕了。
有人可以了解如何让游戏继续运行,让它同时收听套接字吗?
答案 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。)
void idle()
{
if( hasDataArrivedOn(socket) ) {
receiveFrom(socket);
}
simulate();
glutPostRedisplay();
}