ASIO写入操作抛出std::bad_alloc:C++

ASIO write operation throws std::bad_alloc : C++

本文关键字:bad alloc C++ std 操作 ASIO      更新时间:2023-10-16

我指的是聊天客户端

我的写入操作是:

void CSession::beginWrite(const Buffer & message)
{
    //Check if the socket is open or not?
    bool writeInProgress = !writeQueue_.empty();
    writeQueue_.push_back(message);
    if (!writeInProgress) //Exception Thrown here
    {
        asio::async_write(socket_, asio::buffer(writeQueue_.front().received_, writeQueue_.front().buffsize),
            std::bind(&CSession::handle_write, this,
            std::placeholders::_1, std::placeholders::_2));
    }
}
void CSession::handle_write(const asio::error_code& error /*error*/, size_t bytes_transferred /*bytes_transferred*/)
{
    //std::cout << "CSession::handle_write() Called" << "(" << __FILE__ << " : " << __LINE__ << ")" << std::endl;
    if (!error)
    {
        //std::cout << bytes_transferred << " bytes written to the socket." << std::endl;
        writeQueue_.pop_front();
        if (!writeQueue_.empty())
        {
            asio::async_write(socket_, asio::buffer(writeQueue_.front().received_, writeQueue_.front().buffsize),
                std::bind(&CSession::handle_write, this,
                std::placeholders::_1, std::placeholders::_2));
        }
    }
    else
    {
        std::cout << "Write Error Detected" << std::endl;
        std::cout << error.message() << std::endl;
        state_ = false;
        doClose();
        return;
    }
}

它运行良好。然后我尝试了负载测试,让客户端连续11分钟向服务器写入消息Client 2,如下所示:

bool flag = false;
void setFlag(const asio::error_code& /*e*/)
{
    flag = true;
}
void Client(std::string IP, std::string port)
{
    CSession Session(IP, port);
    Session.initSession();
    asio::thread t(boost::bind(&asio::io_service::run, &(*CIOService::fetchIOService().getIO())));
    asio::deadline_timer timer(*CIOService::fetchIOService().getIO(), boost::posix_time::seconds(675));
    timer.async_wait(&setFlag);
    while (!flag)
    {
        Session.write("Client 2");
    }
    Session.close();
    t.join();
}

void main()
{
    Client("localhost", "8974");
    system("Pause");
}

成功写入操作2-3分钟后,代码在行抛出异常Unhandled exception at 0x75B7C42D in NetworkComponentsClient.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x026DE87C.

if (!writeInProgress) //Exception Thrown here { asio::async_write(socket_, asio::buffer(writeQueue_.front().received_, writeQueue_.front().buffsize), std::bind(&CSession::handle_write, this, std::placeholders::_1, std::placeholders::_2)); }

调试显示:

-       writeQueue_ { size=16777215 }   std::deque<channel::Buffer,std::allocator<channel::Buffer> >
+       [0] {received_=0x052a0ac8 "Client 2" }  channel::Buffer
+       [1] {received_=0x052a0b28 "Client 2" }  channel::Buffer
+       [2] {received_=0x052a0b88 "Client 2" }  channel::Buffer
....
....

我可以看到writeQueue_ { size=16777215 }的大小非常大,因此std::bad_alloc也是如此。

为什么会有这样的行为?我可以看到来自deque的代码弹出消息如下:

if (!error) { writeQueue_.pop_front(); if (!writeQueue_.empty()) { asio::async_write(socket_, asio::buffer(writeQueue_.front().received_, writeQueue_.front().buffsize), std::bind(&CSession::handle_write, this, std::placeholders::_1, std::placeholders::_2)); } }

所以write deque不应该长得这么大。

我的客户端应该运行几天,并且应该涉及大的连续数据写入。如何确保长写操作顺利进行?

你的消费者(CSession)比你的生产者(Client)慢得多。您的生产者正在通过尽可能快地生成消息来进行拒绝服务攻击。这是一个很好的测试。

你的消费者应该(至少一个,最好是所有):

  • 检测工作是否在累积,并在发生此类情况时设置策略,如"忽略新的"、"丢弃最旧的"
  • 通过对传入消息设置活动筛选器来限制消耗滞后
  • 改进传入消息处理的性能

我的客户应该要跑几天,应该大量参与连续数据写入。如何确保长写操作顺利进行?

然后你需要一个比网上的例子更好的代码。