Advertisement

Getting error when receiving with SDLNet

Started by February 23, 2016 09:14 PM
3 comments, last by dilyan_rusev 8 years, 9 months ago

About 4 month ago i started learning sdl2 to make simple games. I am familiar with all sdl family (sdl image, sdl ttf...). The thing is that now i want to implement multiplayer to my game, so i want to use SDL2Net. For the basics was fine, but i need to send vectors through packages, so i would need to implement serialization or a protocol buff, so i chose protobuf (Google Protocol Buff). My game was going to be like a snake but multiplater. So the client would send the position of his snake parts and the server would send the position of every client parts (and from himself, the server also plays). At start everything was fine but now i dond't know why i am getting error. I will leave part of source code where i get trouble:

"network.protobuf"

package network;

message PositionSnakePart {
required int32 pos_x = 1;
required int32 pos_y = 2;
}

message Snake
{
optional int32 id = 1;
repeated PositionSnakePart positionsnakepart = 2;
}

message FromServerToClient
{
required bool gameover = 1 [default = false];
repeated Snake snakes_game = 2;
}

"game.cpp"

void readVariables(network::FromServerToClient &from_server_to_client) {//Read data}

void readVariables(network::Snake snake_to_pass) {//Read data}

void addSnakeServer(network::FromServerToClient &from_server_to_client) {//Add snake and parts of snake}

void multiplayerServer(){

int buffer_zise = 200;
char buffer[buffer_zise];
bool quitClient = false;

network::FromServerToClient from_server_to_client;

...

//starts sdlnet and the connection with server and comes into loop

...

std::string StringToSerialize;
if (!from_server_to_client.SerializeToString(&StringToSerialize)) //Serialization ok
{
std::cout << "/* Failed to serialize */" << std::endl;
}
if (from_server_to_client.IsInitialized()) //All ok
{
std::cout << "All ok to send!" << std::endl;
}
std::cout << StringToSerialize.size() << std::endl; //To test, it was 22 at first, then 21 and then 20
SDLNet_TCP_Send(clientSocket, StringToSerialize.c_str(), StringToSerialize.size()); //Sending the package was alright

...

}

void multiplayerClient(){

int buffer_zise = 200;
char buffer[buffer_zise];
bool quitClient = false;

network::FromServerToClient other_players_snakes;

...

//starts sdlnet and the connection with server and comes into loop

...

int a = SDLNet_TCP_Recv( client, buffer, buffer_zise );
if (a <= 0)

{
std::cout << "Connection Broken" << std::endl;
quitClient = true; //If connection broken quit game
}
std::string StringToParse(buffer);
printf("bytes received:%d --- String in bytes:%d --- Char[] in bytes:%d\n", a, StringToParse.size(), strlen(buffer));

//There is the problem, i received 20 bytes with the function wich is ok (a=20), then the string StringToParse in bytes is 1 and the buffer in bytes is 1

if (!other_players_snakes.ParseFromString(StringToParse))
{
std::cout << "Failed to parse" << std::endl; //Obviusly this prints out

}

else

{

readVariables(other_players_snakes);

}

...

}


int a = SDLNet_TCP_Recv(client, buffer, buffer_zise );

'a' is a terrible name for a variable. sad.png

If you had given it a better name, it might have helped you realize what was wrong.

You are giving three parameters to SDLNet_TCP_Recv(), and you are getting one variable returned back to you (and they are using that one variable for two purposes wacko.png).

First, you're creating a buffer called "buffer". Then you're telling SDLNet_TCP_Recv() how large that buffer is.

When SDLNet_TCP_Recv() returns, it's returning the number of bytes it has actually read or a negative number on failure. You are only paying attention to the negative numbers.

If SDLNet_TCP_Recv() is telling you the number of bytes it has read, where are you using that number? How does std::string know how many bytes out of your buffer to actually store? Where do you tell the std::string how many bytes it should store? smile.png

If I do this:


std::string myStr = "meow";

...how does the std::string (myStr) know how many characters to copy from the string literal ("meow")?

It doesn't magically know. wink.png

There are two ways to store a bunch of bytes: Either you can store the size in an integer, or you can use a special character to mark the end of the string.

"meow" is actually five characters - the final character is a special character (the null character) marking the end. The null character is the integer zero. (note: the character '0' is a different number).

The problem is, when you're wanting to use a string for storing non-text data, you are very very likely to have zeroes in your data, because it's a very common number. wink.png

When you assign your buffer to std::string, you are doing this:


std::string StringToParse(buffer);

That means, std::string will read through your buffer... and keep reading... and keep reading... until it finds a zero.

Either that means it'll keep reading beyond your buffer, since you never told std::string the end of the buffer, or, in your case, it hits a zero too early and reads too little.

It's perfectly fine to store your data in a std::string, the problem is, you need to tell the std::string how much data you actually want it to copy.

std::string::assign() is the answer. Note: There are eight different functions with the same name (eight different overloads). The one you want is either number (3) or it's number (4). One of them will make the exact same mistake you already made, the other will do what you want it to do (and the third will stab adventurers who ask tricky questions blink.png).

I won't spoil the answer and tell you which one is the correct one, because it's important to understand the difference between them. Read that page, and it'll explain what each function does (you only need to focus on (3) and (4)).

If you still have questions, feel free to ask! smile.png

Advertisement
@Servant of the Lord

Thanks for taking your time to answer smile.png . I have already changed the "a" name variable to "bytesReceived" biggrin.png . It seems that the solution was with 4. The thing is that i am not used to char arrays and the read until zero. Thanks anyway. smile.png

Yes, (4) is the correct function. Glad it helped. smile.png

This is the reason I like using std::vector and it's data() accessor. Priceless when you have to work with Win32.

This topic is closed to new replies.

Advertisement