send/receive structs instead of ...

06/19/2013 22:25 go for it#1
i was checking out chat applications in c++ and found this

Code:
int ServerThread(int ID)
{
	Buffer sbuffer;

	char* Recv = new char[256];
	ZeroMemory(Recv, 256);

	// In Send we will copy the content of the struct
	// and after this we will send "Send" to the client
	char* Send = new char[sizeof(Buffer)];
	ZeroMemory(Send, sizeof(Buffer));

	for(;; Sleep(10))
	{
		// Same here!
		if(recv(Connections[ID], Recv, 256, NULL))
		{
			sbuffer.ID = ID;
			memcpy(sbuffer.Message, Recv, 256);
			memcpy(Send, &sbuffer, sizeof(Buffer));

			for(int a = 0; a != ConCounter; a++)
			{
				if(Connections[a] == Connections[ID])
				{

				}
				else
				{
					send(Connections[a], Send, sizeof(Buffer), NULL);
				}
			}
			ZeroMemory(Recv, 256);
		}
	}

	return 0;
}
Code:
struct Buffer
{
	int ID;
	char Message[256];
};

int ClientThread()
{
	Buffer sbuffer;

	char buffer[sizeof(sbuffer)] = {0};

	for(;; Sleep(10))
	{
		// The server will send a struct to the client
		// containing message and ID
		// But send only accepts a char as buffer parameter
		// so here we need to recv a char buffer and then
		// we copy the content of this buffer to our struct
		if(recv(sConnect, buffer, sizeof(sbuffer), NULL))
		{
			memcpy(&sbuffer, buffer, sizeof(sbuffer));
			cout << "<Client " << sbuffer.ID << ":> " << sbuffer.Message <<endl;
		}
	}

	return 0;
}
server receives char array and use it to fill in "Buffer" struct with the client number to send it to the rest of clients (it obtain the client number as argument from a thread per client call)
what i found interesting was that

if(recv(sConnect, buffer, sizeof(sbuffer), NULL))
{
memcpy(&sbuffer, buffer, sizeof(sbuffer));
cout << "<Client " << sbuffer.ID << ":> " << sbuffer.Message <<endl;
}

how it could assign a char array (char pointer) to an struct of type Buffer
yeah both are void pointers but what happens behind the scene?
was it because the char array only contains 2 different types it was able to initialize that struct object members with them depending on the type ?

then what if i did the same but with 2 similar types ? ex. 2 ushorts at the same buffer , would it still be able to assign each ? depending on the order of the struct it got ?

i've heard something about that before (about how stupid the wrapper method people use and that there is a better way of getting this done)

sorry for asking too many questions but that saves me load of time to study something else instead of searching :P
06/21/2013 13:14 Mr_PoP#2
you got it wrong! , the recvedbuffer actually is a packet structure(int,char[256]), as the Buffer, so you have (int32)(00 00 00 00) and (byte)(00 * 256), by saying copy the memory of this recvedbuffer to Buffer , it will take the 1st 4bytes from the recvedbuffer copy it to the 1st 4bytes in Buffer which is (int), and will copy the left 256bytes from recvedbuffer to the Buffer which is (char[256]).

that's how TQ build it's packets so they have:

structure SpwanPacket{
ushort length;
ushort type;
uint enityId;
uint messh;
etc;
};

and they copy it to the memory that's why if they add a new value inside the structure the whole packet changes !
06/21/2013 13:22 InfamousNoone#3
and then u run into 2 lovely issues called
1. dynamic packets
2. packing alignment
06/21/2013 13:32 Smaehtin#4
Quote:
Originally Posted by InfamousNoone View Post
and then u run into 2 lovely issues called
1. dynamic packets
2. packing alignment
3. Fragmentation
06/21/2013 15:10 CptSky#5
Quote:
Originally Posted by InfamousNoone View Post
and then u run into 2 lovely issues called
1. dynamic packets
2. packing alignment
Well, not big problems...

