Handling Input from boost::asio

Hi,

I have a boost::asio server that reads into a boost::asio::streambuf with boost::asio::async_read_until that looks something like this:

1
2
boost::asio::async_read_until(connection->getSocket(), buffer, '\n', boost::bind(&Server::handleReadFromSocket, this, boost::asio::placeholders::error,
		boost::asio::placeholders::bytes_transferred, connection));


The callback &Server::handleReadFromSocket takes the boost::asio::streambuf and assigns it to a string. That looks like this:

unsanitizedInput.assign(std::istreambuf_iterator<char>(&buffer), std::istreambuf_iterator<char>());

From there, I found out that the above statement would also copy the '\n' from the buffer, so I used a statement like this to remove it:

unsanitizedInput.erase(std::remove(unsanitizedInput.begin(), unsanitizedInput.end(), '\n'), unsanitizedInput.end());

Then I do a simple check to see if the unsanitized input is equal to "yes" that looks like this:

if(unsanitizedInput == "yes") {do something}

In cases where unsanitizedInput APPEARS to exactly match "yes", that statement STILL resolves to false. (I am both the client and server, and I exactly type yes into the client)

Until I do something like:

suppliedInput.erase(std::remove_if(suppliedInput.begin(), suppliedInput.end(), [](char c) { return !isalpha(c); }), suppliedInput.end());

Which is to say, it seems like there is something in the unsanitizedInput that isn't being shown when I std::cout it, but interferes with the equality statement.

My question is: What?



Can you use a debugger to prove your theory (it's sound)? Could this be the infamous "carriage return / line feed" thing, maybe a tab, who knows....find out
Last edited on
Hi Niccolo.

Thanks for your reply.

Here is a screenshot of the function:
https://files.constantcontact.com/2d731cd6201/cf927a07-fd70-48a3-aa74-89dbb678ce16.png

Here is a screenshot of the client input: https://files.constantcontact.com/2d731cd6201/04a46eb0-9619-4923-8080-1718a6198e59.png

Here is a screenshot of the server output:
https://files.constantcontact.com/2d731cd6201/dba9c55d-3d42-4c4b-85e3-7975ccb2a980.png

Notice in the function that I output what I receive, output a boolean expression to see if they're equal. And I see "yes" and "0" meaning, I'm getting "yes" but "0" is false...they're not equal.
Niccolo's probably right about that carriage return (especially if you are on Windows). Try replacing your code to remove the newline with this:

1
2
if (input.back()) == '\n') input.pop_back();
if (input.back()) == '\r') input.pop_back();

Last edited on
@Aaron Vienneau,

You've not quite "got" my meaning here.

What we see on a console doesn't tell us what is actually in a string. It shows printable characters, but as you might already know you can't see spaces (other than the room they occupy), so trailing spaces (literally "yes " instead of "yes") can't be seen in a screen shot.

What I suggest (and what I asked) is that you use a debugging tool to examine the binary content of the string before the comparison (likely even before you clean it up) to understand what content is arriving in the buffers.

Put another way, if I'm trying to get a temperature and someone tells me "it's hot", I'm not getting an answer. If I then get a response, "It's about 105 degrees out here", I'm still not getting an answer because it isn't from an instrument. In order to get a temperature I must get a reading from a thermometer.

The debugger is similar. It gives us x-ray vision of detailed, actual information. When you look at the content of the buffer in a debugger you'll see what is being tested, not what is being displayed. There could be a huge difference.
Hi Dutch,

I'm currrently doing an erase for both of those characters and it's still not working. Is there something that will allow cout to print non-standard characters to the console so I can see what's causing the interference?

I could, of course, just use remove_if !isalpha() but I want to actually know what's causing it before I make such a sweeping fix.
Even if you did cause cout to "print" non-printable characters (notice the contradiction), you probably wouldn't have any more actual information to work with.

Try something like:

std::for_each( s.begin(), s.end(), [](char &n){ std::cout << static_cast<int>( n )<< std::endl; });

Assuming "s" is a standard string. If you prefer hex

std::for_each( s.begin(), s.end(), [](char &n){ std::cout << std::hex << "0x" << static_cast<int>( n )<< std::endl; });

Of course, if you used a debugger, it would just show you.
Last edited on
Is there something that will allow cout to print non-standard characters to the console so I can see what's causing the interference?

