Sign in to follow this  
Crazyfool

Std::string problems

Recommended Posts

Howdy - I've run into so many problems lately with strings and string parsings. I am trying to parse a string and everything works out fine till the last bit. When I go to parse the last bit at the end of the string, for some reason all hell comes loose. I can display the string, which shows my parsing right, I can load it into a std::stringstream and call the str() function fine. However, when I try to call the >> operator to convert it the an int, my program crashes.
//ss is an std::stringstream
ss << data.substr(data.find(",") + 1);
renderer.text.addChat(ss.str(), "Testing"); //fine, adds string to chat log
ss >> newEnt.z; //causes the error
I've tried several other methods of getting around this, but I just can't figure it out? This is at the end of my string, so I am thinking that it might be trying to go past the end? I dont know.. It displays fine though.. =( Error: Unhandled exception at 0x4fecb94b in ****.exe: 0xC0000005: Access violation reading location 0xccf07a00. Please help me figure this out! [Edited by - Crazyfool on December 31, 2007 12:36:17 PM]

Share this post


Link to post
Share on other sites
Aside from string messages being sub-optimal for network packages:

How exactly are you writing the string to the stream? .c_str() and length() or .c_str() and length() + 1 (the latter would add the 0 char).

Do you take in account, that packets can be received and sent in splits?

Show some code.

Share this post


Link to post
Share on other sites
Thank you for the response and I know my network messages are probably very sub optimal, but I feel if I were to make it very fast before I even have them working, itd probably create more harm than good.

Ok, well now I have kind of realized the std::string problem is only the last part in my previous post.


//ss is a std::stringstream
ss << data.substr(data.find(",") + 1);
ss >> newEnt.z;


That is where it goes bad. The data going into ss is fine, but when I push ss into newEnt.z, things go sour and give the error message listed in the first post. If you're wondering what I am doin, I am given a string message that basically looks something like this when received as parameter by the function:

"0:d34,2" where each number/letter represents a value and the ':' and ',' are there to break up data pieces.

I then break up each chunk, the '0' the 'd', the '34' and then '2', and everything is correct until 2. When I go to display each corresponding value, everything is fine, and when I display the ss.str without pushing its value into newEnt.z, it displays the right value as well.

I am completely baffled at this.

Quote:
Original post by Endurion
Do you take in account, that packets can be received and sent in splits?


Hm, I thought with tcp that this would NEVER happen. Well, it could happen, but it automatically fixes it for you. So I had assumed that (and every packet is the right format) each packet would be guranteed to be in the right format. I know packets can be mujshed together - when I send 10 messages toi the client one after another, it all gets put into the same packet thats received by the client, but my client splits each one into a seperate message for my network code to handle.

Share this post


Link to post
Share on other sites
Quote:
Hm, I thought with tcp that this would NEVER happen. Well, it could happen, but it automatically fixes it for you. So I had assumed that (and every packet is the right format) each packet would be guranteed to be in the right format. I know packets can be mujshed together - when I send 10 messages toi the client one after another, it all gets put into the same packet thats received by the client, but my client splits each one into a seperate message for my network code to handle.


With TCP, you'll receive a number of bytes. Boundaries are not preserved. If you call send() 10 times on server, the client might receive all 10 in one recv call, it might receive one at a time, or it might receive 10 bytes of first one, then 20 of first and 2 of second, then 1 byte of second, then remainder of second, 3rd, 4th and 5th, and on next recv the rest.

This is why you need to specify delimiters between packets - TCP is stream protocol. It has no concept of messages or packets. With UDP, every send() will be handled by either one or zero recv() calls (in case packet got lost).

The only thing TCP guarantees is that individual bytes will arrive in same order they were sent in. How many at a time however varies.

You're not likely to experience these problems over LAN, but over WANs, that's very common.

Share this post


Link to post
Share on other sites
Ok thanks, however the problem with std::string persists!

I appreciate you giving me a bit more insight on that, though =) I planned on keeping this to TCP because I heard it is a bit more reliable, and my game is going to be very small scale (tile based). I might end up going to UDP later but my main goal is to get things working, and then optimize.

Share this post


Link to post
Share on other sites
Quote:
Original post by Crazyfool
Ok thanks, however the problem with std::string persists!

I appreciate you giving me a bit more insight on that, though =) I planned on keeping this to TCP because I heard it is a bit more reliable, and my game is going to be very small scale (tile based). I might end up going to UDP later but my main goal is to get things working, and then optimize.



To build on what Antheus mentioned about delimiters, I would -highly- recommend buffering your messages and add in some debugging to find out why its failing. For instance... Anywhere you're doing a .find() for a specific character, output the string to a console/file first to make sure that character actually exists in the string. Honestly, you shouldn't be doing operations on the results of a .find unless you're certain the character is there, which you can't be with streaming data without a delimiter (sometimes even with one).

Here's a simple algorithm for processing network data -- this is not exactly code, just sorta-C++-pseudocode so you get the idea. I haven't tested this, so there may be a few off by one errors with my string handling ;)


string data;
string message;
const char delimiter = '!'; // I just chose something that I didnt think you were using
bool finished = false;

while(!finished)
{
data += data + getDataFromSocket(); //read data from socket, however much we can, add it to whatever was left last time
//check to see if we got at least one complete message
//while loop in case we got more than one message
while(data.find(delimiter) != string::npos)
{
//construct the message
message = data.substr(0,data.find(delimiter));
//do something with the message, this is where you'd do all the string handling you have already
processMessage(message);
//remove the message from your buffer
data = data.substr(data.find(delimiter) + 1, data.length - (data.find(delimiter) + 1));
//continue loop until all messages received have been processed
}
//at some point detect for finished and set it true to break the main loop.
//this might be some "end of game" command in your network protocol, or end of turn
}



Hope this might help a little!

--Rhalin

Share this post


Link to post
Share on other sites
I appreciate that a lot, and I definitely be reworking a lot of my code to handle bad situations better.

However, since I am doing this over a lan, I have not encountered any actual packet errors so all delimiters are always there (for now).

Right now, my problem is I have a std::string who is let's say, "23,23112:212-1."

Then I use std::string.erase() toget rid of everything but what's between '-' and '.' and it works beautifully. the string in this example is merely '1'. Ok, so now I put that into a std::stringstream and try to push it via >> to an integer - THAT is giving me the error.

Other errors are when I try to access characters (std::string.at(i), and yes i is in bounds)


What's VERY weird is this:


data.erase(0, data.find(":") + 1); //erases previous chunk

newEnt.x = -1 * str2int(data.substr(1, data.find(",") - 1)); //turns the value before the ',' to x


data.erase(0, data.find(",") + 1); //erases up the ','

ss << data; // this is fine
//ss.str() shows the right stuff, no extra characters, nothing

ss >> newEnt.z; //ERROR! crashes game, cant really debug right because of directx and it requires me to either restart computerr or alt f4 - hit enter and it shuts down vc2005

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this