2011-03-11 113 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, 弗蘭克