I would like to start notepad.exe from QT and then for example write "Hello Notepad" to the input-area of Notepad from QT!
What I managed to do, is starting notepad from QT. But what ever I try I can't fill in the text in the Notepad-textedit area.
.h-File:
#ifndef MATLABPROCESS
#define MATLABPROCESS
#include "QObject"
#include <QProcess>
#include <QDebug>
class MatlabProcess : public QObject{
Q_OBJECT
public:
// enum State {IDLE, ERRORX, WRITING};
//State myState;
QProcess* myProcess;
explicit MatlabProcess (QObject* parent = 0) : QObject(parent) {
myProcess = new QProcess(this);
// myState = IDLE;
QObject::connect(myProcess, SIGNAL(readyReadStandardOutput()), SLOT(writing_stream()));
}
Q_INVOKABLE bool startMatlab(){
// QString program = "\"C:/Program Files (x86)/MATLAB/R2012a/bin/matlab.exe\"";
QString program = "\"C:/FlorianK/notepad.exe\"";
myProcess->start(program);
if (!myProcess->waitForStarted(-1)) return false;
qDebug() << "program started";
return true;
}
Q_INVOKABLE bool stopMatlab(){
//TODO
return false;
}
Q_INVOKABLE bool writeSomething(){
QByteArray script = "Hello Notepad\n";
qDebug() << myProcess->write(script);
qDebug() << myProcess->waitForFinished();
QByteArray result = myProcess->readAll();
qDebug() << "result: " + result;
}
private slots:
void writing_stream() {
if (!myProcess) return;
QTextStream out(stdout);
out << myProcess->readAllStandardOutput() << endl;
}
};
#endif // MATLABPROCESS
Because I want to do this stuff from qml, I registered this class in main.cpp
qmlRegisterType<MatlabProcess>("com.myself", 1, 0, "MatlabProcess");
From qml I call startMatlab() and than writeSomething(). The qt-output for "writesomething" will be
14
than 30seconds will happen nothing and program freezes than following lines will be printed in Qt-output
false
"result: "
The Notepad-text-area stays empty.
Related
I am new to Qt, c++, recently I am trying to use UDP to receive data on my raspberrypi1 from another raspberrypi2 (multicast). I am able to bind both of them but I can't receive the data (nopendingdatagram). I wonder what I did wrong here. (As you might notice, the code below was taken from examples found online). Thank you in advanced for helping me.
// myudp.h
#ifndef MYUDP_H
#define MYUDP_H
#include <QObject>
#include <QUdpSocket>
class MyUDP : public QObject
{
Q_OBJECT
public:
explicit MyUDP(QObject *parent = 0);
//void HelloUDP();
signals:
public slots:
void readyRead();
private:
QUdpSocket *socket;
};
#endif // MYUDP_H
// myudp.cpp
#include "myudp.h"
MyUDP::MyUDP(QObject *parent) :
QObject(parent)
{
// create a QUDP socket
socket = new QUdpSocket(this);
bool result = socket->bind(QHostAddress("224.224.0.2"), 10002);
if(result)
{
qDebug() << "Socket Connected";
}
else
{
qDebug() << "Socket Not Connected";
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}
void MyUDP::readyRead()
{
// when data comes in
bool data_pending = socket->hasPendingDatagrams();
qDebug() << data_pending;
if(data_pending)
{
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;
}
else
{
qDebug() << "No data";
}
}
#include <QCoreApplication>
#include "myudp.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyUDP client;
client.readyRead();
return a.exec();
}
The result is as follows:
Socket Connected
false
No data
I am trying to develop a generic function which determines whether two QObjects are equal. In order for this to be possible, the functions being compared must have an 'equals' method that compares various function values in each and returns true if they are all equal. Slso, this 'equal' method must be declared with Q_INVOKABLE.
However, when I attempt to call invokeMethod for the 'equals' method, it fails an an error "QMetaObject::invokeMethod: No such method F1::equals(QObject*)(QObject*)" is displayed.
Here is my test project and files:
Project file:
CONFIG += c++11 console
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
HEADERS += \
f1.h \
assert1.h
assert1.h
#ifndef ASSERT1_H
#define ASSERT1_H
#include <QObject>
#include <QDebug>
class Assert1 : public QObject
{
Q_OBJECT
public:
explicit Assert1(QObject *parent = nullptr) {}
static bool isEqual(QString msg, QObject* o1, QObject* o2)
{
if(o1 != nullptr && o2 != nullptr)
{
if(o1->metaObject()->className() != o2->metaObject()->className())
{
qDebug() << msg << " not same class type!";
return false;
}
const QMetaObject* metaObject =o1->metaObject();
int ix = metaObject->indexOfMethod(QMetaObject::normalizedSignature("equals(QObject *)"));
qDebug() << QMetaObject::normalizedSignature("equals(QObject *)");
if(ix == -1)
{
qDebug() << msg << tr("indexOfMethod(\"equals\") returns %1").arg(ix);
return false;
}
else
{
bool rslt = false;
if(!QMetaObject::invokeMethod(o1, QMetaObject::normalizedSignature("equals(QObject *)"),
Qt::DirectConnection,
Q_RETURN_ARG(bool, rslt),
Q_ARG(QObject*, o2)))
qDebug() << msg << tr("invoke method 'equals' failed for %1").arg(o1->metaObject()->className());
if(!rslt)
qDebug() << msg << tr(" objects not equal");
return false;
}
}
qDebug() << msg << "not equal";
}
signals:
public slots:
};
#endif // ASSERT1_H
f1.h
#ifndef F1_H
#define F1_H
#include <QObject>
#include <QDebug>
class F1 : public QObject
{
Q_OBJECT
public:
explicit F1(int p1, QString p2, QObject *parent = nullptr) : QObject(parent)
{
this->p1 = p1;
this->p2 = p2;
}
void setP1(int p) {this->p1 = p;}
void setP2(QString p) {this->p2 = p;}
Q_INVOKABLE bool equals(QObject* other)
{
if(qobject_cast<F1*>(other) != nullptr)
{
if(this->p1 != ((F1*)other)->p1)
return false;
if(this->p2 != ((F1*)other)->p2)
return false;
}
return true;
}
Q_INVOKABLE QString toString()
{
qDebug() << "p1 '" << p1 << " p2 = '" << p2 << "'";
}
signals:
public slots:
private:
int p1;
QString p2;
};
#endif // F1_H
main.cpp
#include <QCoreApplication>
#include "f1.h"
#include "assert1.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
F1* tf1 = new F1(1, "1");
F1* tf2 = new F1(1, "a");
F1* tf3 = new F1(1, "a");
F1* tf4 = new F1(4, "abc");
qDebug() << "tf1->equals(tf4) returns: " << (tf1->equals(tf4)?"true":"false");
qDebug() << "tf2->equals(tf3) returns: " << (tf2->equals(tf3)?"true":"false");
Assert1::isEqual("should be equal", (QObject*)tf2, (QObject*)tf3);
//return a.exec();
}
running the test produces this output:
Debugging starts
tf1->equals(tf4) returns: false
tf2->equals(tf3) returns: false
"equals(QObject*)"
QMetaObject::invokeMethod: No such method F1::equals(QObject*)(QObject*)
"should be equal" "invoke method 'equals' failed for F1"
How do I get invokeMethod to work?
The error in your case is that invokeMethod only waits for the name of the Q_SLOT or Q_INVOKABLE, does not need or want the signature, but you are passing it QMetaObject::normalizedSignature("equals(QObject*)") which returns "equals(QObject*)", so the solution is just to pass equals:
if(!QMetaObject::invokeMethod(o1, "equals",
Qt::DirectConnection,
Q_RETURN_ARG(bool, rslt),
Q_ARG(QObject*, o2)))
I want to create two-way communicate beetwen my Qt Apps. I want to use QProcess to do this. I'm calling sucesfully child app from root app and sending test data without any erro, but I can't recive any data in child app. I'll be gratefull for any help. I'm using Qt 4.7.1. Below my test code:
Root app:
InterProcess::InterProcess(QObject *parent) : QProcess(parent)
{
process = new QProcess(this);
process->start(myChildApp);
process->waitForStarted();
process->setCurrentWriteChannel(QProcess::StandardOutput);
process->write("Test");
connect( process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)) );
connect( process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()) );
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()) );
QByteArray InterProcess::read()
{
QByteArray readBuffer = process->readAllStandardOutput();
return readBuffer;
}
void InterProcess::error( QProcess::ProcessError error )
{
qDebug() << "Error!";
qDebug() << error;
}
void InterProcess::readyReadStandardError()
{
qDebug() << "Ready to read error.";
qDebug() << process->readAllStandardError();
}
void InterProcess::readyReadStandardOutput()
{
qDebug() << "The output:";
QByteArray readBuffer = process->readAllStandardOutput();
qDebug() << readBuffer;
}
Child app:
InterProcess::InterProcess(QObject *parent) : QProcess(parent)
{
process = new QProcess();
process->setCurrentReadChannel(QProcess::StandardOutput);
connect( process, SIGNAL(readyRead()), this, SLOT(readyReadStandardOutput()));
connect( process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)) );
connect( process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()) );
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()) );
process->waitForReadyRead(5000);
}
void InterProcess::readyReadStandardError()
{
qDebug() << "Ready to read error.";
qDebug() << process->readAllStandardError();
setText("REady error");
}
void InterProcess::readyReadStandardOutput()
{
setMessage("2");
qDebug() << "The output:";
QByteArray readBuffer = process->readAllStandardOutput();
qDebug() << readBuffer;
}
void InterProcess::error( QProcess::ProcessError error )
{
qDebug() << "Error!";
qDebug() << error;
setText(QString(error));
}
It's very hard to explain in one answer all mistakes, so just look at code and ask if you still got problems.
Here is example of using QProcess as IPC.
This is your main process, that creates additional process and connects to its signals
MyApplicaiton.h
#ifndef MYAPPLICATION_H
#define MYAPPLICATION_H
#include <QApplication>
class InterProcess;
class MyApplication : public QApplication {
Q_OBJECT
public:
MyApplication(int &argc, char **argv);
signals:
void mainApplicationSignal();
private slots:
void onInterProcessSignal();
private:
InterProcess *mProcess;
};
#endif // MYAPPLICATION_H
MyApplicaiton.cpp
#include "MyApplication.h"
#include "InterProcess.h"
MyApplication::MyApplication(int &argc, char **argv) : QApplication(argc, argv) {
mProcess = new InterProcess(this);
connect(mProcess, SIGNAL(interProcessSignal()),
this, SLOT(onInterProcessSignal()));
mProcess->start();
}
void MyApplication::onInterProcessSignal() {}
This is example implementation of your interProcess class:
InterProcess.h
class InterProcess : public QProcess {
Q_OBJECT
public:
explicit InterProcess(QObject *parent = nullptr);
signals:
void interProcessSignal();
private slots:
void onMainApplicationSignal();
};
InterProcess.cpp
#include "InterProcess.h"
#include "MyApplication.h"
InterProcess::InterProcess(QObject *parent) : QProcess(parent) {
if(parent) {
auto myApp = qobject_cast<MyApplication *>(parent);
if(myApp) {
connect(myApp, SIGNAL(mainApplicationSignal()),
this, SLOT(onMainApplicationSignal()));
}
}
}
void InterProcess::onMainApplicationSignal() {}
Locally, using UDP is very convenient and efficient
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);
}}
This is from my previous question of read the text line by line.
Based from #KubaOber answer, I can successfully read and display the content line by line in a certain time interval.
Then, I was trying to transmit the content of the text file serially into Arduino Uno using the source code available on the internet.
Here's the header code:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtSerialPort/QSerialPort>
#include <QSerialPortInfo>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
QSerialPort *arduino;
static const quint16 arduino_uno_vendor_id = 10755;
static const quint16 arduino_uno_product_id = 67;
QString arduino_port_name;
bool arduino_is_available;
QByteArray serialData;
QString serialBuffer;
void updateSpeedometer(QString);
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
Ui::Widget *ui;
private slots:
private:
};
#endif // WIDGET_H
and here's the main.cpp :
#include <QtWidgets>
#include <QSerialPortInfo>
#include <QtSerialPort/QSerialPort>
#include "widget.h"
#include <QDebug>
bool arduino_is_available = false;
QString arduino_port_name = "";
QSerialPort *arduino = new QSerialPort;
QString serialBuffer = "";
static const quint16 arduino_uno_vendor_id = 10755;
static const quint16 arduino_uno_product_id = 67;
class PeriodicReader : public QObject {
Q_OBJECT
QTimer m_timer{this};
QFile m_file{this};
void readLine() {
if (m_file.atEnd()) {
m_timer.stop();
return;
}
QByteArray lineBaru(m_file.readLine());
emit newLine(lineBaru);
qDebug()<<lineBaru;
QString lineString(lineBaru);
qDebug()<<lineString << " converted to QString";
lineString.remove("\n");
qDebug()<<lineString;
lineString.remove(" ");
qDebug()<<lineString;
QRegExp rx("d(\\d+)");
QList<int> list;
int pos = 0;
while ((pos = rx.indexIn(lineString, pos)) != -1) {
list << rx.cap(1).toInt();
pos += rx.matchedLength();
}
qDebug()<<list;
int listi = list.at(0);
qDebug()<<"list[0] :"<<listi;// <<---THIS IS WHERE I CAN GET THE VALUE AFTER THE "d"
updateSpeedometer(lineString);
}
void updateSpeedometer(QString command)
{
if(arduino->isWritable())
{
command.remove(" ");
arduino->write(command.toStdString().c_str());
qDebug() << command.toStdString().c_str() << " is uploaded to Arduino";
}else{
qDebug()<<"Couldn't write to Serial !" ;
}
}
public:
explicit PeriodicReader(QObject * parent = {}) : QObject(parent) {
connect(&m_timer, &QTimer::timeout, this, &PeriodicReader::readLine);
}
void load(const QString & fileName) {
m_file.close(); // allow re-opening of the file
m_file.setFileName(fileName);
if (m_file.open(QFile::ReadOnly | QFile::Text)) {
readLine();
m_timer.start(1000); // <<<---------------HERE IS WHERE I WANT THE DELAY TO BE
}
}
Q_SIGNAL void newLine(const QByteArray &);
};
QString lineToString(QByteArray line)
{
while (line.endsWith('\n') || line.endsWith('\r'))
line.chop(1);
return QString::fromUtf8(line);
}
int main(int argc, char ** argv) {
qDebug()<<"Number of available ports :" <<QSerialPortInfo::availablePorts().length();
foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
qDebug()<<"Has Vendor ID:" << serialPortInfo.hasVendorIdentifier();
if(serialPortInfo.hasVendorIdentifier()){
qDebug()<<"Vendor ID:"<< serialPortInfo.vendorIdentifier();
}
qDebug()<<"Has Product ID:" << serialPortInfo.hasProductIdentifier();
if(serialPortInfo.hasProductIdentifier()){
qDebug()<<"Product ID:"<< serialPortInfo.productIdentifier();
}
}
foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
if(serialPortInfo.hasVendorIdentifier() && serialPortInfo.hasProductIdentifier()){
if(serialPortInfo.vendorIdentifier() == arduino_uno_vendor_id){
if(serialPortInfo.productIdentifier() == arduino_uno_product_id){
arduino_port_name = serialPortInfo.portName();
arduino_is_available = true;
}
}
}
}
if(arduino_is_available){
//open and configure the serialport
arduino->setPortName(arduino_port_name);
arduino->open(QSerialPort::ReadWrite);
arduino->setBaudRate(QSerialPort::Baud9600);
arduino->setDataBits(QSerialPort::Data8);
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
arduino->setFlowControl(QSerialPort::NoFlowControl);
//QObject::connect(arduino,SIGNAL(readyRead()),this,SLOT(readSerial()));
}else{
//show error message
qDebug()<<" Port Error, Couldn't find the Arduino' !";
// QMessageBox::warning(this, "Port Error, Couldn't find the Arduino !");
}
QApplication app{argc, argv};
QWidget window;
QVBoxLayout layout{&window};
QPushButton load{"Load"};
QPlainTextEdit edit;
layout.addWidget(&load);
layout.addWidget(&edit);
window.show();
PeriodicReader reader;
QObject::connect(&load, &QPushButton::clicked, [&]{
auto name = QFileDialog::getOpenFileName(&window);
if (!name.isEmpty()) {
edit.clear(); // allow re-opening of the file
reader.load(name);
}
});
QObject::connect(&reader, &PeriodicReader::newLine, &edit,
[&](const QByteArray & line){ edit.appendPlainText(lineToString(line)); });
return app.exec();
}
#include "main.moc"
It is from the coding of "reading text line by line" I've asked months a go which I include the arduino serial connection coding as well and hey, it worked!
It reads the text line by line and when each line is displayed in textEdit, it also transmitted to Arduino Uno.
So my request is, instead of the delay between line by line is preset at 2 seconds, can the delay duration be controlled by the content of the text file?
Let say.. the first line content inside the text file is 's200 d300' , and the 's200' is processed by arduino to generate a frequency, meanwhile 'd300' is the delay interval in milliseconds before it reads the next line and generate another frequency signal.
So,how to make Qt recognise the 'd300' and use it as the delay value?
QString str = "asa24fsesfd300kslfv0";
QTextDocument document(str);
QTextCursor d = document.find("d");
qDebug()<<d.position();
QString s = str.mid(d.position()-1,6); // How many digits can be after << d >>
int count = 0;
for (int i = 1; i < s.size(); ++i) {
QString d = s.at(i);
if(d.isEmpty()){
break;
}else{
bool ok;
int k = d.toInt(&ok);
if(ok){
count++;
}else{
break;
}
}
}
QString result = str.mid(d.position(),count);
bool ok;
int result_int = result.toInt(&ok);
if(ok){
qDebug()<< result_int;
}
result 300
I have written code for a server which accepts connections from different clients. Each client is serviced in different threads. Each thread accesses a database to get data and then updates this data to all the clients connected to server.
1) For the first time when UI asks data from server, it responds properly, but after that server does not read the socket i.e. Server's readyread() doesn't get invoked. Funnily enough, this works fine in mac and linux, this issue is seen only on windows
2) I was able to verify that when the DB module emits a signal which is caught by the threads, the hang occurs, Because everything worked fine when I removed the emit.
Here, I am attaching all the needed .h and .cpp codes
Defn.h
#ifndef DEFN_H
#define DEFN_H
struct PresetData{
QString ID;
QString name;
QString value;
QString source;
};
#endif // DEFN_H
main.cpp
#include <QCoreApplication>
#include "myserver.h"
#include "mydb.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyDB db;
MyServer server(&db);
server.startServer();
return a.exec();
}
mydb.h
#ifndef MYDB_H
#define MYDB_H
#include <QObject>
#include <QtSql>
#include "Defn.h"
class MyDB : public QObject
{
Q_OBJECT
public:
explicit MyDB(QObject *parent = 0);
signals:
void dataAvailable(QString ID, QString name, QString value, QString source);
public slots:
void onUpdateData(QString ID, QString name, QString value, QString source);
void onGetData(QString ID, QString name, QString value, QString source);
private:
QSqlDatabase m_db;
};
#endif // MYDB_H
mydb.cpp
#include "mydb.h"
MyDB::MyDB(QObject *parent) :
QObject(parent)
{
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setConnectOptions();
m_db.setDatabaseName("D:/MySimulator/New Folder/TCPServer1/DB.db");
if (m_db.open()){
qDebug() << "DB opened succesfully" ;
}else{
qDebug() << "DB Opening failed" ;
}
QStringList tables = m_db.tables();
if (tables.contains("Presets", Qt::CaseInsensitive)){
qDebug() << "DB Contains Data" ;
return;
}
}
void MyDB::onGetData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onGetData" ;
QString queryString = "SELECT Value from 'Presets' where ID = \'" + ID + "\'";
QSqlQuery q;
bool result = q.exec(queryString);
if (result){
if (q.next()){
value = q.value(q.record().indexOf("Value")).toString();
qDebug() << " Retrieved Value = " << value ;
emit dataAvailable(ID, name, value, source);
}else{
qDebug("Empty Result");
}
}else{
qDebug("NO Result");
}
}
void MyDB::onUpdateData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onUpdateData" ;
QString queryString = "UPDATE 'Presets' SET Value = \'" + value + "'\ WHERE ID = \'" + ID + "\'";
QSqlQuery q;
QSqlDatabase::database().transaction();
bool result = q.exec(queryString);
if (result){
QSqlDatabase::database().commit();
onGetData(ID, name, "", "000");
}else{
qDebug("NO Result");
}
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QDebug>
#include "Defn.h"
#include "mydb.h"
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(int ID, MyDB* db, QObject * parent = 0);
void run();
void parseInput(QString string);
signals:
void error(QTcpSocket::SocketError socketError);
void updateData(QString ID, QString name, QString value, QString source);
void getData(QString ID, QString name, QString value, QString source);
public slots:
void readyRead();
void disconnected();
void onDataAvailable(QString ID, QString name, QString value, QString source);
private:
QTcpSocket* socket;
int socketDescriptor;
MyDB* db;
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include "qtcpserver.h"
#include "qabstractsocket.h"
MyThread::MyThread(int ID, MyDB* db, QObject * parent ):
QThread(parent)
{
this->socketDescriptor = ID ;
this->db = db;
}
void MyThread::run()
{
// thread starts here.
qDebug() << socketDescriptor << "Starting Thread" ;
socket = new QTcpSocket();
if (!socket->setSocketDescriptor(this->socketDescriptor)){
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
connect(this, SIGNAL(getData(QString, QString , QString , QString )), this->db, SLOT(onGetData(QString , QString , QString , QString )));
connect(this, SIGNAL(updateData(QString , QString , QString , QString )), this->db, SLOT(onUpdateData(QString , QString , QString , QString )));
connect(this->db, SIGNAL(dataAvailable(QString , QString , QString , QString )), this, SLOT(onDataAvailable(QString , QString , QString , QString )));
qDebug() << socketDescriptor << "Client Connected" ;
exec();
}
void MyThread::readyRead()
{
QByteArray data = socket->readAll();
qDebug() << socketDescriptor << "Data in: " << data;
parseInput(data);
}
void MyThread::disconnected()
{
qDebug() << socketDescriptor << "Disconnected" ;
socket->deleteLater();
exit(0);
}
void MyThread::parseInput(QString dataFromTCP)
{
qDebug() << socketDescriptor << ":" <<"parseInput " << dataFromTCP;
if (dataFromTCP.isEmpty())
return;
QStringList list1 = dataFromTCP.split("\n", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list1 BEGIN";
for (int i = 0 ; i < list1.count(); i++)
{
qDebug() << i<< ":" << list1.at(i);
}
qDebug() << socketDescriptor << ":" << "list1 END";
if (list1.count() < 1){
return;
}
QString strMessage = "";
for (int i = 0 ; i < list1.count() ; i++)
{
strMessage = list1[i];
QStringList list2 = strMessage.split(" ", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list2 BEGIN";
for (int i = 0 ; i < list2.count(); i++)
{
qDebug() << i<< ":" << list2.at(i);
}
qDebug() << socketDescriptor << ":" << "list2 END";
if (list2.count() < 1){
break;
}
QString ID = list2[1];
QString source = QString::number(socketDescriptor) ;
if (list2[0] == "GET"){
emit getData(ID, "", "", source);
}
else if (list2[0] == "UPD"){
QString value = list2[2];
emit updateData(ID, "", value, source);
}
}
}
void MyThread::onDataAvailable(QString ID, QString name, QString value, QString source)
{
if( (QString::number(socketDescriptor) == source) || ("000" == source ) ) {
qDebug() << socketDescriptor << " : On Data Available " << ID << name << value ;
QString data = "DATA " + ID + " " + value + " " + "\n" ;
QByteArray ba;
ba.append(data);
socket->write(ba);
}
}
myserver.h
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QDebug>
#include <QObject>
#include <QTCPServer>
#include <QTCPSocket>
#include "mythread.h"
#include "mydb.h"
class MyServer: public QTcpServer
{
Q_OBJECT
public:
explicit MyServer(MyDB* pdb, QObject* parent = 0);
void startServer();
signals:
public slots:
protected:
void incomingConnection(qintptr socketDescriptor);
private:
MyDB* pdb ;
};
#endif // MYSERVER_H
myserver.cpp
#include "myserver.h"
MyServer::MyServer(MyDB* pdb, QObject* parent ):
QTcpServer(parent)
{
this->pdb = pdb;
}
void MyServer::startServer()
{
if (!this->listen(QHostAddress::Any, 1234)){
qDebug() << "Could not Start Server " << this->errorString();
}
else{
qDebug() << " Server Running... ";
}
}
void MyServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting... ";
MyThread *thread = new MyThread(socketDescriptor, pdb, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
Here the signal about which I mentioned above is dataAvailable from "mydb.cpp". If I comment out that line then server responds to client messages. But if that signal is emitted then after the initial response, the server seems to hang and no longer reacts to incoming messages from the client.
The same code is working perfectly fine in mac and linux. But it is having this problem in Windows only.
Could someone let me know what is it that I am doing wrong that it is failing only in Windows?
Thanks in advance for helping me out.
EDIT:
The objective of this code is that whenever a thread causes an update call to the database, EVERY thread including the one that called the update gets informed about the change. So it is EXPECTED that other thread that runs at that time also receives a signal.
This is what is expected of the server:
Be able to allow TCP connections from multiple clients simultaneously.
If any client requests info, it gets the required data over the TCP connection.
If any client updates info, all clients including the updating client, gets a notifications over the TCP connection.
Well, for starters, your code is completely not thread-safe. You create a single instance of MyDB in your main() function, then call it from threads without protecting its data member. Also, signals get emitted, updating data without any protection. What if two threads happen to be running at the same time?
Secondly, and this is more important: whenever you emit dataAvailable() you call functions in other thread objects in your own thread. This is the code path when data arrives:
MyThread::parseInput() emits
MyThread::getData(), which is connected to
MyDB::onGetData(), which emits
MyDb::dataAvailable, which is connected to (drumroll....)
MyThread::onDataAvailable, which eventually calls
socket->write()
So if data arrives in thread #1, you're going to send data from MyThread object #2, #3, #4, etc from .... thread #1. Depending on the OS, this is bad news. I don't know enough about Windows threads but I do know this code is terminally broken.
If all you want to do is update a database and relay the data you can dispense with the threads and use a sequential program that handles sockets using the regular Qt signals and slots just fine.