我正在构建客户端服务器通信。服务器发送Header + Data(使用async_write和单独的IO线程),Client接收固定大小的Header并知道它必须读取多少数据。
问题:有时客户端会收到错误的数据。似乎服务器发送了错误的数据。
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 :(得分: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。