QTcpSocket how to return QString - qt

I have a service: GWT client calls QT QTcpSocket function that make a request to a device and gets responses(it cannot be only the one response. I should waiting for all of them).
According to the QT documentation I can't use waitForReadyRead() function because I use Windows platform.
Note: This function may fail randomly on Windows. Consider using the
event loop and the readyRead() signal if your software will run on
Windows. http://doc.qt.io/qt-5/qabstractsocket.html#waitForReadyRead
I have only one decision now:
pseudo code:
QString MainQTFunc() {
create new thread;
while (!thread.isStopped()) {
sleep(x);
}
return QString variable from thread to GWT client;
}
New Thread {
run() {
make a TcpRequest to the device...
}
boolean isStopped() {
if(we got the response!!!) {
return true;
}
}
}
Does it the best solution to do so? I can't understand how to send simply QString variable after I get the result. Is it really impossible to the powerful QT?
Now I have(without any threads):
// The function should to return QString to the GWT client
QString MainWindow::TcpConnect(QByteArray data) {
_pSocket = new QTcpSocket( this );
connect( _pSocket, SIGNAL(readyRead()), SLOT(readTcpData()) );
connect( _pSocket, SIGNAL(connected()), SLOT(connected()) );
connect( _pSocket, SIGNAL(disconnected()), SLOT(disconnected()) );
dataGlobal = data;
_pSocket->connectToHost("IP", port);
//waiting here for all responses and sendinig the last response
return responseHexGlobal;
}
void MainWindow::connected() {
qDebug() << "connected. " << QDateTime::currentDateTime();
_pSocket->write( dataGlobal );
}
void MainWindow::disconnected() {
qDebug() << "disconnected. " << QDateTime::currentDateTime();
}
void MainWindow::readTcpData()
{
QByteArray data = _pSocket->readAll();
QByteArray as_hex_string = data.toHex();
QString response = QString(as_hex_string);
if(some condition here...) {
responseHexGlobal = response;
_pSocket->disconnectFromHost();
}
}

It's the best solution I've found. It works, but I don't like it
QString JSPrinter::connectTcp(QByteArray data) {
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
_pSocket = new QTcpSocket( this ); // <-- needs to be a member variable: QTcpSocket * _pSocket;
connect( _pSocket, SIGNAL(readyRead()), SLOT(readTcpData()) );
connect( _pSocket, SIGNAL(connected()), SLOT(connected()) );
connect( _pSocket, SIGNAL(disconnected()), SLOT(disconnected()) );
connect( &timer, SIGNAL(timeout()), &loop, SLOT(quit()) );
loop.connect( this, SIGNAL(exitLoop()), SLOT(quit()) );
dataGlobal = data;
_pSocket->connectToHost(ip_, port_);
timer.start(75000);
loop.exec();
if(timer.isActive())
logger()->info("ok");
else
logger()->info("timeout");
return responseHexGlobal;
}
void JSPrinter::connected() {
qDebug() << "connected. " << QDateTime::currentDateTime();
_pSocket->write( dataGlobal );
}
void JSPrinter::disconnected() {
qDebug() << "disconnected. " << QDateTime::currentDateTime();
}
void JSPrinter::readTcpData() {
QByteArray data = _pSocket->readAll();
QByteArray as_hex_string = data.toHex();
std::string stdString(as_hex_string.constData(), as_hex_string.length());
qDebug() << "readTcpData response " << QDateTime::currentDateTime() << QString::fromStdString(stdString);
// doing something...
if(condition) {
responseHexGlobal = received;
qDebug() << "responseHexGlobal " << responseHexGlobal;
emit exitLoop();
_pSocket->disconnectFromHost();
} else {
emit exitLoop();
_pSocket->disconnectFromHost();
return;
}
}

Related

QSystemTrayIcon DoubleClick Activation results in two Trigger events

