Qt QUdpSocket triggers readyRead() on sending data - qt

I have written following simple program for UDP communication:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::AnyIPv4, 4000);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readDataFromSocket()));
udpSocket->writeDatagram("Test Data", QHostAddress("192.168.2.91"), 3000);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::readDataFromSocket()
{
while (udpSocket->hasPendingDatagrams()) {
udpSocket->receiveDatagram();
qDebug()<<"UDP data received";
}
}
Now the problem is that, when I run this program, readyRead() also fires on sending data.
Few interesting findings:
I have tried sending data to different IPs on my network. For few IPs
it doesn't trigger my readyRead() function. But for most of the
IPs readyRead() does trigger.
Though udpSocket->hasPendingDatagrams() returns true, but it doesn't
have any data.
I am running Qt 5.12.3 (MSVC 2017, 32 bit). When I run same program in Qt 5.3.2 (MSVC 2010, 32 bit), it works fine, my readyRead() never fires.
Anyone can help?

As per qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port) docs:
Warning: Calling this function on a connected UDP socket may result in an error and no packet being sent. If you are using a connected socket, use write() to send datagrams.

Related

Sending a series of messages to a client from a QWebSocketServer in real-time

I have implemented a websocket server in a QCoreApplication. As soon as a connection is established with a client, I wish to send a series of messages to it immediately in real-time with a delay of 0.5 seconds between messages. However, the individual messages reach the client only after all the messages have been sent or right after sendMyMessages() method returns in the below implementation of my websocket server. If I have a huge number of messages to send, the client has to wait for a long time before getting all the messages in one go.
MyWebSocketServer.h
#ifndef MYWEBSOCKETSERVER_H
#define MYWEBSOCKETSERVER_H
#include <QtCore/QObject>
#include <QtCore/QList>
#include <QtCore/QByteArray>
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)
class MyWebSocketServer : public QObject
{
Q_OBJECT
public:
explicit MyWebSocketServer(quint16 port,
bool debug = false,
QObject *parent = nullptr);
~MyWebSocketServer();
Q_SIGNALS:
void closed();
private Q_SLOTS:
void onNewConnection();
void socketDisconnected();
private:
void sendMyMessages(QWebSocket *client);
QWebSocketServer *m_pWebSocketServer;
QList<QWebSocket *> m_clients;
bool m_debug;
};
#endif // MYWEBSOCKETSERVER_H
MyWebSocketServer.cpp
#include "MyWebSocketServer.h"
#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>
#include <QtWebSockets/qwebsocketserver.h>
#include <QtWebSockets/qwebsocket.h>
#include <QtCore/QDebug>
QT_USE_NAMESPACE
MyWebSocketServer::MyWebSocketServer(quint16 port,
bool debug,
QObject *parent)
: QObject(parent)
, m_pWebSocketServer(new QWebSocketServer(
QStringLiteral("My WebSocket Server"),
QWebSocketServer::NonSecureMode,
this))
, m_debug(debug)
{
connect(m_pWebSocketServer,
&QWebSocketServer::newConnection,
this,
&MyWebSocketServer::onNewConnection);
connect(m_pWebSocketServer,
&QWebSocketServer::closed,
this,
&MyWebSocketServer::closed);
m_pWebSocketServer->listen(QHostAddress::LocalHost, port);
}
MyWebSocketServer::~MyWebSocketServer()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
void MyWebSocketServer::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket,
&QWebSocket::disconnected,
this,
&MyWebSocketServer::socketDisconnected);
m_clients << pSocket;
sendMyMessages(pSocket);
}
void MyWebSocketServer::sendMyMessages(QWebSocket *client)
{
std::fstream jsonStringFileHandler;
jsonStringFileHandler.open("my-messages.txt", std::ios::in);
if (jsonStringFileHandler.is_open())
{
std::string message;
while(getline(jsonStringFileHandler, message))
{
// Individual messages don't go through immediately
// Only after this method returns, all the messages show up on the client's end
// Is it possible to send the individual messages immediately? (probably with a 0.5 second delay)
client->sendTextMessage(QString::fromUtf8(message.c_str()));
}
jsonStringFileHandler.close();
}
}
void MyWebSocketServer::socketDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (pClient)
{
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
Only after the sendMyMessages() returns, the client gets all the messages. It is not in real-time. I understand it would be possible to achieve what I am after using some asynchronous programming technique but I unable to figure out a way to set it up in my implementation of the websocket server.
Here is an implementation of the websocket server that worked for me in Python using the websockets and asyncio modules. However, I wish to implement the same logic in C++ using Qt.
import asyncio
import websockets
async def sendMyMessages(websocket, path):
with open("my-messages.txt") as fp:
lines = fp.readlines()
for line in lines:
await asyncio.sleep(0.5)
await websocket.send(line.strip())
start_server = websockets.serve(sendMyMessages, "127.0.0.1", 3000)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
One of the approaches I found uses QWebSocket::flush() immediately after a call to QWebSocket::sendTextMessage().
From the docs on QWebSocket::flush(),
This function writes as much as possible from the internal write buffer to the underlying network socket, without blocking. If any data was written, this function returns true; otherwise false is returned. Call this function if you need QWebSocket to start sending buffered data immediately. The number of bytes successfully written depends on the operating system. In most cases, you do not need to call this function, because QWebSocket will start sending data automatically once control goes back to the event loop.
However, I am not sure if this is the right approach as the doc indicates that the data may not be written to the underlying network socket reliably. I will be happy to know if there is a better technique out there!
client->sendTextMessage(QString::fromUtf8(message.c_str()));
client->flush();
std::this_thread::sleep_for(std::chrono::milliseconds(50));

QT: problems with the continuous reading of data from the serial port

I'm reading data from serial port with QT, in mainwindow I've write this code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QTextStream>
#include<QSerialPort>
#include<QSerialPortInfo>
#include<QtDebug>
#include<QThread>
QSerialPort *serial;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWindow),
m_standardOutput(stdout)
{
ui->setupUi(this);
serial= new QSerialPort(this);
serial->setPortName("COM3");
serial->setBaudRate(QSerialPort::Baud115200);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
serial->open(QIODevice::ReadOnly);
connect(serial, &QSerialPort::readyRead, this, &MainWindow::ReaderH);
float HUM;
HUM=H;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::ReaderH()
{
quint64 X=20;
serial->waitForReadyRead();
m_readData=serial->QSerialPort::read(X);
//if (!m_timer.isActive())
// m_timer.start(5000);
inter2=QString(m_readData);
QStringList firstlist2= inter2.split(";");
m_readData3=firstlist2.takeFirst();
H=m_readData3.toFloat();
qDebug() <<"Data:"<<m_readData<< " \r\n";
//QThread::sleep(11);
}
the program reads the data correctly for a few seconds, after a while the reading starts to be out of phase, like this:
Data: "60.904655;25.779804$"
Data: "60.970406;25.816269$"
Data: "60.988335;25.798037$"
Data: "60."
Data: "883736;25.7"
Data: "61570$"
Data: "60."
Data: "91063"
Data: "7;25.779804$"
Data: "60."
Data: "934544;25."
Data: "798037$"
Data: "60"
Data: ".871784;25.798037$"
I can't understand how to solve the problem.
Thank you for your time.
When reading from a serial port, you need to cut the "stream" into "messages" yourself. You should not make any assumption about the timing of your data in order to be robust.
When data are received, you should input them to a "decoder", i.e. typically a class that reads byte per byte and finds the "delimiters" of the packets.
The decoder class usually have an internal buffer and may look like that:
class Decoder : public QObject
{
Q_OBJECT
signals:
void messsageReceived(QByteArray message);
public:
void decode(const QByteArray& bytes)
{
for (char c : bytes)
{
if (c == '$')
{
emit messsageReceived(m_buffer);
m_buffer.clear();
}
else
{
m_buffer.append(c);
}
}
}
private:
QByteArray m_buffer;
};
Also there is usually no guarantee that you will start reading at the beginning of a packet. The first read might occur at the middle of a packet, that's why most protocol use a "Start" and a "Stop" sequence, or you should drop the first packet if you are not able to validate its consistency. In the snippet above, the first packet is not handled.
Also, serial ports do not guarantee to transmit bytes error free over the line, so it is mandatory to have a validation mechanism if the data are sensible, such as a checksum (i.e. CRC). If some data is corrupted, the packet should be dropped, and maybe a mechanism has to be put in place at a higher level so that the packet is re-transmitted (if needed).

Receiving Udp packets using Qt

I'm trying to receive udp packets which are send to the braodcast. According to wireshark they are incoming but I don't receive anything. At first Ithough the firewall was blocking me but even with the firewall turned down I receive nothing. I also need to say that I'm new to C++ so I have some problems understanding the syntax of examples in the qt documentation. I don't understand why it doesn't work, the answer from Possible duplikate totally crushed my code.
#include "receiver.h"
Receiver::Receiver(QWidget *parent)
: QWidget(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(12375, QUdpSocket::ShareAddress);
connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(processPendingDatagrams()));
}
void Receiver::processPendingDatagrams()
{
QByteArray datagram;
while (udpSocket->hasPendingDatagrams())
{
datagram.resize(int(udpSocket->pendingDatagramSize()));
udpSocket->readDatagram(datagram.data(), datagram.size());
statusLabel->setText(tr("Received datagram: \"%1\"")
.arg(datagram.constData()));
}
}

