我一直在为2D平台游戏开发视频游戏应用程序。为此,两个玩家都将其位置数据流式传输到服务器,该服务器将其重新路由到其他玩家。到目前为止,代码如下:
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <iostream>
using boost::asio::ip::udp;
using boost::asio::ip::address;
class Server {
std::string playerIP[20];
boost::array<int, 5> buf;
udp::endpoint remote_endpoint;
std::string ipaddress;
public:
Server(boost::asio::io_service& io_service) : socket(io_service, udp::endpoint(udp::v4(), port)) {
std::cout << "Server started!" << std::endl;
wait();
}
void wait() {
socket.async_receive_from(
boost::asio::buffer(buf), remote_endpoint,
boost::bind(&Server::handle_receive, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_receive(const boost::system::error_code& error, size_t bytes_transferred) {
// Do to asynchronous nature of this method, both the message received and the IP sent from must be saved to persist when buffer changes
std::string address(remote_endpoint.address().to_string());
boost::array<int, 5> recv(buf);
std::cout << "Received " << recv[0] << "-" << recv[1] << "-" << recv[2] << "-" << recv[3] << "-" << recv[4] << "-" << recv[5] << std::endl;
if (error) {
std::cout << "Receive failed: " << error.message() << std::endl;
return;
}
if (bytes_transferred > 0)
{
if(playerIP[recv[PLAYER_ID]] == "") {
// New player
playerIP[recv[PLAYER_ID]] = address;
} else if(playerIP[recv[PLAYER_ID]] != address) {
// Error! Different IP address is identified with this player!
wait();
return;
}
// Handle message
NetworkClient::handleReceive(error, bytes_transferred);
broadcast(recv);
}
// Start new async wait
wait();
}
void broadcast(boost::array<int, 5> message) {
// Broadcast back to other players in connection list
for(int player=0; player<global::MAX_PLAYERS; player++) {
if(playerIP[player] != "" && player != message[PLAYER_ID]) {
socket.async_send_to(boost::asio::buffer(message),
udp::endpoint(address::from_string(playerIP[player]), SER_TO_CLI_PORT),
boost::bind(&Server::handleSend, this, message,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
}
void handleSend(boost::array<int, 5> message,
const boost::system::error_code& error, size_t bytes_transferred) {
// Handle extra message-handling stuff...
}
};
void WorkerThread( boost::shared_ptr<boost::asio::io_service> io_service )
{
io_service->run();
}
// This game uses SDL, which normally rerouts all output to a txt file.
// I want server info in realtime, so disable that using undef
#undef main
int main(int argc, char *argv[])
{
boost::asio::io_service io_service;
Server server(io_service);
server.wait();
std::cout << "Making " << boost::thread::hardware_concurrency() << " threads" << std::endl;
boost::thread_group tg;
for (unsigned i = 0; i < boost::thread::hardware_concurrency(); ++i)
tg.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
tg.join_all();
return 0;
}
一个明确的特征是,在等待消息的同时,客户端不会从客户端发送数据,直到播放器实际执行某些操作为止,这意味着服务器可以等待很长时间而无需执行任何操作。 / p>
考虑到这一点,服务器一直存在错误:Receive failed: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full
。我在一台速度较慢的计算机(2.8 GHz,896 MB RAM)上运行服务器,此错误在40秒内开始显示。我认为那是不自然的。在此40秒标记后,此错误会遇到所有传入消息的50%,即使两个玩家都长时间静止不动,错误也会继续发生,这应该使服务器有足够的时间来处理其队列。
我必须使用一些“队列刷新”命令吗?还是我的代码中存在某种泄漏?