由于系统缺少足够的缓冲区空间或队列已满,无法对套接字执行boost :: asio操作

时间:2019-12-06 01:46:21

标签: c++ boost boost-asio

我一直在为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%,即使两个玩家都长时间静止不动,错误也会继续发生,这应该使服务器有足够的时间来处理其队列。

我必须使用一些“队列刷新”命令吗?还是我的代码中存在某种泄漏?

0 个答案:

没有答案