Пишу пару TCP сервер-клиент с boost asio. Это очень просто и синхронно.
Предполагается, что сервер передает большое количество двоичных данных посредством нескольких рекурсивных вызовов функции, которая передает пакет данных по протоколу TCP. Клиент делает то же самое, читая и добавляя данные через рекурсивную функцию, которая считывает входящие пакеты из сокета.
Однако в середине получения этих данных в большинстве случаев (около 80%) клиент просто внезапно останавливает рекурсию, всегда перед одним из вызовов чтения (показано ниже). Этого не должно быть, учитывая, что после рекурсии есть несколько других операторов и вызовов функций.
size_t bytes_transferred = m_socket.read_some(boost::asio::buffer(m_fileReadBuffer, m_fileReadBuffer.size()));
m_fileReadBuffer — это boost::массив символов размером 4096 (хотя я пробовал и другие форматы буферов, но безуспешно).
Я совершенно не могу понять, почему это происходит.
- Программа завершается немедленно, поэтому я не могу передать код ошибки в read_some и прочитать все сообщения об ошибках, так как это должно произойти после оператора read_some.
- Исключения не выбрасываются
- Нет ошибок или предупреждений во время компиляции/выполнения
- Если я ставлю точки останова внутри рекурсивной функции, проблема никогда не возникает (передача завершается успешно)
- Если я ставлю точки останова после передачи или прерываю выполнение в цикле while после передачи, проблема никогда не возникает, и нет никаких признаков того, что что-то не так.
Также важно отметить, что сервер ВСЕГДА успешно отправляет все данные. Кроме того, проблема всегда возникает в самом конце передачи: я могу отправить 8000 байт, и он завершится, когда будет передано около 6000 или 7000 байт, и я могу отправить 8000000 байт, и он завершится, когда будет что-то вроде 7996000 байт. были переведены.
Я могу предоставить любой необходимый код, я просто понятия не имею, где может быть проблема. Ниже показана функция рекурсивного чтения на клиенте:
void TCP_Client::receive_volScan_message()
{
try
{
//If the transfer is complete, exit this loop
if(m_rollingSum >= (std::streamsize)m_fileSize)
{
std::cout << "File transfer complete!\n";
std::cout << m_fileSize << " "<< m_fileData.size() << "\n\n";
return;
}
boost::system::error_code error;
//Transfer isn't complete, so we read some more
size_t bytes_transferred = m_socket.read_some(boost::asio::buffer(m_fileReadBuffer, m_fileReadBuffer.size()));
std::cout << "Received " << (std::streamsize)bytes_transferred << " bytes\n";
//Copy the bytes_transferred to m_fileData vector. Only copies up to m_fileSize bytes into m_fileData
if(bytes_transferred+m_rollingSum > m_fileSize)
{
//memcpy(&m_fileData[m_rollingSum], &m_fileReadBuffer, m_fileSize-m_rollingSum);
m_rollingSum += m_fileSize-m_rollingSum;
}
else
{
// memcpy(&m_fileData[m_rollingSum], &m_fileReadBuffer, bytes_transferred);
m_rollingSum += (std::streamsize)bytes_transferred;
}
std::cout << "rolling sum: " << m_rollingSum << std::endl;
this->receive_volScan_message();
}
catch(...)
{
std::cout << "whoops";
}
}
В качестве предложения я попытался изменить рекурсивные циклы на циклы for как на клиенте, так и на сервере. Проблема почему-то сохраняется. Единственное отличие состоит в том, что теперь вместо 0 перед ранее упомянутым вызовом read_some он выходит из 0 в конце одного из блоков цикла for, как раз перед началом выполнения другого прохода цикла for.
РЕДАКТИРОВАТЬ: Как оказалось, ошибка не возникает всякий раз, когда я строю клиент в режиме отладки в своей среде IDE.