boost :: asio :: streambuf断言“迭代器越界”

问题描述 投票:4回答:2

客户端向服务器发送大约165kB的数据。起初一切都很好。但是当客户端再次发送相同的数据(165kB)时,我在服务器端收到一个断言。断言包含有关“迭代器越界”的信息

在调用堆栈上,有一些关于read_until方法的信息。所以我认为我犯了一个错误。

TCP异步服务器代码如下:

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

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

m_bufferRead,m_bufferWrite都是Session类的成员。

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

更新

我发现问题出现在我的代码的其他地方。在线程完成任务之后,调用metdhod do_writeMessage()。

线程功能

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

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
}

所以最后我遇到了async_send的问题......

更新

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

会员

     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;
c++ boost boost-asio
2个回答
2
投票

当使用prepare从套接字读取和写入时,您需要使用consumecommitasio::streambuf。文档describes以及一个例子。如果您这样做,基于您的示例代码对我来说并不明显。

写作

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

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;

1
投票

如果您使用的是async_read / async_read_until,则无需为streambuf指定大小,但需要确保读入的数据不大于最大允许大小。关于“迭代器越界”问题;我发现告诉asio在读取时已经读取会导致asio读取的streambuf的竞争条件导致断言错误:

断言“迭代器超出范围”

您可以使用以下内容:

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

帮助同步你的线程,但你必须小心,不要“包装”已经运行的访问共享数据的东西。

HTH

© www.soinside.com 2019 - 2024. All rights reserved.