Sign in to follow this  
Demx

recieving data with sockets

Recommended Posts

Demx    389
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 :

[CODE]
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);

}
[/CODE]



server:

[CODE]
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);

}
[/CODE]


Is this correct ? because the server outputs incorrect values.

Share this post


Link to post
Share on other sites
KnolanCross    1974
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. Edited by KnolanCross

Share this post


Link to post
Share on other sites
KnolanCross    1974
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.

Share this post


Link to post
Share on other sites
Demx    389
[quote name='KnolanCross' timestamp='1350697724' post='4992012']
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.
[/quote]

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:

[CODE]


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);
}
[/CODE]




server:

[CODE]


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[i].id; // here it crashes
}
}
}

[/CODE]

Share this post


Link to post
Share on other sites
hplus0603    11347
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.)

Share this post


Link to post
Share on other sites
Demx    389
[quote name='hplus0603' timestamp='1350756948' post='4992215']
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.)
[/quote]

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 [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img] Edited by Demx

Share this post


Link to post
Share on other sites
KnolanCross    1974
"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.

Share this post


Link to post
Share on other sites
Demx    389
[quote name='KnolanCross' timestamp='1350784084' post='4992326']

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.
[/quote]

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?

Share this post


Link to post
Share on other sites
hplus0603    11347
[quote name='KnolanCross' timestamp='1350784084' post='4992326']
sizeof(Player) should be sizeof(struct Player)
[/quote]

There is no difference between those two expressions, unless you're using plain C and do not have a typedef for struct Player to Player. And, if you don't have that, then the code wouldn't even compile.

Share this post


Link to post
Share on other sites
KnolanCross    1974
[quote name='hplus0603' timestamp='1350849399' post='4992539']
[quote name='KnolanCross' timestamp='1350784084' post='4992326']
sizeof(Player) should be sizeof(struct Player)
[/quote]

There is no difference between those two expressions, unless you're using plain C and do not have a typedef for struct Player to Player. And, if you don't have that, then the code wouldn't even compile.
[/quote]

Good to know, as I said, I am a C programmer, no CPP.

[quote name='Demx' timestamp='1350806670' post='4992385']
[quote name='KnolanCross' timestamp='1350784084' post='4992326']
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.
[/quote]

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?
[/quote]

Personally I never had problem with endianess, so I can't tell any popular processor having a different endianess.

Share this post


Link to post
Share on other sites
BeerNutts    4400
I posted something similar in another thread, but I would take a slightly different approach than using some random number of players (100) when you can easily use a configurable amount:
[code]

struct TPacketData {
uint16_t MsgType;
uint16_t MsgLength;
uint8_t MsgPayload[0];
}

enum {
PLAYER_PACKET = 0,
CHAT_PACKET
// define other types here
}

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

struct TChatData {
uint32_t PlayerId;
uint32_t ChatLength;
char ChatData[0];
}

void SendData(uint16_t msgType, uint16 msgLength, uint8_t *msgData)
{
uint32_t totalLength = sizeof(TPacketData) + msgLength;
TPacketData *packet = (TPacketData*)malloc(totalLength);
packet->MsgType = msgType;
packet->MsgLength = msgLength;
memcpy(packet->MsgData, msgData, msgLength);
send(ServerSocket, packet, totalLength);
}

// To Send 10 Player's Data do this
TPlayerData playerData[10]; // or use malloc to allocate how many players you need

// Fill in each of the player's data
playerData[0].id = Players[0].id;
...
playerData[9].x = Players[9].x;

// Now send off
SendData(PLAYER_PACKET, sizeof(TPlayerData)*10, (uint8_t *)playerData);


// To read it out, do this:
void RecvData()
{
TPacketData packetTemp;
TPacketData *packet;

// Read the packet header
recv(clientSocket, &packetTemp, sizeof(TPacketData));

// Create the actual packet
packet = (TPacketData*)malloc(sizeof(TPacketData) + packetTemp.MsgLength);
memcpy(packet, &packetTemp, sizeof(TPacketData);

// Read the rest of the data into the msg data
recv(clientSocket, packet->MsgData, packet->MsgLength);

// Check the type
if (packet->MsgType == PLAYER_PACKET) {
// parse each player
uint32_t playerLength = sizeof(TPlayerData);
uint32_t numPlayers = packet->MsgLength/playerLength;
for (uint32_t i = 0; i < numPlayers; i++) {
TPlayerData player;
memcpy(&player, packet->MsgData + playerLength*i, playerLength);

UpdatePlayer(player);
}
}
[/code]

Casting and other things my be funny, but that's just something I threw together.

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