【发布时间】:2017-05-13 20:47:42
【问题描述】:
我想通过 boost asio 将 shared_ptr 对象从客户端传输到服务器。这是我的代码:
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/asio.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <chrono>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
using namespace std;
class Message {
public:
Message() {
}
virtual ~Message() {
}
string text;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar &text;
}
};
BOOST_CLASS_EXPORT(Message)
void runClient() {
// Give server time to startup
this_thread::sleep_for(chrono::milliseconds(3000));
boost::asio::ip::tcp::iostream stream("localhost", "3000");
boost::archive::text_oarchive archive(stream);
for (int i = 0; i < 10; i++) {
std::shared_ptr<Message> dl = std::make_shared<Message>();
stringstream ss;
ss << "Hello " << i;
dl->text = ss.str();
archive << dl;
}
stream.close();
cout << "Client shutdown" << endl;
}
void handleIncommingClientConnection(boost::asio::ip::tcp::acceptor &acceptor) {
boost::asio::ip::tcp::iostream stream;
acceptor.accept(*stream.rdbuf());
boost::archive::text_iarchive archive(stream);
while (true) {
std::shared_ptr<Message> m;
try {
archive >> m;
cout << m->text << endl;
} catch (std::exception &ex) {
cout << ex.what() << endl;
if (stream.eof()) {
cout << "eof" << endl;
stream.close();
cout << "Server: shutdown client handling..." << endl;
break;
} else
throw ex;
}
}
}
void runServer() {
boost::asio::io_service ios;
boost::asio::ip::tcp::endpoint endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 3000);
boost::asio::ip::tcp::acceptor acceptor(ios, endpoint);
handleIncommingClientConnection(acceptor);
}
int main(int argc, char **argv) {
thread clientThread(runClient);
thread serverThread(runServer);
clientThread.join();
serverThread.join();
return 0;
}
这是程序输出:
Hello 0
Hello 1
Hello 2
Hello 3
Hello 3
Hello 3
Hello 3
Hello 3
Client shutdown
Hello 3
Hello 3
input stream error
eof
Server: shutdown client handling...
我期待以下输出:
Hello 0
Hello 1
Hello 2
Hello 3
Hello 4
Hello 5
Hello 6
Hello 7
Client shutdown
Hello 8
Hello 9
input stream error
eof
Server: shutdown client handling...
将shared_ptr 更改为简单对象(std::shared_ptr<Message> m; 至Message m)时,一切都按预期工作。我想坚持shared_ptr。我需要改变什么?
仅序列化似乎有效:
stringstream stream;
{
boost::archive::text_oarchive archive(stream);
std::shared_ptr<Message> dl = std::make_shared<Message>();
stringstream ss;
ss << "Hello World!";
dl->text = ss.str();
archive << dl;
}
{
boost::archive::text_iarchive archive(stream);
std::shared_ptr<Message> m;
archive >> m;
cout << m->text << endl;
}
输出:Hello World!
【问题讨论】:
-
问题是您销毁旧消息并在每次迭代时创建一个新消息。正如在您的情况下发生的那样,在第 4 次迭代之后,新的消息对象被分配在同一地址 - 在我对 coliru 的测试中,所有消息对象都发生了这种情况。您可以通过打印
dl.get()的值来轻松验证这一点。 -
现在,为什么这是一个问题?原始指针是序列化框架如何判断两个共享指针是否指向同一个对象。 (检查档案的内容)。基本上,要求所有共享指针在整个序列化序列之前指向某些对象,并且在序列期间不被修改(或者至少你已经序列化的任何东西都不应该改变,并且唯一对象需要具有唯一性地址)。
-
你去。请仔细阅读文档,他们非常清楚。我以前没有使用过这个特定的库,绝对不是在这种情况下,并且挖掘参考来写答案证实了我从基于 cmets 的实验中得出的结论。感谢您提出一个有用的问题:)
-
您可能应该问自己为什么要假装您正在序列化共享对象,而事实上您不是。这是错误的来源。
标签: boost boost-asio boost-serialization