[英]Reading JSON from a socket using boost::asio
我目前正在嘗試使用 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 處理整個文檔。 如何確保緩沖區包含足夠的數據?
這是應用層協議的區域
任何一個
Content-Length: 12346\\r\\n
這樣的標題來提前知道要讀取多少async_read_until
)ASIO Http 服務器示例包含一個非常好的模式,用於解析您可以使用的 HTTP 請求/標頭。 這假設您的解析器可以檢測完整性並且只是“軟失敗”,直到所有信息都存在。
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 的答案,之前使用 QJsonDocument 將子字符串解析為 JSON ; 您可以使用它來檢測正確 JSON 文檔的結尾(如果不完整,結尾將與開頭重合)
這里有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,您可以使用
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.