Qt cannot connect to the server

I am trying to create simple server that will just show when somebody have connected to me. Everything works fine when client and server use "localhost" as a host name to connect, but when I changed localhost to my ip address then I got timeout error :(
There is my code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
server_status=0;
}
void MainWindow::on_starting_clicked()
{
tcpServer = new QTcpServer(this);
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newuser()));
if (!tcpServer->listen(QHostAddress::Any, 33333) && server_status==0) {
qDebug() << QObject::tr("Unable to start the server: %1.").arg(tcpServer->errorString());
ui->textinfo->append(tcpServer->errorString());
} else {
server_status=1;
qDebug() << tcpServer->isListening() << "TCPSocket listen on port";
ui->textinfo->append(QString::fromUtf8("Server started!"));
qDebug() << QString::fromUtf8("Server started!");
}
}
void MainWindow::on_stoping_clicked()
{
if(server_status==1){
foreach(int i,SClients.keys()){
QTextStream os(SClients[i]);
os.setAutoDetectUnicode(true);
os << QDateTime::currentDateTime().toString() << "\n";
SClients[i]->close();
SClients.remove(i);
}
tcpServer->close();
ui->textinfo->append(QString::fromUtf8("Server stopped!"));
qDebug() << QString::fromUtf8("Server stopped!");
server_status=0;
}
}
void MainWindow::newuser()
{
if(server_status==1){
qDebug() << QString::fromUtf8("New connection!");
ui->textinfo->append(QString::fromUtf8("New connection!"));
QTcpSocket* clientSocket=tcpServer->nextPendingConnection();
int idusersocs=clientSocket->socketDescriptor();
SClients[idusersocs]=clientSocket;
connect(SClients[idusersocs],SIGNAL(readyRead()),this, SLOT(slotReadClient()));
}
}
And for client:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
socket = new QTcpSocket(this);
socket->connectToHost("95.220.162.117", 33333);
socket->waitForConnected();
}
MainWindow::~MainWindow()
{
delete ui;
}
I am a novice in the field of working with network, so please explain me what I am doing wrong
"95.220.162.117" looks like a public European IP address. This public IP address is shared by all the computers/tablets/phones/etc. in your home/office. Think of it this way: The public IP address points to your router, not to a specific computer.
When a client sends a request to a public IP address, the router receives the request first. It is then the router's job to forward the request to the correct device... but in your case, your router doesn't know which device should receive the request!
There are two levels to making your connection work:
1. Private: Within your local network (Easier)
On your server, open your console and enter the following to find your private/local IP address:
ifconfig -a
Your local IP address is different from your public IP address. It identifies a specific computer on your local network. Make your client connect to this address, and your server should receive the request.
This only works when the client and the server are on the same local network (e.g. connected to the same router)
2. Public: Over the internet (Harder)
You need to set up Port Forwarding -- This tells your router to take requests received at port 33333 and forward them to your server.
To learn more about this topic, read up on Network Address Translation.

