Search code examples
c++udpindy

Correctly sending and receiving a struct through Indy UDP


Consider the following minimal program using Borland 2007 and Indy UDP server and client:

struct DATA_PACKAGE
{
    int t;
    int x;
    int y;
};

void __fastcall TForm1::Button1Click(TObject *Sender)
{
   DATA_PACKAGE a;
   a.t = 3;
   a.x = 2;
   a.y = 1;
   Form1->Memo1->Lines->Add("sent " + IntToStr(sizeof(DATA_PACKAGE)));
   Form1->UDPClient1->SendBuffer(server,port,RawToBytes(&a, sizeof(DATA_PACKAGE)));
}

void __fastcall TForm1::UDPServer1UDPRead(TObject *Sender, TBytes AData,
      TIdSocketHandle *ABinding)
{
    DATA_PACKAGE r;
    Form1->Memo1->Lines->Add("received " + IntToStr(sizeof(AData)));
    BytesToRaw(AData, &r, sizeof(AData));
    Form1->Memo1->Lines->Add(IntToStr(r.t) + " " + IntToStr(r.x) + " " + IntToStr(r.y));
}

output:

sent 12
received 4
3 4717901 0 

First of all, why is it sending 12, but only receiving 4 bytes?

Secondly what happends to x and y ?

When I change the datatype of t,x,y to short, I get:

sent 6 
received 4 
3 2 0

looking around I found pointers that the packing (and possibly the endianness?) of the struct is of importance, I could however not find a clear guide how design it properly.


Solution

  • TBytes is a dynamic array of bytes, it is implemented by the RTL as a pointer, which is why sizeof(AData) is returning 4. Do not use sizeof(AData), use the AData.Length property instead:

    void __fastcall TForm1::UDPServer1UDPRead(TObject *Sender, TBytes AData,
          TIdSocketHandle *ABinding)
    {
        DATA_PACKAGE r;
        Form1->Memo1->Lines->Add("received " + IntToStr(AData.Length));
        BytesToRaw(AData, &r, AData.Length);
        Form1->Memo1->Lines->Add(IntToStr(r.t) + " " + IntToStr(r.x) + " " + IntToStr(r.y));
    }