Jump to content

  • Log In with Google      Sign In   
  • Create Account


recieving data with sockets


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 Demx   Members   -  Reputation: 299

Like
0Likes
Like

Posted 19 October 2012 - 02:52 PM

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.

Sponsor:

#2 KnolanCross   Members   -  Reputation: 1264

Like
1Likes
Like

Posted 19 October 2012 - 05:32 PM

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, 19 October 2012 - 05:36 PM.

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


#3 Demx   Members   -  Reputation: 299

Like
0Likes
Like

Posted 19 October 2012 - 07:06 PM

ok thanks :)

#4 KnolanCross   Members   -  Reputation: 1264

Like
0Likes
Like

Posted 19 October 2012 - 07:48 PM

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).


#5 hplus0603   Moderators   -  Reputation: 5104

Like
1Likes
Like

Posted 19 October 2012 - 11:11 PM

Also: Always check the return value from functions. Especially from send() and recv()!

enum Bool { True, False, FileNotFound };

#6 Demx   Members   -  Reputation: 299

Like
0Likes
Like

Posted 20 October 2012 - 04:53 AM

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



#7 hplus0603   Moderators   -  Reputation: 5104

Like
0Likes
Like

Posted 20 October 2012 - 12:15 PM

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 };

#8 Demx   Members   -  Reputation: 299

Like
0Likes
Like

Posted 20 October 2012 - 04:14 PM

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 Posted Image

Edited by Demx, 20 October 2012 - 05:14 PM.


#9 KnolanCross   Members   -  Reputation: 1264

Like
0Likes
Like

Posted 20 October 2012 - 07:48 PM

"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).


#10 Demx   Members   -  Reputation: 299

Like
0Likes
Like

Posted 21 October 2012 - 02:04 AM

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?

#11 hplus0603   Moderators   -  Reputation: 5104

Like
2Likes
Like

Posted 21 October 2012 - 01:56 PM

sizeof(Player) should be sizeof(struct Player)


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.
enum Bool { True, False, FileNotFound };

#12 KnolanCross   Members   -  Reputation: 1264

Like
0Likes
Like

Posted 21 October 2012 - 06:06 PM


sizeof(Player) should be sizeof(struct Player)


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.


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


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?


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

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


#13 BeerNutts   Crossbones+   -  Reputation: 2762

Like
0Likes
Like

Posted 23 October 2012 - 01:28 PM

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:

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);
    }
  }

Casting and other things my be funny, but that's just something I threw together.
My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS