使用UDP协议和readDatagram接收数据

时间:2014-06-12 13:12:19

标签: c++ qt network-programming udp

在帮助我使用UDP协议将数据正确发送给某人的第一个主题之后,我在接收这些数据时遇到了问题。这个问题很奇怪,只有在我第一次启动发送数据的功能时才会发生。第一次,服务器只接收第一帧。但之后,如果我重新使用该功能,一切都还可以。

所以这是通过UDP协议发送数据的代码(我的数据是结构):

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

    MyStruct envoie;

    envoie.test1 = 1;
    envoie.test2 = true;
    envoie.test3 = 97;

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

    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)envoie.test3;

    //I'm sending 5 frames        

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

这是允许我接收这些数据的功能:

void MyUDP::readyRead()
{

    QHostAddress sender;
    quint16 senderPort;

    // qint64 QUdpSocket::readDatagram(char * data, qint64 maxSize,
    //                 QHostAddress * address = 0, quint16 * port = 0)
    // Receives a datagram no larger than maxSize bytes and stores it in data.
    // The sender's host address and port is stored in *address and *port
    // (unless the pointers are 0).

    typedef struct MyStructTag
    {
       int test1;
       bool test2;
       char test3;

    } MyStruct;

    MyStruct recois;
    socket->readDatagram((char*)&recois, sizeof (recois), &sender, &senderPort);


    qDebug() << "Message from: " << sender.toString();
    qDebug() << "Message port: " << senderPort;
    qDebug() << "Message: " << recois.test3;
}

为什么我第一次启动sendUDP时只收到1帧?

2 个答案:

答案 0 :(得分:3)

有两个问题:

  1. readyRead {em}必须循环socket->hasPendingDatagrams() QDataStream为真。

  2. 您必须使用 发送端和接收端{/ 1}}。

  3. 最后,您正在编写C ++,不应该使用C结构语法。结构声明重复也会适得其反。您需要的是拥有MyStruct的流媒体运营商。

    以下是一个完整的例子。

    #include <QCoreApplication>
    #include <QUdpSocket>
    #include <QDataStream>
    #include <QBasicTimer>
    
    static const quint16 port = 4000;
    
    class MyUDP : public QObject {
       Q_OBJECT
       QUdpSocket m_socket;
       QBasicTimer m_timer;
    
       void timerEvent(QTimerEvent*ev) {
          if (ev->timerId() != m_timer.timerId()) return;
          sendUDP();
       }
       void sendUDP();
    public:
       MyUDP() {
          m_timer.start(1000, this);
          connect(&m_socket, SIGNAL(readyRead()), SLOT(readyRead()));
          m_socket.bind(QHostAddress::LocalHost, port);
       }
       Q_SLOT void readyRead();
    };
    
    struct MyStruct {
       int test1;
       bool test2;
       char test3;
       MyStruct() {}
       MyStruct(int t1, bool t2, char t3) : test1(t1), test2(t2), test3(t3) {}
    };
    
    template <typename T> T get(QDataStream & str) {
       T value;
       str >> value;
       return value;
    }
    
    QDataStream & operator<<(QDataStream & str, const MyStruct & m)
    {
       return str << (qint32)m.test1 << (bool)m.test2 << (qint8)m.test3;
    }
    
    QDataStream & operator>>(QDataStream & str, MyStruct & m)
    {
       m.test1 = get<qint32>(str);
       m.test2 = get<bool>(str);
       m.test3 = get<qint8>(str);
       return str;
    }
    
    void MyUDP::sendUDP()
    {
       MyStruct envoie(1, true, 97);
    
       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 << envoie;
    
       for (int i = 0; i < 5; ++ i) {
          m_socket.writeDatagram(buf, QHostAddress::LocalHost, port);
       }
    }
    
    void MyUDP::readyRead()
    {
       QHostAddress sender;
       quint16 senderPort;
    
       MyStruct recois;
       while (m_socket.hasPendingDatagrams()) {
          QByteArray buf(m_socket.pendingDatagramSize(), Qt::Uninitialized);
          QDataStream str(&buf, QIODevice::ReadOnly);
          m_socket.readDatagram(buf.data(), buf.size(), &sender, &senderPort);
          str >> recois;
          qDebug() << "Message from: " << sender;
          qDebug() << "Message port: " << senderPort;
          qDebug() << "Message: " << recois.test3;
       }
    }
    
    int main(int argc, char *argv[])
    {
       QCoreApplication a(argc, argv);
       MyUDP udp;
       return a.exec();
    }
    
    #include "main.moc"
    

答案 1 :(得分:0)

在您的问题中确实没有足够的信息,但是当您读取数据报时,每次读取只能获得1个数据报。与以流模式读取的TCP不同,UDP是面向消息的。如果要读取更多消息,请执行多次读取或循环读取它们。另请注意,您不能依赖有保证的订单甚至保证交付......