Boost :: asio :: streambuf claims "iterator out of bounds"

The client sends about 165 KB of data to the server. At first everything is fine. But when the client sends the same data again (165 KB), I get a server-side approval. Assert contains information about an "iterator beyond borders"

The call stack has some information about the read_until method. Therefore, I think I made a mistake.

The asynchronous TCP server code is below:

Code for handle_read :

 void Session::handle_read(const boost::system::error_code& a_error, size_t a_nbytestransferred) { if (!a_error) { std::ostringstream dataToRetrive; dataToRetrive << &m_bufferRead; boost::thread threads(boost::bind(retriveMessageFromClient, shared_from_this(), dataToRetrive.str())); boost::asio::async_write(m_socket, m_bufferWrite, boost::bind(&Session::handle_write, shared_from_this(), boost::asio::placeholders::error)); } else disconnect(); } 

Code for handle_write :

 void Session::handle_write(const boost::system::error_code& a_error) { if (!a_error) { boost::asio::async_read_until(m_socket, m_bufferRead, boost::regex(G_strREQUESTEND), boost::bind(&Session::handle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else disconnect(); } 

Both m_bufferRead, m_bufferWrite are members of the Session class.

 class Session... boost::asio::streambuf m_bufferRead; boost::asio::streambuf m_bufferWrite; 

Update

I found that the problem lies elsewhere in my code. After completing the finishing tasks, metdhod do_writeMessage () is called.

Stream function

 void retriveMessageFromClient(boost::shared_ptr<Session>& A_spSesion, std::string A_strDataToRetrive) { try { std::string strAnswer; bool bFind = (A_strDataToRetrive.find(G_REGEX_BIG_FILE_BEGIN) != std::string::npos); if(bFind) // Write large data to osFile { A_strDataToRetrive = boost::regex_replace(A_strDataToRetrive, boost::regex(G_REGEX_BIG_FILE_BEGIN), std::string("")); std::string strClientFolder = str(boost::format("%1%%2%") % CLIENT_PRE_FOLDER_FILE % A_spSesion->getIdentifier()); std::string strClientFile = str(boost::format("%1%\\%2%%3%") % strClientFolder % strClientFolder % CLIENT_EXTENSION); if ( boost::filesystem::exists(strClientFolder) ) boost::filesystem::remove_all(strClientFolder); else boost::filesystem::create_directory( strClientFolder ); std::ofstream osFile(strClientFile.c_str()); osFile << A_strDataToRetrive; osFile.close(); strAnswer = str(boost::format(G_FILE_WAS_WRITE) % strClientFile); } else { double dResult = sin (30.0 * 3.14/180); strAnswer = str(boost::format(G_OPERATION_RESULT) % dResult); } // Sleep thread boost::xtime timeToSleep; boost::xtime_get(&timeToSleep, boost::TIME_UTC); timeToSleep.sec += 2; boost::this_thread::sleep(timeToSleep); A_spSesion->do_writeMessage(strAnswer); } catch (std::exception& e) { std::cerr << THREAD_PROBLEM << e.what() << "\n"; } } 

Do_writeMessage session

 void Session::do_writeMessage(const std::string& A_strMessage) { m_strMessage = A_strMessage; m_strMessage += G_strRESPONSEEND; // m_socket.send(boost::asio::buffer(m_strMessage)); It works correctly m_socket.async_send(boost::asio::buffer(m_strMessage), boost::bind(&Session::handle_write, shared_from_this(), boost::asio::placeholders::error)); -- after that assert } 

So I have a problem with asynch_send ...

UPDATED

 **TCPAsyncServer**::TCPAsyncServer(boost::asio::io_service& A_ioService, short port, : m_ioService(A_ioService), m_lIDGenerator(0), m_clientSocket(m_ioService, tcp::endpoint(tcp::v4(), port)), { SessionPtr newSession(new Session(m_ioService, m_mapSessions, ++m_lIDGenerator)); m_clientSocket.async_accept(newSession->getSocket(), boost::bind(&TCPAsyncServer::handle_ClientAccept, this, newSession, boost::asio::placeholders::error)); 

Session Contractor

 Session::Session(boost::asio::io_service& A_ioService, std::map<long, boost::shared_ptr<Session> >& A_mapSessions, long A_lId) : m_socket(A_ioService), m_mapSessions(A_mapSessions), m_lIdentifier(A_lId), m_ioService(A_ioService) {} 

Members of the session

  std::map<long, boost::shared_ptr<Session> >& m_mapSessions; long m_lIdentifier; boost::asio::ip::tcp::socket m_socket; boost::asio::io_service& m_ioService; 
+4
source share
2 answers

When using asio::streambuf to read and write from a socket, you need to use prepare , consume and commit . The documentation describes this with an example. This is not obvious to me based on your sample code if you do this.

write

 boost::asio::streambuf b; std::ostream os(&b); os << "Hello, World!\n"; // try sending some data in input sequence size_t n = sock.send(b.data()); b.consume(n); // sent data is removed from input sequence 

reading

 boost::asio::streambuf b; // reserve 512 bytes in output sequence boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512); size_t n = sock.receive(bufs); // received data is "committed" from output sequence to input sequence b.commit(n); std::istream is(&b); std::string s; is >> s; 
+2
source

If you use async_read / async_read_until, you do not need to specify a size for streambuf, but you need to make sure that the data you are reading does not exceed the maximum size allowed. Regarding the “iterator beyond borders” problem; I found that the asio read message, when it is already reading, causes a race condition for streambuf, for which asio is being read, which leads to an assertion error:

Approve "iterator beyond borders"

You can use something like:

strand_.wrap (boost :: bind (& your_class :: handle_read, this, asio :: placeholders :: error, asio :: placeholders :: bytes_transferred)));

to synchronize your threads, but you have to be careful not to “wrap” something that is already running with access to shared data.

NTN, Frank

0
source

Source: https://habr.com/ru/post/1343394/


All Articles