开发者

boost::asio::streambuf asserts "iterator out of bounds"

开发者 https://www.devze.com 2023-02-16 20:49 出处:网络
Client sends to server near about 165kB of data. At first all is fine. But when client send the same data once again(165kB), I receive an assert on server side.

Client sends to server near about 165kB of data. At first all is fine. But when client send the same data once again(165kB), I receive an assert on server side. Assert contains information about "iterator out of bounds"

On the call stack, there is some information about read_until method. So I think that I made a mistake.

TCP Asynchronous 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 class Session.

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

Update

I detected that problem is layed in other place of my code. After than thread finishs tasks, metdhod do_writeMessage() is called.

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

Session do_writeMessage

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 finnally 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 contructor

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

Session members

     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;


You need to use prepare, consume, and commit when using asio::streambuf to read and write from a socket. The documentation describes this with an example. It's not obvious to me based on your sample code if you are doing that.

writing

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;


If you are using async_read / async_read_until you don't need to specify a size for streambuf but do need to ensure the data you read into it is not greater than it maximum allowed size. In relation to the “iterator out of bounds” issue; I have found that telling asio to read when it's already reading causes a race condition for the streambuf to which asio reads which results in the assertion error:

Assert “iterator out of bounds”

You can use something like:

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

to help synchronize your threads but you must be careful not to 'wrap' something that is already running with access to shared data.

HTH

0

精彩评论

暂无评论...
验证码 换一张
取 消