2

My goal is to send a structure throught UDP Protocol, my problem is that the function I use to do it is not compatible with structure in his parameters. (I'm using QT )

Here's the code I make :

void MyUDP::sendUDP()
{
    typedef struct MyStructTag
    {
       int test1;
       bool test2;
       char test3;
    } MyStruct;

    MyStruct envoie;

    // Sends the datagram datagram
    // to the host address and at port.
    // qint64 QUdpSocket::writeDatagram(const QByteArray & datagram,
    //                      const QHostAddress & host, quint16 port)

    socket->writeDatagram(envoie, QHostAddress("10.100.14.79"), 4000);


}

I know this line is totally wrong : socket->writeDatagram(envoie, QHostAddress("10.100.14.79"), 4000); But I don't how to proper use this function, or if there's an alternative to this function ?

Thank you for your help.

Evans Belloeil
  • 2,413
  • 7
  • 43
  • 76
  • 3
    `socket->writeDatagram( (const char*) &envoie, sizeof (envoie), QHostAddress("10.100.14.79"), 4000 );` – Ivan Jun 11 '14 at 07:42
  • Love You ... Thanks for the help, but in the doc of the function I don't find this parameters, how is this possible ? – Evans Belloeil Jun 11 '14 at 07:43
  • 1
    the function is documented in qt docs http://qt-project.org/doc/qt-5/qudpsocket.html#writeDatagram – Ivan Jun 11 '14 at 07:44
  • Yep, my IDE doesn't specify this one to me, thanks for your help, you can post an answer for everyone if you want. – Evans Belloeil Jun 11 '14 at 07:46
  • Ivan's solution should probably work in this case as the structure will be contiguous in memory, but will fail if you have anything dynamically allocated. It also doesn't allow for conversion to network-byte-order (though maybe Qt handles this internally some how I don't know, something to check out). – cgeroux Jun 11 '14 at 07:58
  • @ Ivan Grynko that worked, thanks! – normalUser Aug 12 '15 at 13:04

2 Answers2

6

It is almost always wrong to send a bare structure over the wire, since you are not guaranteed anything about how it's packed - is there padding between members, what's the endianness, are there any extra internal fields that you are unaware of? You can only do that if the receiver is running the same binary on the same platform. Running the same binary is not sufficient by itself in light of fat binaries.

The proper way to do it is to use QDataStream to serialize the structure:

void MyUDP::sendUDP()
{
  struct MyStruct
  {
     int test1;
     bool test2;
     char test3;
  };
  MyStruct envoie;

  QByteArray buf;
  QDataStream s(&buf, QIODevice::WriteOnly);
  // The encoding is big endian by default, on all systems. You 
  // can change it if you wish.
  if (false) s.setByteOrder(QDataStream::LittleEndian);
  s << (qint32)envoie.test1 << (quint8)envoie.test2 << (qint8)test3;
  socket->writeDatagram(buf, QHostAddress("10.100.14.79"), 4000);
}

I provide more details in another answer on the same topic.

Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • You already help me on other topic, you damn good. Is there a limit size for writeDatagram that can be send ? – Evans Belloeil Jun 12 '14 at 06:25
  • 1
    @EvansBelloeil That depends on what protocol is in use. Since, in this case, you're sending UDP, see [this question](http://stackoverflow.com/q/1098897/1329652) for details. TL;DR: 508 bytes should be OK as long as the IPv4 traffic is not encapsulated (say in a VPN). – Kuba hasn't forgotten Monica Jun 12 '14 at 11:45
  • @Kubahasn'tforgottenMonica just out of curiosity, how do you deserialize a struct packed in this method on the readDatagram end? This seems like an elegant solution. – Robbie P. Mar 29 '22 at 03:45
0

After doing a quick search on what socket->writeDatagram() actually expects (see docs) it seems that there are two overloaded functions with this name. One that expects a const char* and a size, and the other that expects a QByteArray reference. In both cases this means that you need to pack your structure into these formats and unpack them into a structure on the other end. So in the case of the const char* create a character array that is the right size for your structure

unsigned int size=sizeof(int)+sizeof(bool)+sizeof(char)
char cBuffer[size];

and pack it like so

unsigned int nPos=0;
memcpy(cBuffer[nPos],envoie.test1,sizeof(int));
nPos+=sizeof(int);
memcpy(cBuffer[nPos],envoie.test2,sizeof(bool));
nPos+=sizeof(bool);
memcpy(cBuffer[nPos],envoie.test3,sizeof(char));

The second form of the function might have some nicer way to pack things but I am not familiar with Qt so you would have to look it up to see how it does it and whether it is nicer than the option I have given above. With the option I have given you also need to be careful about endianess if both machines don't have the same endianness they can switch the order in which they interpreter the bytes. This is most important for integer types. Types that are one character in length (i.e. char) will not be a problem, and it seems that often floating point numbers are also not a problem (though don't quote me on this). The QtByteArray might be a little nicer to work with, but a quick browse through the documentation on it doesn't seem to say anything about handling different endiannesses. The generally way to handle different endiannesses is to convert things to network byte order, or big endian byte order. There are likely some functions to convert your integers from your native endianness to the network byte order, and back to a native endianness on the other end.

cgeroux
  • 192
  • 4
  • The question was specifically about Qt *and* C++. You provide a generic C99-style answer instead. Your answer is "OK", but it's to a different question. The use of `memcpy` in modern C++ is cringe-inducing and there's rarely any reason for it. – Kuba hasn't forgotten Monica Jun 11 '14 at 20:04
  • Personally, I consider all answers containing the phrase "I am not familiar with [x]", where "x" is a tag on the question, to be counterproductive and they are all almost universally of low quality. – Kuba hasn't forgotten Monica Jun 11 '14 at 20:06