2011-11-22 105 views
2

我是Boost新手。我正在開發一個小服務器。當客戶端向我的服務器發送消息時,我遇到了問題。我的服務器調用函數的套接字上讀兩遍Boost Asio插座問題

這是我的客戶端類

void ClientManager::ToRecv(void) 
{ 
    this->_socket.async_read_some(boost::asio::buffer(_buffer), 
    _strand.wrap(boost::bind(&ClientManager::HandleRead, this, boost::asio::placeholders::error)) 
    ); 
} 

void ClientManager::HandleRead(boost::system::error_code const & error) 
{ 
    _mutex.lock(); 
    std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl; 
    for (unsigned int i = 0; i < _buffer.size(); ++i) 
    { 
     std::cout << _buffer[i]; // I display the message 
    } 
    std::cout << std::endl; 
    _mutex.unlock(); 

    this->ToRecv(); 
} 

代碼當客戶端連接,我調用start功能。這是當我啓動我的服務器時在控制檯中顯示的內容:

我創建了3個主題。

Server Connect 
[004FE200] Thread Start 
[004FE238] Thread Start 
[004FE7C8] Thread Start 

,這是當我油灰客戶端連接到我的服務器

[004FE7C8] acceptor->NewClient() 
[004FE7C8] client->Start() 

,這是當客戶送什麼我的服務器顯示「Hello World」。

[004FE238] client->HandleRead() 
hello world 

[004FE7C8] client->HandleRead() 
llo world 

回答

1

我不知道是什麼類型_buffer是,但它可能應該是這樣的,注意bytes_transferred

void ClientManager::HandleRead(boost::system::error_code const & error, size_t bytes_transferred) 
{ 
     _mutex.lock(); 
     std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl; 
     for (unsigned int i = 0; i < bytes_transferred; ++i) 
     { 
      std::cout << _buffer[i]; // I display the message 
     } 
     std::cout << std::endl; 
     _mutex.unlock(); 

     this->ToRecv(); 
} 

什麼是互斥體?這是否真的需要?

我會寫它像:

void ClientManager::HandleRead(boost::system::error_code const & error, size_t bytes_transferred) 
{ 
    std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl; 
    std::copy(_buffer.begin(), _buffer.begin() + bytes_transferred, std::ostream_iterator<char>(std::cout)); 
    std::cout << std::endl; 
    this->ToRecv(); 
} 

現在,你可能會看到(和已經看到從下面的評論來看)是事實,HandleRead()將與唯一的部分被多次調用包括消息。如果在調用read函數之前知道消息的大小,則可以使用組合函數async_read()代替。這是boost::asio名稱空間中的一項免費功能。

+0

_buffer是一個boost ::陣列<炭,緩衝區大小>類型。 – RottenRonin

+0

我遵循你的建議,現在我的服務器不會顯示相同的消息兩次,但服務器再次調用HandleRead函數兩次。 – RottenRonin

+0

我該如何避免HandleRead的第二次調用? – RottenRonin

0

我想冒險猜測你初始化_buffer到某個地方的「Hello World」。

調用socket::async_read_some不保證在調用完成處理程序之前已經讀取了所有數據。您可以使用asio命名空間中的組合自由函數來完成此操作。

因此,可能發生的情況是,您在第一次調用處理函數時獲取了部分消息,第二次調用中收到了其他消息。但是,如果緩衝區已經被初始化,它會看起來像你收到消息兩次。

改變這一行也通過在佔位符傳輸的字節的數目:

_strand.wrap(
    boost::bind(
     &ClientManager::HandleRead, 
     this, 
     boost::asio::placeholders::error, 
     boost::asio::placeholders::bytes_transferred))); 

然後適當地改變您的HandleRead()功能:

void ClientManager::HandleRead(
    boost::system::error_code const & error, 
    size_t bytes_transferred) // Add bytes_transferred 
{ 
    _mutex.lock(); 
    std::cout << boost::this_thread::get_id() << " client->HandleRead()" << std::endl; 

    // Then -- check the buffer up to the number of bytes transferred: 
    for (unsigned int i = 0; i < bytes_transferred; ++i) 
    { 
     std::cout << _buffer[i]; // I display the message 
    } 
    std::cout << std::endl; 
    _mutex.unlock(); 

    this->ToRecv(); 
} 
+0

我遵循你的建議,現在我的服務器不會顯示相同的消息兩次,但服務器再次調用HandleRead函數兩次。 – RottenRonin

+0

如何避免HandleRead的第二次調用? – RottenRonin