recieving data with sockets

Started by
11 comments, last by BeerNutts 11 years, 5 months ago
I'm trying to send a struct from a client and reading it with the server but i'm not sure i'm doing it right

client :


struct packet
{
uint32_t id;
uint32_t x;
uint32_t y;
};

void send()
{

packet p;
p.id=1;
p.x=10;
p.y=10;
send( m_Socket, (const char*)&p, sizeof(p), 0);

}




server:


unsigned int extractUnsignedInt(char** msg)
{
unsigned int* value;
value = (unsigned int*) *msg;
*msg += sizeof(unsigned int);
return *value;
}

void recieve()
{

char *buf;

recv(pClientContext->GetSocket(), buf, sizeof(buf), 0);

unsigned int id = extractUnsignedInt(&buf);
unsigned int x = extractUnsignedInt(&buf);
unsigned int y = extractUnsignedInt(&buf);

}



Is this correct ? because the server outputs incorrect values.
Advertisement
No it is not correct.
Your buf* variable (the one you are giving to the recv function) is not poiting to any known area of memory.

Replace:

[source lang="cpp"]char* buf;[/source]
By:
[source lang="cpp"]char buf[4096];[/source]
And you it should work. Also, you should probably be checking the recv function return, it will be pretty useful so that you can check how much data you received.

Also, on the server it is better to use:

[source lang="cpp"]send( m_Socket, (const char*)&p, sizeof(struct packet), 0);[/source]

Because if you are trying to send a pointer that comes as argument the compiler will think that the sizeof that variable is 4 (or 8 in a 64 bits system), not the correct size (in this point of the code it will work, because - since the variable was created locally - the compiler can still find its context and will get the size correctly, still not recomended).

PS: I am assuming you coded the server bind/accept correcly, that may be the problem too.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

ok thanks :)
By the way, that function you are using, I posted in the forums some other day, good to see someone is using it, but as I said in the post, you should replace the unsigned int to uint32_t. In this case (unsigned int) you won't have any problems, but if you make a "long" or "unsigned long" version of it (instead of using int64_t or uint64_t) you will run into compatibility problems between 32 and 64 bits versions.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).

Also: Always check the return value from functions. Especially from send() and recv()!
enum Bool { True, False, FileNotFound };

By the way, that function you are using, I posted in the forums some other day, good to see someone is using it, but as I said in the post, you should replace the unsigned int to uint32_t. In this case (unsigned int) you won't have any problems, but if you make a "long" or "unsigned long" version of it (instead of using int64_t or uint64_t) you will run into compatibility problems between 32 and 64 bits versions.


ok I won't be using longs lol,
I tried to implement your method to send variable arrays but it gives an unhandled exception can you check please..

client:




struct Player
{
int id;
int x;
int y;
};

struct PlayerPacket
{
uint32_t messageId;
uint32_t numPlayers;
Player playerArray[100];
};

void send()
{

PlayerPacket ppack;

ppack.messageId = 1;
ppack.numPlayers = 3;


ppack.playerArray[0].id = 1;
ppack.playerArray[0].x = 5;
ppack.playerArray[0].y = 5;

ppack.playerArray[1].id = 2;
ppack.playerArray[1].x = 10;
ppack.playerArray[1].y = 10;

ppack.playerArray[2].id = 3;
ppack.playerArray[2].x = 20;
ppack.playerArray[2].y = 20;



nBytesSent = send( m_Socket, (const char*)&ppack, sizeof( (sizeof(uint32_t) + sizeof(uint32_t) + (sizeof(Player) * ppack.numPlayers) ) ), 0);
}





server:




char buf[4096];
unsigned int i;

int nBytes = recv(pClientContext->GetSocket(), buf, sizeof(buf), 0);
char* messageToProcess = (char*) buf;

unsigned int id = extractUnsignedInt( &messageToProcess );
unsigned int numberOfPlayers = extractUnsignedInt( &messageToProcess );

if( id == 1 )
{
if (numberOfPlayers != 0 )
{
Player* playerarray = (Player*) messageToProcess;

for( i = 0; i < numberOfPlayers; i++ )
{
cout << playerarray.id; // here it crashes
}
}
}

You need to learn some basic debugging skills.
Start the program in the debugger.
When you get the "unhandled exception" -- what line are you getting it on?
Can you look at the variables, and see what values they have?
Try to figure out why you're getting that exception. For example: Will an unsigned int be the same thing as a pointer-to-player object?

Honestly, you need a significantly better understanding of pointers, arrays, memory, object lifetime, and debugging, before you can successfully develop network code in C or C++.
I suggest you focus on learning C++ development and debugging first, and come back to the actual networking part when you "speak the language." Right now, what you're trying is similar to trying to learn advanced calculus (network programming) from a textbook in latin (a language you don't yet master.)
enum Bool { True, False, FileNotFound };

You need to learn some basic debugging skills.
Start the program in the debugger.
When you get the "unhandled exception" -- what line are you getting it on?
Can you look at the variables, and see what values they have?
Try to figure out why you're getting that exception. For example: Will an unsigned int be the same thing as a pointer-to-player object?

Honestly, you need a significantly better understanding of pointers, arrays, memory, object lifetime, and debugging, before you can successfully develop network code in C or C++.
I suggest you focus on learning C++ development and debugging first, and come back to the actual networking part when you "speak the language." Right now, what you're trying is similar to trying to learn advanced calculus (network programming) from a textbook in latin (a language you don't yet master.)


np it works now.. for no reason it wasnt working lol .. and I know I have to study more but i should do in depth at university or in the future

btw is this method solid ? i heard it had problems if the machines had different endian .. could someone explain smile.png
"sizeof( (sizeof(uint32_t) + sizeof(uint32_t) + (sizeof(Player) * ppack.numPlayers) );"

Remove the first sizeof and sizeof(Player) should be sizeof(struct Player) as should the Player inside the PlayerPacket.

Other than that seems ok at a first glance. You should probably check the send/recv returns, this is pretty important.
Also, if you are using exceptions (which you should), take a look at the try, catch and throw examples (I am a C programmer, not CPP, so I can't tell you in details how it work).

Endianness problems got to do with how each machine deals with the byte order, for instance, if you have an int (4 bytes) with the value 1 it can be:
00 00 00 01
or
00 00 01 00

Depending on the machine.

Currently working on a scene editor for ORX (http://orx-project.org), using kivy (http://kivy.org).



Endianness problems got to do with how each machine deals with the byte order, for instance, if you have an int (4 bytes) with the value 1 it can be:
00 00 00 01
or
00 00 01 00

Depending on the machine.


from wikipedia:
"Well-known processor architectures that use the little-endian format include x86 (including x86-64), 6502 (including 65802, 65C816), Z80 (including Z180, eZ80 etc.), MCS-48, 8051, DEC Alpha, Altera Nios, Atmel AVR, SuperH, VAX, and, largely, PDP-11."

So we can say all commercial computers (x86 and x64) use little endian so there is not much of a problem here right?

This topic is closed to new replies.

Advertisement