There is an example from the official QT documentation of QUdpSocket datagrams reading:
void Server::initSocket()
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, 7755);
connect(udpSocket, SIGNAL(readyRead()),
this, SLOT(readPendingDatagrams()));
}
void Server::readPendingDatagrams()
{
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
processTheDatagram(datagram);
}
}
I'm trying to understand what exactly happens, when readyRead() signal emits. In the while loop (in Server::readPendingDatagrams() slot) we read available datagrams, but what happens if new datagram appends to the socket, while we still read the previous datagrams batch? readyRead() signal will be emited again? But how while loop will be read the data in this case - from last appended datagram or in some other way?
Related
Currently I am writing an application for Windows 10 to read UDP packets with a QUDPSocket through the Ethernet adapted to thunderbolt.
WireShark and Microsoft UDP Receiver/Sender both see the proper UDP packets and where each sender ip address, port#, local ip address and local port# are.
But whenever I try to use QUDPSocket, it has trouble receiving any packets. The readyRead() is never signaled.
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
socket = new QUdpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()), Qt::QueuedConnection);
socket->bind(QHostAddress::AnyIPv4, 56666);
}
void MainWindow::processPendingDatagrams()
{
QByteArray array;
QHostAddress sender;
quint16 senderPort;
while (socket->hasPendingDatagrams())
{
array.fill(0, socket->pendingDatagramSize());
socket->readDatagram(array.data(),
array.size(),
&sender,
&senderPort);
qDebug()<<socket->pendingDatagramSize();
}
}
I tried multiple versions of binding but none worked.
Thanks for any help in advance.
I have a program that sends and receives broadcast messages. If I run two copies of these programs on the same PC, everything works just fine. If I run each copy on different PCs, then the broadcast messages are not received. I utilized Wireshark to verify whether the packets were sent (yes they were). In addition, on PC "A" Wireshark does not observe the sent packets, but on PC "B" everything is OK. Could the problem be in hardware?
Receiver code:
Receiver::Receiver(QObject *parent) : QObject(parent)
{
udpSocket = new QUdpSocket(this);
udpSocket->bind(45454, QUdpSocket::ShareAddress);
timer = new QTimer(this);
timer->start(500);
connect(timer, SIGNAL(timeout()), this, SLOT(processPendingDatagrams()));
}
void Receiver::processPendingDatagrams()
{
qDebug("first entrance");
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
qDebug() << datagram.data();
qDebug("Receive");
sendToQML(datagram.data());
}
}
Sender code:
Sender::Sender(QObject *parent) : QObject(parent)
{
messageNo = 0;
udpSocket = new QUdpSocket(this);
}
void Sender::broadcastDatagram(int message)
{
QByteArray datagram = QByteArray::number(message);
udpSocket->writeDatagram(datagram.data(), datagram.size(),
QHostAddress::Broadcast, 45454);
}
void Sender::sendBroadcast(int message)
{
qDebug() << message;
broadcastDatagram(message);
}
UPDATE
I managed to send and receive packets through an ethernet connection (via a cable).
I have a class COMPort for interaction with QSerialPort. When I create exemplar this class from main thread, then I can send and receive data and signal readyRead will be emitted. But when I try make the same from thread, signal readyRead will be not emitted.
void GetSN_Thread::run()
{
// Connect to serial port with default baudrate
serialPort = new COMPort();
if (!(serialPort->connectCOM(portName, DEFAULT_BAUDRATE)))
{
//Send signal -> Unable connect to this com port
emit showMsg("Unable to connect to " + portName + "\n");
return;
}
emit showMsg(portName + " connected" + "\n");
serialPort->write("Hello");
After this I wait a signal readyRead, but this was not emitted.
When I make this from main thread, then it all works.
serialPort = new COMPort();
QString btlMsg= "";
if (serialPort->connectCOM(comName, comBR))
{
serialPort->write(COMMAND_START);
rcvThr = new ReceiveThread(serialPort, 4);
connect(rcvThr,SIGNAL(sendString(QString)), this, SLOT(msgHandler(QString)));
rcvThr->start();
}
And code for COMPort:
bool COMPort::connectCOM(QString name, int baudrate)
{
this->portName = name;
this->baudrate = baudrate;
connect(&serialPort, SIGNAL(readyRead()), this, SLOT(readDataCOM()));
serialPort.setPortName(this->portName);
serialPort.setDataBits(QSerialPort::Data8);
serialPort.setParity(serialPort.NoParity);
serialPort.setBaudRate((QSerialPort::BaudRate)this->baudrate);
serialPort.setStopBits(serialPort.OneStop);
serialPort.open(QIODevice::ReadWrite);
if (serialPort.isOpen())
return true;
else
return false;
}
Method for reading data:
void COMPort::readDataCOM()
{
char chData;
while (serialPort.read(&chData,1))
{
queueMsg.append(chData);
}
}
Everything ok... but where is signal emitted? I don't see anywhere in code emit readyRead(); and nowhere is connected showMsg(); signal.
I have problem with QUdpSocket. I want to create a simple program to send and receive data using the UDP protokol. I already read many similar topic but I do not found solved. Communication worked only for QHostAdress::LocalHost, then I give this same data as send, but if I want to send data to outside set concrete address, for example 194.181.161.134, that does not worked. That mean data is send but I can't receive. This is my code:
class Okno_GL : public QMainWindow
{
Q_OBJECT
public:
explicit Okno_GL(QWidget *parent = 0);
QWidget *wg;
QPushButton *pb;
QPushButton *pl;
QGridLayout *gr;
QUdpSocket *socket;
QHostAddress host;
QHostAddress bcast;
signals:
public slots:
void SLOT_Write();
void SLOT_load();
};
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver();
QUdpSocket *udpSocket;
public slots:
void SLOT_processPendingDatagrams();
void SLOT_StCh(QAbstractSocket::SocketState state);
};
Okno_GL::Okno_GL(QWidget *parent) :
QMainWindow(parent)
{
pb = new QPushButton("write" , this);
pl = new QPushButton("read" , this);
wg = new QWidget(this);
setCentralWidget(wg);
gr = new QGridLayout(wg);
gr->addWidget(pb);
gr->addWidget(pl);
socket = new QUdpSocket(this);
connect(pb , SIGNAL(clicked()) , SLOT(SLOT_Write()));
connect(pl , SIGNAL(clicked()) , SLOT(SLOT_load()));
}
void Okno_GL::SLOT_Write()
{
QByteArray datagram = "gS";
int send;
send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
}
void Okno_GL::SLOT_load()
{
}
Receiver::Receiver()
{
udpSocket = new QUdpSocket(this);
connect(udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)) , this , SLOT(SLOT_StCh(QAbstractSocket::SocketState)));
if(udpSocket->bind(QHostAddress::Any , 1200))
{
qd "bind";
}
else
{
qd "not bind";
}
}
void Receiver::SLOT_processPendingDatagrams()
{
qd "receiver";
QByteArray datagram;
do {
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size());
} while (udpSocket->hasPendingDatagrams());
qd "datagram" << datagram;
}
void Receiver::SLOT_StCh(QAbstractSocket::SocketState state)
{
qd "slot" << state;
QByteArray datagram = "gS";
if ( state == QAbstractSocket::BoundState ) {
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(SLOT_processPendingDatagrams()) , Qt::QueuedConnection);
}
}
You should use write() instead of writeDatagram()
qint64 QUdpSocket::writeDatagram(const char * data, qint64 size, const QHostAddress & address, quint16 port)
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.
So, I rebuild my code accordingly with your proposition. I add this line in construktor class Okno_GL.
socket = new QUdpSocket(this);
socket->connectToHost(QHostAddress("194.181.161.134") , 1200);
Here is slot to send
void Okno_GL::SLOT_Write()
{
QByteArray datagram = "gS";
int send;
// send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
send = socket->write(datagram);
qd " send" << send;
}
Receiver code is not change, so I still white for signal readRedy() ,and I do not get him after send data.
PS. I whant to add that I have other option to connetc, is very very simply file command *bat whitch connect this host without any problem . This is proof that my network or admin nothing blocks (port , ip);
Pss thanks for your interest
Problem solved ! It is very stupid mistake. I should be send 3 bajt instead 2. The 3 bajt it is 0x0D.
Following code is work
socket = new QUdpSocket(this);
socket->bind(QHostAddress::Any, 1200);
and send
QByteArray datagram = "gS";
datagram.append(0x0D);
int send;
send = socket->writeDatagram(datagram.data(), QHostAddress("194.181.161.134"), 1200);
and receive after signal readyRead()
qd "receiver";
QByteArray datagram;
do {
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(), datagram.size());
} while (socket->hasPendingDatagrams());
qd "datagram" << datagram;
very help mi wireshark. Thanks for all
What I'm having is a strange problem in typical scenario: QTcpServer's method incomingConnection is overrided in custom class, and any received connection is planned for processing in separate thread on QThreadPool.
Server:
void FooS::incomingConnection(qintptr socketDescriptor)
{
QThreadPool *thread_pool = QThreadPool::globalInstance();
FooSocket *fs = new FooSocket();
fs->setSocket(socketDescriptor);
thread_pool->start(fs);
}
Task:
class FooSocket: public QObject, public QRunnable;
...
private slots:
void connectionIncomingData();
...
void FooSocket::run() {
QTcpSocket *socket = new QTcpSocket();
qDebug() << "SD: " << socketDescriptor; // is correct
if (!socket->setSocketDescriptor(socketDescriptor)) {
qDebug() << "Can't set socket descriptor";
emit error(socket->error());
return;
}
// -- had no effect here
// socket->moveToThread(QThread::currentThread());
connect(socket, SIGNAL(readyRead()), this, SLOT(connectionIncomingData()));
connect(socket, SIGNAL(disconnected()), this, SLOT(connectionClosed()));
}
readyRead signal doesn't gets triggered, but socket client is confirmed (tcpdump) to send data..
After making QRunnable to spawn a QThread object with socket logics inside, and toying with setAutoDelete, moveToThread - still no effect.
In order to process events in a QRunnable, a thread needs to have its own event loop, it mustn't rely on the one from the main thread. From what you've shown in your code, your thread quickly starts, then exits without running a loop.
Try adding
QEventLoop loop;
// connect a signal to the event loop's quit() slot
loop.exec();