Qt QUdpSocket readyRead() signal is not triggering

I am trying to write a small UDP server application.
I have a client transmitting to this applications socket and I have verified this is sending ok using a small UDP echo program (which echoes the data received on a port to the screen) and also, I can see the packets received in wireshark.
I am using QUdpSocket and it would appear that this Binds ok on setup - but the readyRead() signal doesn't ever seem to get triggered.
I have included some of my code below - at the minute I am simply trying to emulate the little echo program.
Just to give some context to the below code - a button press on the UI calls 'setupNewSocket' on a port that is typed in on UI.
#include "sockethandler.h"
SocketHandler::SocketHandler(QObject *parent) :
QObject(parent)
{
udpSocket = new QUdpSocket(this);
connect( &w, SIGNAL(openNewUDPSocket(quint16)), this, SLOT(setupNewSocket(quint16)) );
connect( this, SIGNAL(printOnUI(QString,QString,QString)), &w, SLOT(updateUI(QString,QString,QString)) );
w.show();
}
void SocketHandler::readPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
QString data = QString( datagram.data() );
QString sender_address = sender.toString();
QString sender_port = QString("%1").arg(senderPort);
emit printOnUI(data, sender_address, sender_port);
}
}
void SocketHandler::setupNewSocket(quint16 port)
{
if( udpSocket->bind(QHostAddress::LocalHost, port) )
{
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
else
{
// bind has failed
}
}
QHostAddress::LocalHost binds to 127.0.0.1 .
Probably you need to use QHostAddress::Any which binds to 0.0.0.0.

Resources