I am reading data from a asio socket in c .
I need to parse the incoming data as json. To do this, i need to get a single json string entry. I am adding a character ';' at the end of the json string, now i need to split at that character on read. i am trying this:
int main()
{
asio::io_service service;
asio::ip::tcp::endpoint endpoint(asio::ip::address::from_string("127.0.0.1"), 4444);
asio::ip::tcp::socket socket(service);
std::cout << "[Client] Connecting to server..." << std::endl;
socket.connect(endpoint);
std::cout << "[Client] Connection successful" << std::endl;
while (true)
{
std::string str;
str.resize(2048);
asio::read(socket, asio::buffer(str));
std::string parsed;
std::stringstream input_stringstream(str);
if (std::getline(input_stringstream, parsed, ';'))
{
std::cout << parsed << std::endl;
std::cout<<std::endl;
}
}
}
But it gives me random sections of the string.
The full message is: (for testing, not json formatted)
this is the message in full, no more no less ;
and I get:
full, no more no less
this is the message in full, no more no less
ull, no more no less
is is the message in full, no more no less
l, no more no less
is the message in full, no more no less
no more no less
Where am i going wrong here?
Thanks!
CodePudding user response:
I'd use read_until
:
#include <boost/asio.hpp>
#include <iostream>
#include <iomanip>
namespace asio = boost::asio;
using asio::ip::tcp;
int main()
{
asio::io_service service;
tcp::socket socket(service);
socket.connect({{}, 4444});
std::string str;
while (auto n = asio::read_until(socket, asio::dynamic_buffer(str), ';')) {
std::cout << std::quoted(std::string_view(str).substr(0, n - 1)) << std::endl;
str.erase(0, n);
}
}
For example with a sample server:
paste -sd\; /etc/dictionaries-common/words | netcat -l -p 4444
Output is:
"A"
"A's"
"AMD"
"AMD's"
"AOL"
"AOL's"
"Aachen"
"Aachen's"
"Aaliyah"
"Aaliyah's"
"Aaron"
"Aaron's"
"Abbas"
"Abbas's"
"Aberdeen's"
...
"zucchinis"
"zwieback"
"zwieback's"
"zygote"
"zygote's"
"zygotes"
"Ångström"
"Ångström's"
"éclair"
"éclair's"
"éclairs"
"éclat"
"éclat's"
"élan"
"élan's"
"émigré"
"émigré's"
"émigrés"
"épée"
"épée's"
"épées"
"étude"
"étude's"
Additional hints
You can use any dynamic buffer. Here's streambuf
:
for (asio::streambuf buf; auto n = asio::read_until(socket, buf, ';');) {
std::cout << std::string_view(
asio::buffer_cast<char const*>(buf.data()), n)
<< std::endl;
buf.consume(n);
}
Or, hybrid, showing that dynamic_string_buffer
models the same concept as streambuf
:
std::string str;
for (auto buf = asio::dynamic_buffer(str);
auto n = asio::read_until(socket, buf, ';');) {
std::cout << std::string_view(
asio::buffer_cast<char const*>(buf.data()), n)
<< std::endl;
buf.consume(n);
}
Or also:
std::vector<unsigned char> vec;
for (auto buf = asio::dynamic_buffer(vec);
auto n = asio::read_until(socket, buf, ';');) {
std::cout << std::string_view(
asio::buffer_cast<char const*>(buf.data()), n)
<< std::endl;
buf.consume(n);
}