I'm developing an application, where I have a system tray icon. I'm trying to catch QSystemTrayIcon::DoubleClick in the system tray. For some reason I do not understand, I have been unable to catch. In its stead, I just get two QSystemTrayIcon::Trigger events. I have tried this using both Qt4 (v4.8.7) and Qt5 (v5.5.1). My platform is KDE/Plasma 5(v5.4.3), on Debian Testing. I have tested this even on LXDE available on Debian Testing.
So my question here is: is this a bug in Qt or some other issue else where?
/* My Header File */
class MyTrayIcon : public QSystemTrayIcon {
Q_OBJECT
public :
NBTrayIcon();
public slots:
void handleActivation( QSystemTrayIcon::ActivationReason reason );
private slots:
void toggleVisible();
void showInfo();
void quit();
Q_SIGNALS:
void newWindow();
};
/* My Cpp File */
MyTrayIcon::MyTrayIcon() : QSystemTrayIcon() {
setIcon( QIcon( ":/icons/newbreeze.png" ) );
connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), this, SLOT( handleActivation( QSystemTrayIcon::ActivationReason ) ) );
QMenu *menu = new QMenu( "TrayMenu" );
menu->addAction( "&Toggle Visible Windows", this, SLOT( toggleVisible() ) );
menu->addAction( QIcon::fromTheme( "application-exit", QIcon( ":/icons/delete.png" ) ), "&Quit NewBreeze", this, SLOT( quit() ) );
setContextMenu( menu );
};
void MyTrayIcon::handleActivation( QSystemTrayIcon::ActivationReason reason ) {
qDebug() << reason;
switch( reason ) {
case MyTrayIcon::Context: {
qDebug() << "Context";
break;
};
case MyTrayIcon::MiddleClick: {
qDebug() << "Middle Click";
break;
};
case MyTrayIcon::Trigger: {
qDebug() << "Trigger";
break;
}
case MyTrayIcon::DoubleClick: {
qDebug() << "DoubleClick";
break;
};
default:{
qDebug() << reason;
break;
};
};
};
PS: I have added the code as listed above.

Qt5 slot being called multiple times from a single emit statement

I'm relatively new to Qt, but I have done a little searching around. I have a base class that handles UDP broadcasting, and does the connect statements in the constructor of the class like this:
NetworkConnection::NetworkConnection(QObject *parent)
: QObject(parent) // Based on QObject
, m_server_search( new QUdpSocket ) // Our UDP Broadcast socket
, m_waiting_for_server( false )
, m_found_server( false )
{
qDebug() << "NetworkConnection::constructor";
connect( m_server_search, SIGNAL(readyRead()), this, SLOT(serverResponse()), Qt::UniqueConnection );
if ( m_server_search->bind( QHostAddress::AnyIPv4, (quint16)PORT_MULTICAST, QUdpSocket::ShareAddress ) )
{
if ( m_server_search->joinMulticastGroup( QHostAddress( MULTICAST_GROUP ) ) )
{
connect( this, SIGNAL(broadcast(NetworkMessage)), this, SLOT(broadcast_message(NetworkMessage)), Qt::UniqueConnection );
this->m_ping_timer = this->startTimer(2000);
qDebug() << "Ping timer id=" << this->m_ping_timer;
} else qDebug() << "Couldn't start multicast listener";
} else qDebug() << "Couldn't bind multicast to port" << PORT_MULTICAST;
}
I set up a signal/slot interface for broadcasting:
signals:
void serverFound();
void serverNotFound();
void broadcast(NetworkMessage);
private slots:
void serverResponse();
void broadcast_message( NetworkMessage msg );
And broadcast_message looks like this:
void NetworkConnection::broadcast_message( NetworkMessage msg )
{
QByteArray raw = msg.toString();
qDebug() << "NetworkConnection::broadcast_message>" << raw;
if ( m_server_search->writeDatagram( raw.data(), raw.size(), QHostAddress(MULTICAST_GROUP), (quint16)PORT_MULTICAST ) < 1 ) qDebug() << "Failed broadcast last message";
}
My timer works well, and here is the code:
void NetworkConnection::timerEvent(QTimerEvent *event)
{
qDebug() << "NetworkConnection::timerEvent with id" << event->timerId() << "(ping timer=" << this->m_ping_timer << ")";
if ( event->timerId() == this->m_ping_timer )
{
qDebug() << "NetworkConnection::pingForServer";
if ( m_waiting_for_server && !m_found_server )
{
qDebug() << "Server not found!";
emit this->serverNotFound();
return;
}
if ( !m_found_server )
{
qDebug() << "Sending a ping to the server";
NetworkMessage msg( m_software_guid, get_microseconds(), QString("whoisaserver") );
emit this->broadcast( msg );
m_waiting_for_server = true;
m_found_server = false;
}
}
}
I only get the text "Sending a pint to the server" once, but my broadcast_message outputs it's qDebug() multiple times.
I'm not explicitly using multiple threads, and as you can see I'm using Qt::UniqueConnection, which is apparently having no affect?
SO why would the slot be called multiple times? I've even tried debugging it a little and just calling this->broadcast( ... ) without using emit, and it still gets called multiple times.
Edit: I just added a counter to the broadcast_message slot, and it gets called 340 times. Is there any significance to that?

