5

I am trying write a QT program to receive UDP packet.I am trying to receive from Packet Sender software This is my code

    socket = new QUdpSocket(this);
    bool result =  socket->bind(QHostAddress("150.100.50.88"),45454);
    qDebug() << result;
    if(result)
    {
        qDebug << "PASS";
    }
    else
    {
        qDebug << "FAIL";
    }
    processPendingDatagrams();
    connect(socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()),Qt::QueuedConnection);


    void UDP::processPendingDatagrams() 
    {
        QHostAddress sender;
        u_int16_t port;
        while (socket->hasPendingDatagrams())
        {
            QByteArray datagram;
            datagram.resize(socket->pendingDatagramSize());
            socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
           qDebug() <<"Message From :: " << sender.toString();
           qDebug() <<"Port From :: "<< port;
           qDebug() <<"Message :: " << datagram;    
       } //! [2] 
   }

UDP.h:

 class UDP : public QObject 
 {
 Q_OBJECT public:
 explicit UDP(QObject *parent = 0);

 signals:

 public slots:
 void SendDatagram(u_int8_t,u_int8_t,u_int8_t);

 private slots:
 void processPendingDatagrams();

 private :
 QUdpSocket *socket; 
 };

The readReady signal and corresponding slot are not working . I can see the packets in Wireshark. If a I try receive the packets in continuously in a loop I am able see the datagrams.What can be the reason for signals and Slots for not working.Sending operation is working well.

roalz
  • 2,699
  • 3
  • 25
  • 42
Karthik Poojary
  • 53
  • 1
  • 1
  • 6
  • is your void UDP::processPendingDatagrams() definition in your .h in the slots instead of just the functions ? (with public/protected/private slots: ) – Gabrielle de Grimouard Mar 10 '17 at 10:02
  • void UDP::processPendingDatagrams() is declare as public function not as slot.I have added the class to my question – Karthik Poojary Mar 10 '17 at 10:26
  • if you want to use it as a slot like you do in connect, you should move it to the slots. If it's as a function it's won't be called because Qt won't be able to link it with a signal. – Gabrielle de Grimouard Mar 10 '17 at 10:31
  • I have moved the declaration to Slots even after that there is no change.In wireshark I am getting Destination Unreachable (port unreachable). – Karthik Poojary Mar 10 '17 at 11:02
  • can you update the .h accodingly to the changes you made ? – Gabrielle de Grimouard Mar 10 '17 at 11:03
  • 1
    if oyu are receiving the packets here, you should change the ip to QHostAddress::AnyIPv4. and try another port. (if you are on linux, you can try sending udp packets through netcat with nc) – Gabrielle de Grimouard Mar 10 '17 at 11:08
  • I am able to send UDP packets successfully, problems only is when I try to receive the data using signals and slots in QT. – Karthik Poojary Mar 10 '17 at 11:16
  • I tried the code you wrote, the slot is working well (I did some modifications since your code doesn't compile (qDebug() not qDebug). I will write my code as an answer then you could try it and see if it's working too. Then if not, we can try to find why it's not working for you – Gabrielle de Grimouard Mar 10 '17 at 11:27

3 Answers3

7

This code work for me. Try it please.

.pro:

#-------------------------------------------------
#
# Project created by QtCreator 2017-03-10T11:44:19
#
#-------------------------------------------------

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = test
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

mainwindow.cpp:

#include "mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    socket = new QUdpSocket(this);
        bool result =  socket->bind(QHostAddress::AnyIPv4, 45454);
        qDebug() << result;
        if(result)
        {
            qDebug() << "PASS";
        }
        else
        {
            qDebug() << "FAIL";
        }
        processPendingDatagrams();
        connect(socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()),Qt::QueuedConnection);
}

MainWindow::~MainWindow()
{
}

void MainWindow::processPendingDatagrams()
 {
    qDebug() << "in !";
    QHostAddress sender;
    u_int16_t port;
    while (socket->hasPendingDatagrams())
    {
         QByteArray datagram;
         datagram.resize(socket->pendingDatagramSize());
         socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
        qDebug() <<"Message From :: " << sender.toString();
        qDebug() <<"Port From :: "<< port;
        qDebug() <<"Message :: " << datagram;
    }
}

mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QUdpSocket>


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void processPendingDatagrams();
private:
    QUdpSocket *socket = nullptr;
};

#endif // MAINWINDOW_H

main.cpp:

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

tried with netcat with the command:

 netcat -u 127.0.0.1 45454

once you ran the command, just type anything and press return.

  • I was wondering what your development environment is. I have a similar setup on Ubuntu Qt5.9.5 but am having issues getting the processPendingDatagrams() slot to trigger. https://stackoverflow.com/questions/54209604/can-i-use-qudpsockets-wo-polling-or-custom-classes-in-qt – simgineer Jan 17 '19 at 22:51
  • I tried on both Ubuntu, and Windows 10. Without a QCoreApplication and a app.exec() the signal and slot cannot work in Qt. Indeed The signal slots of Qt are put in a queue which need to be read during the app.exec. In you other question you do not let Qt do that. – Gabrielle de Grimouard Jan 31 '19 at 11:02
0

@Gabriel answer did't work for me because it's using the old connect syntax. I updated it to the following (Qt 6):

// udpclient.h

#ifndef UDPCLIENT_H
#define UDPCLIENT_H
#include <QObject>
#include <QUdpSocket>

class UdpClient: public QObject
{
    Q_OBJECT

public:
    explicit UdpClient(QObject *parent);
    void initSocket();

private:
    void processPendingDatagrams();
    QUdpSocket *socket=nullptr;

};

#endif // UDPCLIENT_H
// udpclient.cpp

#include "udpclient.h"

UdpClient::UdpClient(QObject *parent) : QObject(parent) {
}

void UdpClient::initSocket()
{
    socket = new QUdpSocket(this);
    bool result =  socket->bind(QHostAddress::AnyIPv4, 4999);
    if(result)
    {
        qDebug() << "Socket PASS";
    }
    else
    {
        qDebug() << "Socket FAIL";
    }

    processPendingDatagrams();
    connect(socket, &QUdpSocket::readyRead, this, &UdpClient::processPendingDatagrams);

}

void UdpClient::processPendingDatagrams()
{
    qDebug() << "in !";
    QHostAddress sender;
    quint16 port;
    while (socket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(socket->pendingDatagramSize());
        socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
        qDebug() <<"Message From :: " << sender.toString();
        qDebug() <<"Port From :: "<< port;
        qDebug() <<"Message :: " << datagram;
    }
}

It can be used in a function or main() as:

auto udpClient = new UdpClient(0);
udpClient->initSocket();
Bersan
  • 1,032
  • 1
  • 17
  • 28
0

In my case this did not work, because there was always a "dummy" datagram left somewhere in memory, even if hasPendingDatagrams() returned false, I had to call readDatagram one more time to let my program receive newer datagrams. My answer is here anyways https://stackoverflow.com/a/74056997/11414500 Good luck!