2011-03-11 117 views
4

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

在调用堆栈上,有一些关于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是一流的会议成员。

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

更新

我检测到的问题在其他地方我的代码奠定。 比线程完成任务后,调用do_writeMessage()metdhod 。

线程函数

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 
} 

所以finnally我有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; 
+0

我已经合并,这一个您未注册的帐户,您可以编辑您的问题。另外,我将你留下的答案和你的问题合并在一起。 – 2011-03-12 11:38:58

+0

@Lehu你为什么要在handle_read中启动一个线程? – 2011-03-12 14:02:09

+0

我的任务是:当我从客户端收到消息时,我必须在新线程中检索此消息,并且在线程完成工作时,应发送消息给客户端。 – Lehu 2011-03-12 14:17:26

回答

2

您需要使用prepareconsumecommit使用asio::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; 
+0

我更新了我的帖子。 – Lehu 2011-03-12 13:16:26

0

如果您正在使用async_read/async_read_until你不需要指定大小流缓冲,但确实需要确保你读入它是数据不大于最大允许尺寸。关于“迭代器出界”问题;我发现,告诉ASIO当它已经阅读阅读造成了到ASIO读取流缓冲导致的断言错误的竞争条件:

Assert “iterator out of bounds”

您可以使用类似:

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

以帮助同步您的线程,但是您必须小心,不要“包装”已经在运行并访问共享数据的内容。

HTH, 弗兰克