unable to establish two way communication using qt

I have used QTcpSocket and QTcpServer class of qt to establish two way communication. I am able to send data from client to server. But am not getting the response back from server i.e my client.cpp never fires readyRead() signal. I have checked using Wireshark that my data from the server is available in specifed port.
I am posting my client.cpp code( Please help) :
Client::Client(QObject* parent): QObject(parent)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()),
this, SLOT(startTransfer()));
connect(socket, SIGNAL(readyRead()),this, SLOT(startRead()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(socketError(QAbstractSocket::SocketError)) );
}
Client::~Client()
{
socket->close();
}
void Client::start(QString address, quint16 port)
{
addr.setAddress(address);
socket->connectToHost(addr,port,QTcpSocket::ReadWrite);
}
void Client::startTransfer()
{
printf("Connection established.\n");
char buffer[1024];
forever
{
printf(">> ");
gets(buffer);
int len = strlen(buffer);
buffer[len] = '\n';
buffer[len+1] = '\0';
socket->write(buffer);
socket->flush();
}
}
void Client::startRead()
{
cout<<"inside startRead()<<endl";
while(socket->canReadLine())
{
QByteArray ba = socket->readLine();
if(strcmp(ba.constData(), "!exit\n") == 0)
{
socket->disconnectFromHost();
break;
}
printf(">> %s", ba.constData());
}
}
void Client::socketError(QAbstractSocket::SocketError )
{
qDebug()<<"error" ;
}
Looks like you have forever loop here. This means that your Qt main eventloop never gets the control back after you call startTransfer(). How do you suppose the Qt should run the startRead() code if you block your execution thread with infinite loop?
For Amartel adding the server code:
Server::Server(QObject* parent): QObject(parent)
{
// cout << "Before connect" << endl;
connect(&server, SIGNAL(newConnection()),
this, SLOT(acceptConnection()));
cout << "Listening.." << endl;
server.listen(QHostAddress::Any, 9999);
// cout << "Server started.." << endl;
}
Server::~Server()
{
server.close();
}
void Server::acceptConnection()
{
// cout << "In acceptConnection" << endl;
client = server.nextPendingConnection();
connect(client, SIGNAL(readyRead()),
this, SLOT(startRead()));
}
void Server::startRead()
{
while(client->canReadLine())
{
QByteArray ba = client->readLine();
if(strcmp(ba.constData(), "!exit\n") == 0)
{
client->disconnectFromHost();
break;
}
printf(">> %s", ba.constData());
int result = 0;
bool ack = true;
result = client->write("I Reached");
cout<<result<<endl;
if(result <= 0)
qDebug("Ack NOT sent to client!!!");
else
qDebug("Ack sent to client.");
// client->write("I Reached");
client->flush();
}
}

Dequeue always fails, queue is always empty

