A UDP socket send/receive.
-
I have a class
MyUDP::MyUDP(QObject *parent) : QObject(parent) { // create a QUDP socket socket = new QUdpSocket(this); } void MyUDP::Start(QString local_ip, quint16 local_port) { socket->bind(QHostAddress(local_ip), local_port); connect(socket, SIGNAL(ReadyRead()), this, SLOT(ReadyRead())); } void MyUDP::Send(QString data, QString remote_ip, quint16 remote_port) { QByteArray Data; Data.append(data); socket->writeDatagram(Data, QHostAddress(remote_ip), remote_port); } void MyUDP::ReadyRead() { // when data comes in QByteArray buffer; buffer.resize(socket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; socket->readDatagram(buffer.data(), buffer.size(), &sender, &senderPort); qDebug() << "Message from: " << sender.toString(); qDebug() << "Message port: " << senderPort; qDebug() << "Message: " << buffer; }
And I have two buttons CONNECT and SEND in mainwindow.cpp
static MyUDP udp; void MainWindow::on_ButtonStartConnection_clicked() { QString loc_ip = ui->lineEditLocalIP->text(); quint16 loc_port =static_cast<quint16>(ui->spinBoxLocalPort->value()); udp.Start(loc_ip, loc_port); } void MainWindow::on_ButtonSendNetMessage_clicked() { QString rem_ip = ui->lineEditRemoteIP->text(); quint16 rem_port = static_cast<quint16>(ui->spinBoxRemotePort->value()); QString message = ui->textEditNetTX->toPlainText(); udp.Send(message, rem_ip, rem_port); }
Connect - OK.
Send - OK - remote units get messages.
However I never receive from the remote units, also I connected the event - connect(socket, SIGNAL(ReadyRead()), this, SLOT(ReadyRead()));What do I miss?
-
@jenya7 said in A UDP socket send/receive.:
connect(socket, SIGNAL(ReadyRead()), this, SLOT(ReadyRead()))
I see a slot
ReadyRead
, but what is thisSIGNAL(ReadyRead())
? If you changed over to New Signal Slot Syntax it would not compile if you have not defined the signal. If you must stick with old style connects, at least check the return result of yourconnect()
s, and be prepared for runtime errors....Separately,
static MyUDP udp;
, what do you need/want astatic
variable for, probably not a good idea at all. -
@jenya7 Please read documentation: there is no signal ReadyRead in QUdpSocket, but https://doc.qt.io/qt-5/qiodevice.html#readyRead
And static variables should be avoided as much as possible. Usually they are a sign for bad design. -
@jsulm said in A UDP socket send/receive.:
@jenya7 Please read documentation: there is no signal ReadyRead in QUdpSocket, but https://doc.qt.io/qt-5/qiodevice.html#readyRead
And static variables should be avoided as much as possible. Usually they are a sign for bad design.OK. So this way - connect(socket, SIGNAL(readyRead()), this, SLOT(ReadyRead())); on readyRead my ReadyRead is invoked?
-
@jenya7 Yes.
But as @JonB already suggested you should switch to new Qt5 syntax to detect such issues already at compile time.
See https://wiki.qt.io/New_Signal_Slot_Syntax/de -
what you wrote:
connect(socket, SIGNAL(ReadyRead()), this, SLOT(ReadyRead()));
what it should be:
Qt5 and Qt6connect(socket, & QUdpSocket::readyRead, this, &MyUDP::ReadyRead);
Qt4 and earlier:
bool connectWasSuccessfull = connect(socket, SIGNAL(readyRead()), this, SLOT(ReadyRead())); Q_ASSERT(connectWasSuccessfull);
you should read up on signal and slots and on static. Because static does not "limit anything to only 1 file"
-
@J-Hilk
I have Qt 4.8. Indeed this SIGNAL(readyRead() is quite unclear. This way QUdpSocket::readyRead it's clear and I can see all events on smart autocomplete.
One more thing - how can I display a received message to a user? Say in textEdit. qDebug() is not usefull in a real application. How can I pass the data outside the class? Outside the void MyUDP::ReadyRead().On signal event I get to MyUDP::ReadyRead() but who is signaling to UI to display message?
-
@jenya7 said in A UDP socket send/receive.:
How can I pass the data outside the class?
Using signals and slots. In your MyUDP class add a signal with a QString parameter. Then emit this signal when you want to show a message with the text as signal parameter. Connect this signal with a slot in your GUI class which is responsible for showing the message. In this slot you can show the text then.
-
@jsulm said in A UDP socket send/receive.:
@jenya7 said in A UDP socket send/receive.:
How can I pass the data outside the class?
Using signals and slots. In your MyUDP class add a signal with a QString parameter. Then emit this signal when you want to show a message with the text as signal parameter. Connect this signal with a slot in your GUI class which is responsible for showing the message. In this slot you can show the text then.
Sorry I fail to understand. Right now the receiving is working and I got the message in a global string
msg = QString(udp_buffer);
Now what signal do I emit? -
@jenya7 said in A UDP socket send/receive.:
Now what signal do I emit?
One you need to define in your MyUDP class as I wrote before:
class MyUDP... { signals: void showMessage(const QString& msg); ... void MyUDP::ReadyRead() { ... showMessage(QString(buffer));
Please read https://doc.qt.io/qt-5/signalsandslots.html
-
@jenya7 said in A UDP socket send/receive.:
in any file?
Yes, just add a slot where you need it and connect it to the signal.
Signals/slots is a very powerful concept and it also helps to decouple classes from each other. For example your MyUDP class does not need to know who connects to its signal, it just emits the signal. You can connect 0..n slots to a signal, you can connect a signal to 0..n other signals. -
In mainwindow.h I created a slot
class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); MyUDP udp; public slots: void ShowUdpMessage(const QString& msg, const QByteArray data); //and so on...
in mainwindow.cpp
void MainWindow::ShowUdpMessage(const QString& msg, const QByteArray data) { QByteArray arr = data; ui->textEditNetRX->append(msg); }
now in main.cpp
MainWindow w; w.show(); QObject::connect(&???, &???, &w, &MainWindow::ShowUdpMessage);
How do I tie the signal source?
The signal generates by MyUDP udp that resides in the MainWindow class. -
@jenya7 You should do the connection inside MainWindow (for example in its constructor), because MainWindow needs the signal and it also has the MyUDP instance...
"although it declared public:MyUDP udp" - don't declare it public, just do the connection inside MainWindow.
-
I try in the constructor
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->tabWidget->setCurrentIndex(0); ui->textEditTerminalTx->installEventFilter(this); QObject::connect(&udp, &MyUDP::ShowUdpMessage, &MainWindow, &MainWindow::ShowUdpMessage); }
third argument - &MainWindow <- 'MainWindow' does not refer to a value.