Code:
    #pragma pack(1)
    typedef struct
    {
        Msg::Header Header;
        uint32_t Color; // ARGB code
        int16_t Channel;
        int16_t Style;
        int32_t Timestamp;
        uint8_t Buf[1];
    }MsgInfo;
    #pragma pack(pop)
06/21/2013 16:53 go for it#6
about Fragmentation it's not a big deal to me as i can assign after i receive the complete packet so there is nothing to worry about (as i bet tq client should be doing the same)

about dynamic packet and packet alignment
i've seen a thread you made about it [Only registered and activated users can see links. Click Here To Register...]
but i guess there is away around to define a struct with a variable size
didn't honestly understand the example cptsky said

but is there a better way of getting that done ?
06/21/2013 17:33 Mr_PoP#7
Quote:
Originally Posted by CptSky View Post
Well, not big problems...

Code:
    #pragma pack(1)
    typedef struct
    {
        Msg::Header Header;
        uint32_t Color; // ARGB code
        int16_t Channel;
        int16_t Style;
        int32_t Timestamp;
        uint8_t Buf[1];
    }MsgInfo;
    #pragma pack(pop)
it's a prob! consider the ChatPacket , you don't know what is the msg length is going to be!, because it's dynamic ,therefore you going to hack the structure by pulling out the msg (resize/copy to) it then send the structure, where when we pass arguments to the constructor we will have a better way of controlling it! don't you agree?
06/21/2013 18:35 CptSky#8
Quote:
Originally Posted by Mr_PoP View Post
it's a prob! consider the ChatPacket , you don't know what is the msg length is going to be!, because it's dynamic ,therefore you going to hack the structure by pulling out the msg (resize/copy to) it then send the structure, where when we pass arguments to the constructor we will have a better way of controlling it! don't you agree?
Well, the struture is internal to the MsgTalk class. So, it's only a cast over a byte buffer to put values directly in memory without handling any offset, etc. When I construct the object, the internal buffer is allocated with the real size in mind, so the MsgInfo struct is less than the internal buffer. By using a string packer on the last byte, you can easily write any dynamic packet.

You can't only have a simple structure, but if it's neasted inside a class, it's easier than managing the offset yourself, etc.

Code:
MsgTalk :: MsgTalk(const char* aSpeaker, const char* aHearer, const char* aWords,
                   Channel aChannel, uint32_t aColor)
    : Msg(sizeof(MsgInfo) +
          (aSpeaker != nullptr ? strlen(aSpeaker) : 0)  + 1 +
          (aHearer != nullptr ? strlen(aHearer) : 0)  + 1 +
          /* (aEmotion != nullptr ? strlen(aEmotion) : 0) */ + 1 +
          (aWords != nullptr ? strlen(aWords) : 0) + 1)
{
    mInfo = (MsgInfo*)mBuf;
    create(aSpeaker, aHearer, "", aWords, aChannel, aColor); // HACK !
}

MsgTalk :: MsgTalk(uint8_t** aBuf, size_t aLen)
    : Msg(aBuf, aLen)
{
    ASSERT(aLen >= sizeof(MsgInfo));

    mInfo = (MsgInfo*)mBuf;
    #if BYTE_ORDER == BIG_ENDIAN
    swap(mBuf);
    #endif
}
06/21/2013 19:00 Mr_PoP#9
Quote:
Originally Posted by CptSky View Post
Well, the struture is internal to the MsgTalk class. So, it's only a cast over a byte buffer to put values directly in memory without handling any offset, etc. When I construct the object, the internal buffer is allocated with the real size in mind, so the MsgInfo struct is less than the internal buffer. By using a string packer on the last byte, you can easily write any dynamic packet.

You can't only have a simple structure, but if it's neasted inside a class, it's easier than managing the offset yourself, etc.[..]
I always wanted to do that in C# in safe way, without allowing unsafe code , but I couldn't lol, I agree it's better in away YOU DON'T CARE where is the offset it's handling it's self making it easier for you to deal with packets.