使用 UDP 协议和 writeDatagram 发送结构体

Posted

技术标签:

【中文标题】使用 UDP 协议和 writeDatagram 发送结构体【英文标题】:Send a structure with UDP protocol and writeDatagram 【发布时间】:2014-08-01 03:49:25 【问题描述】:

我的目标是通过UDP协议发送一个结构,我的问题是我用来做它的函数与他参数中的结构不兼容。 (我正在使用 QT)

这是我制作的代码:

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



我知道这一行是完全错误的:socket->writeDatagram(envoie, QHostAddress("10.100.14.79"), 4000); 但我不知道如何正确使用此功能,或者是否有替代此功能的方法?

感谢您的帮助。

【问题讨论】:

socket->writeDatagram( (const char*) &envoie, sizeof (envoie), QHostAddress("10.100.14.79"), 4000 ); 爱你...谢谢你的帮助,但是在函数的文档中我没有找到这个参数,这怎么可能? 该函数记录在 qt 文档qt-project.org/doc/qt-5/qudpsocket.html#writeDatagram 是的,我的IDE没有给我指定这个,感谢您的帮助,如果您愿意,可以为大家发布答案。 Ivan 的解决方案可能在这种情况下可以工作,因为结构在内存中是连续的,但如果您有任何动态分配的内容,则会失败。它也不允许转换为网络字节顺序(尽管 Qt 可能在内部处理了一些我不知道的事情,需要检查一下)。 【参考方案1】:

几乎总是通过网络发送裸结构是错误的,因为你不能保证它是如何打包的 - 成员之间是否有填充,字节序是什么,是否有任何额外的内部你不知道的领域?只有当接收器在同一平台上运行相同的二进制文件时,您才能这样做。鉴于fat binaries,仅运行相同的二进制文件是不够的。

正确的做法是使用QDataStream序列化结构:

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

我在another answer 中提供了有关同一主题的更多详细信息。

【讨论】:

你已经在其他话题上帮助我了,你真是太棒了。可以发送的 writeDatagram 是否有大小限制? @EvansBelloeil 这取决于使用的协议。因为在这种情况下,您正在发送 UDP,请参阅this question 了解详细信息。 TL;DR:只要 IPv4 流量没有被封装(比如在 *** 中),508 字节应该没问题。【参考方案2】:

在快速搜索socket-&gt;writeDatagram() 实际期望的内容 (see docs) 之后,似乎有两个具有此名称的重载函数。一个需要一个 const char* 和一个大小,另一个需要一个 QByteArray 引用。在这两种情况下,这意味着您需要将结构打包成这些格式,然后将它们解包到另一端的结构中。因此,在 const char* 的情况下,创建一个大小适合您的结构的字符数组

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

然后像这样打包

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

函数的第二种形式可能有更好的打包方式,但我对 Qt 不熟悉,所以你必须查看它以了解它是如何实现的,以及它是否比我上面给出的选项更好.使用我提供的选项,如果两台机器的字节序不同,您还需要注意字节序,它们可以切换解释字节的顺序。这对于整数类型最为重要。长度为一个字符的类型(即 char)不会成为问题,而且浮点数似乎通常也不是问题(尽管不要引用我的话)。 QtByteArray 使用起来可能会更好一些,但是快速浏览它上面的documentation 似乎并没有说明处理不同的字节序。处理不同字节序的一般方法是将事物转换为网络字节顺序或大字节序字节顺序。可能有一些函数可以将整数从本机字节序转换为网络字节顺序,然后在另一端转换回本机字节序。

【讨论】:

这个问题专门针对 Qt C++。您改为提供通用 C99 样式的答案。你的回答是“好的”,但这是一个不同的问题。在现代 C++ 中使用 memcpy 令人畏缩,而且几乎没有任何理由。 就我个人而言,我认为所有包含“我不熟悉 [x]”(其中“x”是问题上的标签)短语的答案都会适得其反,而且它们几乎普遍都是低的质量。

以上是关于使用 UDP 协议和 writeDatagram 发送结构体的主要内容,如果未能解决你的问题,请参考以下文章

TCP协议和UDP协议区别

UDP协议和黏包

MQTT协议和TCP协议有啥区别?为啥人们推荐MQTT协议?

UDP协议和TCP协议的区别?

TCP协议和UDP协议

TCP协议和UDP协议