2014-01-27 57 views
1

我正在構建客戶端服務器通信。服務器發送Header + Data(使用async_write和一個單獨的IO線程),客戶端接收固定大小的Header並知道需要讀取多少數據。Boost Asio - 郵件內容傳輸錯誤

問題:有時客戶端收到錯誤的數據。這似乎是服務器發送錯誤的數據。

void Session::do_write(std::shared_ptr<DataItem> data) 
{ 
    std::lock_guard<std::mutex> lk(doWrite_mutex); 

    std::vector<boost::asio::const_buffer> buffers; 
    buffers.push_back(boost::asio::buffer(&data->length, sizeof(uint32_t))); 
    buffers.push_back(boost::asio::buffer(&data->callbackID, sizeof(uint8_t))); 
    buffers.push_back(boost::asio::buffer(&data->isString, sizeof(bool))); 
    //Get the data to send into the buffer and make sure the given shared ptr to the data item keeps living until this function is finished. 
    buffers.push_back(boost::asio::buffer(data->getData(), data->length)); 

    boost::asio::async_write(*socket_, buffers, boost::bind(&Session::onSend, this, data, _1,_2)); 
} 

    void Session::onSend(std::shared_ptr<DataItem> data,const boost::system::error_code ec, std::size_t length) 
{ //Some logging, nothing special here 
} 

該數據項是一個多態類,用於處理不同種類的數據(向量,字符串...)。 getData()方法將const void*返回到實際數據(例如在矢量的情況下爲myData->data())。數據在DataItem中保存爲shared_ptr(以防止其被銷燬)。

在大多數情況下,數據傳輸是正確的。

我不知道在哪裏調試或我做錯了什麼。

+0

」好像服務器發送了錯誤的數據。「你應該驗證一下。 – PlasmaHH

+0

我在'onSend'中驗證了'data'中的數據仍然正確,正如預期的那樣。 – Till

+0

我更像是在電線上思考。 – PlasmaHH

回答

3

在具有未完成的async_write()操作的流上調用寫入操作未能滿足async_write()的要求,這會導致交織的數據。此外,如果多個線程正在服務io_service事件循環,或者從未處理事件循環的線程調用Session::do_write(),則使用互斥鎖將無法滿足流的線程安全要求。此answer演示使用隊列來序列化多個async_write()操作,並在strand內使用異步調用鏈處理隊列,同時滿足async_write()的要求和流的線程安全性。

有關更多詳細信息,async_write()函數是一個組合操作,導致零個或多個調用流的async_write_some()函數。因此,如果程序不確保該流在未完成的操作完成之前不執行其他寫入操作,則中間寫入操作可以在其他寫入操作之間混合,從而導致交織的數據。此外,這些中間操作在流上調用async_write_some()而未獲取doWrite_mutex,這可能違反流的線程安全要求。有關組合操作和strand用法的更多信息,請考慮閱讀此answer。 「