【问题标题】:boost::asio::streambuf asserts "iterator out of bounds"boost::asio::streambuf 断言“迭代器越界”
【发布时间】:2019-02-16 16:01:13
【问题描述】:

客户端向服务器发送大约 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;

更新

我检测到问题出在我的代码的其他位置。 在线程完成任务之后,方法 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
}

所以最后我遇到了 asynch_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;

【问题讨论】:

  • 我已将您未注册的帐户与此帐户合并,您现在可以编辑您的问题。此外,我将您留下的答案与您的问题合并。
  • @Lehu 为什么要在handle_read 中启动线程?
  • 我的任务是:当我收到来自客户端的消息时,我必须在新线程中检索此消息,并且当线程完成工作时,应该向客户端发送消息。
  • @Sam。这个帖子问题严重吗?
  • @Lehu 您可能与附加线程存在竞争条件。 再次,我不清楚为什么需要单独的线程。为什么retriveMessageFromClient做的工作不能在Session::handle_read做?异步编程很棘手,引入线程使其更加困难。我强烈建议您删除额外的线程并专注于使单线程方案正常工作。我在您之前的一个问题中提出了这个same comment

标签: c++ boost boost-asio


【解决方案1】:

在使用asio::streambuf 从套接字读取和写入时,您需要使用prepareconsumecommit。文档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;

【讨论】:

    【解决方案2】:

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

    断言“迭代器越界”

    你可以使用类似的东西:

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

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

    HTH

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-02
      • 2011-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-26
      • 2016-10-19
      • 1970-01-01
      相关资源
      最近更新 更多