Receiving Udp packets using Qt - 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()));
}
}

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 QUdpSocket triggers readyRead() on sending data

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.

libconnman-qt connect to wifi

Hi currently I am working on project that require to connect to wifi and I am using libconnman-qt.
Everything goes well (enable/disable wifi, list of wifi), until I found a problem to connect to the wifi. So when I connect the service to wifi by :
mCurrentNetworkService->setPassphrase(ui->linePassword->text());
mCurrentNetworkService->requestConnect();
Occurs an error that says : "Not Registered". I don't know what happen, since the lib not give any clue for me. Or maybe there is step that I missed?
You must first register an "agent" that can respond to requests for input from the connman daemon. Here is a simple example.
#include <networkservice.h>
#include <useragent.h>
class Wifi : public QObject {
Q_OBJECT
public:
Wifi(QObject *parent = 0) :
QObject(parent), m_agent(NULL), m_service(NULL) {
//Register an agent to handle requests from connmand
m_agent = new UserAgent(this);
//Connect to UserAgent signal
connect(m_agent, SIGNAL(userInputRequested(QString, QVariantMap)),
this, SLOT(agentRequestedUserInput(QString, QVariantMap)));
}
~Wifi() {}
public Q_SLOTS:
void agentRequestedUserInput(QString path, QVariantMap fields) {
Q_UNUSED(path)
QVariantMap reply;
reply.insert("Passphrase", QString("pass1234"));
m_agent->sendUserReply(reply);
}
void connectToService(QString servicePath) {
// Add logic to find NetworkService pointer for the service you will connect to
// pseudo code
// m_service = findService(servicePath);
m_service->requestConnect();
}
private:
UserAgent *m_agent;
NetworkService *m_service;
}

How to emit error for QLocalSocket

I am implementing 'Local fortune server' example (from Qt 4.7.3) as a service on Windows.
What i want is that when someone paused the service, the local server should notify the error to the connected local socket (local fortune client). The error can be QLocalSocket::ServerNotFoundError.
Now, How to generate this error from server example. Please look at the following code where i want to generate this error.
void FortuneServer::incomingConnection(quintptr socketDescriptor)
{
if (disabled) {
**// here i want to emit QLocalSocket::ServerNotFoundError**
return;
}
QString fortune = fortunes.at(qrand() % fortunes.size());
FortuneThread *thread = new FortuneThread(socketDescriptor, fortune, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
void FortuneServer:: pause()
{
disabled = true;
}
If you want your server to notify your clients I think you should create and send your own message like :
QString fortune = "Server down";
But this will occure when your server has incoming message.
or you can shutdown the server whith the QTcpServer::close() method
void FortuneServer:: pause()
{
this.close();
}
your client app will lost its connection and you should be able to get the signal you want in it with this :
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayError(QAbstractSocket::SocketError)));
You can't emit QLocalSocket::ServerNotFoundError, because it's not a signal. You should define your own signal and emit it instead (you can pass values in signals). You should also implement slot and connect signal to it. Read more about signals and slots.

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