I do not know what the heck is wrong with my code that it never Dequeus the queue, instead isEmpty always meets true.
class ConcurrentQueue
{
private:
QQueue<QByteArray> dataStore;
public:
void Enqueue(QByteArray value);
QByteArray Dequeue();
bool isEmpty();
private:
QMutex mutex;
};
void ConcurrentQueue::Enqueue(QByteArray value)
{
qDebug() << dataStore.length();
mutex.lock();
dataStore.enqueue(value);
mutex.unlock();
qDebug() << dataStore.length();
}
QByteArray ConcurrentQueue::Dequeue()
{
// mutex.lock();
// return dataStore.dequeue();
// mutex.unlock();
QByteArray tmp;
mutex.lock();
if(!dataStore.isEmpty())
{
tmp = dataStore.dequeue();
}
mutex.unlock();
return tmp;
}
bool ConcurrentQueue::isEmpty()
{
return dataStore.isEmpty();
}
next a timer is connected to a slot to Enqueu a packet every lt's say 10 milliseconds:
QByteArray built((char*)data, len) ;
//qDebug() << built.toHex();
qDebug() << "EnQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ";
queue.Enqueue(built);
A thread regularly checks if this queue is not empty it dequeues the queue and does something, but isEmplty always returns true
if(queue.isEmpty())
{
qDebug() << "#####################################";
return;
}
//NEVER COMES HERE
QByteArray rd15Bytes = queue.Dequeue();
here's the thread:
Write::Write()
{
}
void Write::run(){
while(1)
{
rs.writeToSerialPort(); // in this function above always isemplty is true
this->msleep(10);
}
}

Qt HTTP GET freezes screen

I'm writing a Qt program to get an image from site and insert in a QLabel. When I send my request my screen freezes and nothing more occurs.
Notice I'm new in Qt.
Based on my initial knowledge of Qt it's enough send a signal when download is finished.
...
MapReader::MapReader(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
imageLabelMap = ui.imageMap;
getImageButton = ui.getImageButton;
networkManager = new QNetworkAccessManager(this);
setup();
}
MapReader::~MapReader()
{
}
void MapReader::setup()
{
QObject::connect(getImageButton, SIGNAL(clicked()), this, SLOT(triggerDownload()));
QObject::connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedDownload(QNetworkReply*)));
}
void MapReader::setImage(QByteArray imageBytes)
{
QImage map;
...
}
void MapReader::triggerDownload()
{
QUrl url("http://images.tsn.ca/images/stories/2012/09/26/terrydunfield_2035-430x298.jpg");
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
}
void MapReader::finishedDownload(QNetworkReply* reply)
{
reply->deleteLater();
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if(reply->error() != QNetworkReply::NoError)
{
QMessageBox msgBox;
msgBox.setWindowTitle("Error");
msgBox.setInformativeText("Error on downloading file: \n"+reply->errorString());
msgBox.exec();
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
QUrl url = attribute.toUrl();
qDebug() << "must go to:" << url;
return;
}
setImage(reply->readAll());
}
I think there is some code missing that might give us a clue. You have
QObject::connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
But I don't see where loop is defined? Sounds like you are running an additional event loop?
Regardless, you don't need that. This should be as simple as:
void MapReader::triggerDownload()
{
QUrl url("http://images.tsn.ca/images/stories/2012/09/26/terrydunfield_2035-430x298.jpg");
QNetworkReply* reply = networkManager->get(QNetworkRequest(url));
QObject::connect(reply, SIGNAL(finished()), this, SLOT(finishedDownload()));
}
void MapReader::finishedDownload()
{
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); // sender() allows us to see who triggered this slot - in this case the QNetworkReply
QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QVariant redirectionTargetUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if(reply->error() != QNetworkReply::NoError)
{
QMessageBox msgBox;
msgBox.setWindowTitle("Error");
msgBox.setInformativeText("Error on downloading file: \n"+reply->errorString());
msgBox.exec();
return;
}
QVariant attribute = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (attribute.isValid())
{
QUrl url = attribute.toUrl();
qDebug() << "must go to:" << url;
return;
}
setImage(reply->readAll());
reply->deleteLater();
}
Make sure you have defined finishedDownload() as a slot in your header file

Resources