我目前正在尝试使用boost-asio的套接字API通过网络将一些JSON数据从客户端传输到服务器。我的客户基本上是这样做的:
int from = 1, to = 2;
boost::asio::streambuf buf;
ostream str(&buf);
str << "{"
<< "\"purpose\" : \"request\"" << "," << endl
<< "\"from\" : " << from << "," << endl
<< "\"to\" : " << to << "," << endl
<< "}" << endl;
// Start an asynchronous operation to send the message.
boost::asio::async_write(socket_, buf,
boost::bind(&client::handle_write, this, _1));
在服务器端,我可以选择各种boost::asio::async_read*
功能。
我想使用JsonCpp来解析收到的数据。研究JsonCpp API(http://jsoncpp.sourceforge.net/class_json_1_1_reader.html)我发现Reader在std::string
,char *数组或std::istream
之上运行,我可以使用boost::asio::streambuf
进行操作传递到函数。
关键是,据我所知,不一定是整个内容一次传输的情况,所以我需要某种确认,缓冲区包含足够的数据来使用JsonCpp处理整个文档。如何确保缓冲区包含足够的数据?
答案 0 :(得分:7)
这是应用程序级协议的区域
要么
Content-Length: 12346\r\n
之类的标题,以提前知道要阅读的内容async_read_until
)ASIO Http服务器示例包含一个非常好的模式,用于解析您可以使用的HTTP请求/标头。这假设您的解析器可以检测到完整性并且只是软失败&#39;直到所有信息都存在。
void connection::handle_read(const boost::system::error_code& e,
std::size_t bytes_transferred)
{
if (!e)
{
boost::tribool result;
boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
request_, buffer_.data(), buffer_.data() + bytes_transferred);
if (result)
{
request_handler_.handle_request(request_, reply_);
boost::asio::async_write(socket_, reply_.to_buffers(),
boost::bind(&connection::handle_write, shared_from_this(),
boost::asio::placeholders::error));
}
else if (!result)
{
reply_ = reply::stock_reply(reply::bad_request);
boost::asio::async_write(socket_, reply_.to_buffers(),
boost::bind(&connection::handle_write, shared_from_this(),
boost::asio::placeholders::error));
}
else
{
socket_.async_read_some(boost::asio::buffer(buffer_),
boost::bind(&connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
else if (e != boost::asio::error::operation_aborted)
{
connection_manager_.stop(shared_from_this());
}
}
我提供了一个使用Boost Spirit解析JSON的答案Parse a substring as JSON using QJsonDocument;您可以使用它来检测正确的JSON文档的结尾(如果它不完整,结束将与开始一致)
答案 1 :(得分:0)
这里有2个问题:1)告诉服务器要读取多少字节; 2)读取JSON
对于1)您可以制作自己的简单协议
300#my message here
发送300字节大小的消息; #是大小和消息之间的分隔符
int write_request(socket_t &socket, const char* buf_json)
{
std::string buf;
size_t size_json = strlen(buf_json);
buf = std::to_string(static_cast<long long unsigned int>(size_json));
buf += "#";
buf += std::string(buf_json);
return (socket.write_all(buf.data(), buf.size()));
}
在服务器上阅读
//parse header, one character at a time and look for for separator #
//assume size header lenght less than 20 digits
for (size_t idx = 0; idx < 20; idx++)
{
char c;
if ((recv_size = ::recv(socket.m_sockfd, &c, 1, 0)) == -1)
{
std::cout << "recv error: " << strerror(errno) << std::endl;
return str;
}
if (c == '#')
{
break;
}
else
{
str_header += c;
}
}
要读取JSON,可以使用