2015-02-23 3 views
0

Я имею в виду Chat Clientоперация ASIO записи бросает зЬй :: bad_alloc: C++

Моя операция записи:

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; 
    } 
} 

Он отлично работает. Затем я попытался нагрузочное тестирование, сделав сообщение клиент записи Client 2 к непрерывно в течение 11 минут сервера, как показано ниже:

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)); }

Debug показывает:

-  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.

Почему такое поведение? Я могу увидеть код появляются сообщения, как показано ниже дека:

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 не выросли настолько велики.

Мой клиент должен работать в течение нескольких дней и должен быть связан с большими непрерывными данными. Как обеспечить гладкую длительную запись?

+0

Вы загружаете сообщения так быстро, как только можете, но сетевой стек не сможет пройти так быстро, поэтому очередь растет и растет. Мы не знаем, как структурирован ваш класс 'Buffer', но предположительно каждый экземпляр использует бит памяти, который все складывается. Вам нужно будет добавить ограничение скорости, если вы хотите сделать это реальным испытанием. –

+0

@JonathanPotter Буфер символов массива - \t 'структура буфера \t { \t \t перечисление {buffsize = 32}; \t \t char received_ [buffsize]; \t \t Buffer() {} \t \t Buffer (станд :: строка ул) \t \t { \t \t \t // Обрезать, если Переполнение \t \t \t авто Len = str.size(); \t \t \t, если (длина> = buffsize) \t \t \t { \t \t \t \t Len = buffsize - 1; \t \t \t} \t \t \t станд :: копия (str.begin(), str.begin() + длина, received_); \t \t \t received_ [str.size()] = '\ 0'; \t \t} \t}; 'Я полагаю, это самый простой буфер, который я могу сделать. У вас есть идея создания буферной структуры для лучшей производительности? –

ответ

0

Ваш потребитель (CSession) намного медленнее вашего производителя (Client). Ваш производитель делает атаку отказа в обслуживании, создавая сообщения так быстро, как только может. Это хороший тест.

Ваш потребитель должен (по крайней мере, один, в идеале все):

  • обнаружить, что работа аккумулирует и установить политику, когда происходят такие вещи, как «игнорировать новый», «падение старейшей»
  • Ограничьте задержку потребления, установив активный фильтр на входящие сообщения
  • Повысьте эффективность обработки входящих сообщений.

Мой клиент должен работать в течение нескольких дней и должен быть вовлечена большими непрерывной записи данных. Как обеспечить гладкую длительную запись?

Тогда вам нужен гораздо лучший код, чем пример, найденный в Интернете.

Смежные вопросы