How about:

 
for (auto ch: input) std::cout << int(ch) << '\n';


EDIT: Oh, Niccolo already said that ... of course. :-) I also concur with the suggestion to learn to use a debugger, which is generally more useful.
Last edited on
Hi Niccolo,

Perhaps I'm confused. You asked me to "prove my theory [that there is something in the unsanitizedInput that isn't being shown when I std::cout it, but interferes with the equality statement]".

If I could do that I wouldn't be posting here. Hahaha.

So, I guess my question becomes: Do you have a suggested way of debugging the string in the fashion you mentioned with GCC?

Or is there a simpler way of outputing/revealing non-standard characters to the std::cout stream?
Right, I guess it was just assumed that I didn't know how to use a debugger since...if I did, I probably just would've used it and not posted here. Haha.
Hey @Aaron Vienneau,

We see a lot of questions from a wide range of people, and some have a tool right in front of them they simply don't try that would make their life much easier. My suggestion was intended to prompt one of two responses, either "oh, I forgot" kind of response that is quite common, or "I don't have/know/use debuggers". Either moves in a productive direction.

Put another way, though, the kind of individual capable of implementing Asio just aren't what we expect to be unfamiliar with debuggers. Asio isn't introductory level, and by the time skills for such work are developed the programmer is usually familiar with a wide range of tools.

The code @dutch and I suggest prints the numeric value of each entry in the string, which is exactly the information required to understand what's happening, but the notion of "debugging" code like this goes back to the 70's and before. It's old school, and it works, but it's slower than using a debugger for the same result.

GCC is just a compiler. A debugger is a separate tool, usually part of an IDE in modern work. What IDE are you using (if one)?
Last edited on
Hi Niccolo and Dutch,

Thanks for your suggested cast-to-int approach. It's definitely more telling as:

for (auto ch: unsanitizedInput) std::cout << int(ch) << '\n'; // Outputs: 0 0 0 0 0 0 121 101 115 13 10
for (auto ch: "yes") std::cout << int(ch) << '\n'; // Outputs 121 101 115 0 0

It's clear from this output that these are not equal and that a carriage return and null line-feed are indeed in the string (prior to removal), but also that unsanitizedInput contains a prefix of null characters. This is exactly what I needed :)

From here, I can figure out how to only extract the necessary bytes from asio::streambuf and put it into the unsanitizedInput.

As for an IDE, I don't actually use one of those....Just GCC and Sublime....compile and run in my terminal on Mac. I used to use Visual Studios on windows which would probably make this a lot easier. I'll see if I can't find a debugging tool to integrate into my workflow...

I've not used it for this, but Visual Code can run on the MAC, and I'm told it can be configured to become a rather full IDE (though not like Visual Studio).

XCode on the MAC can do this, though I'm not fond of XCode's interface myself.

Eclipse or IntelliJ might be fair choices.

There is a Visual Studio for OS X - haven't tried it.

There's CLion. No info.

I think CodeBlocks can run on MAC - not familiar, really.

I'm not certain as I haven't used Asio for a few years, but I think (I vaguely recall) that this kind of finding suggests that the Asio buffer isn't being parsed out quite correctly. I could be off here, but leading zeros hint at some buffer misalignment as it tries to pull out data from packets.
Last edited on
Cool. Thanks.

std::istream(&buffer) >> unsanitizedInput; looks promising, but I'll have to do more testing.

Thanks for the help!
This is what I use for clipboards.
1
2
3
4
5
6
7
void deleteControls ( std::string& startstring )
{
  startstring.erase(std::remove_if(startstring.begin(),startstring.end(),
    [](char _1){
      return _1 != '\n' && (_1 < (char)32 || _1 == (char)127 );
    }), startstring.end());
}


You could also just compare the strings together using string::compare, and testing if it returns a positive value, meaning you don't care about garbage data like "yesabdybwayd" == "yes". And also making sure you keep the global string lowercase, and covert the inputted text to be lowercase with lower(ch) (this can be streamlined into a function).

But I would recommend you to avoid using strings in places that don't require it, so a yes/no could be a bool, and "playable classes" could be an enum, and before you ask the player which class he wants to pick, print all the classes with each index associated with it. This is also nice since the error management on the server side is as easy as testing if the value is a bool, done. Or testing if it is an int, and check the range, done.
Last edited on
Topic archived. No new replies allowed.