I am working on a mqtt project using QT. The publisher works fine which opens and closes a lock controlled by an raspi3, but I also need to subscribe a topic and need to start another action when the subscribed topic responses. I did a first small example as well, before starting to implement it in the bigger project which worked there fine.
But not in this project. Am I missing something?
Here are the relevant snippets from my code:
HMIController.cpp
QmlMqttClient *HMIController::createClient()
{
mqttClient = new QmlMqttClient;
mqttClient->handleSub();
return mqttClient;
}
qmlmqttclient.h
#ifndef QMLMQTTCLIENT_H
#define QMLMQTTCLIENT_H
#include <QtCore/QMap>
#include <QtMqtt/QMqttClient>
#include <QtMqtt/QMqttSubscription>
#include <QtMqtt/QMqttMessage>
class QmlMqttClient;
class QmlMqttClient : public QMqttClient
{
Q_OBJECT
public:
QmlMqttClient(QObject *parent = nullptr);
QMqttSubscription *QmlMqttClient::subscribe(const QMqttTopicFilter &topic, quint8 qos = 0);
Q_INVOKABLE qint32 publish(const QMqttTopicName &topic, const QByteArray &message = QByteArray(),
quint8 qos = 0, bool retain = false);
public slots:
void handleOpen();
void handleClose();
void handleSub();
private:
Q_DISABLE_COPY(QmlMqttClient)
private slots:
void brokerDisconnected();
};
#endif // QMLMQTTCLIENT_H
qmlmqttclient.cpp
#include <QtMqtt/QMqttSubscription>
#include <QtMqtt/QMqttTopicFilter>
#include <QMqttTopicName>
#include <QtMqtt/QMqttClient>
#include <QMqttClient>
#include <QMqttSubscription>
#include <QDateTime>
#include <QDebug>
#include <QtQuick>
#include "qmlmqttclient.h"
#include "hmicontroller.h"
QmlMqttClient::QmlMqttClient( QObject *parent)
: QMqttClient(parent)
{
this->setHostname("192.168.137.82");
this->setPort(1883);
this->connectToHost();
if (ClientState::Disconnected)
{
connect(this, &QmlMqttClient::disconnected, this, &QmlMqttClient::brokerDisconnected);
qDebug() << "Broker disconnected";
} else if (ClientState::Connecting)
{
qDebug() << "Connecting to MqttBroker ..." << this->clientId();
}
connect(this, &QMqttClient::messageReceived, this, [this](const QByteArray &message, const QMqttTopicName &topic) {
qDebug() << QDateTime::currentDateTime().toString()
+ QLatin1String(" Received Topic: ")
+ topic.name()
+ QLatin1String(" Message: ")
+ message
+ QLatin1Char('\n');
});
}
qint32 QmlMqttClient::publish(const QMqttTopicName &topic, const QByteArray &message,
quint8 qos, bool retain)
{
return QMqttClient::publish(topic, message, qos, retain);
}
void QmlMqttClient::handleOpen()
{
QString msg = "AUF";
const QMqttTopicName *topic = new QMqttTopicName("lock");
publish(*topic, msg.toUtf8() ,0);
}
void QmlMqttClient::handleClose()
{
QString msg = "ZU";
const QMqttTopicName *topic = new QMqttTopicName("lock");
publish(*topic, msg.toUtf8() ,0);
}
QMqttSubscription *QmlMqttClient::subscribe(const QMqttTopicFilter &topic, quint8 qos)
{
qDebug() << "Subscribed" << this->clientId();
return QMqttClient::subscribe(topic, qos);
}
//Called from hmicontroller
void QmlMqttClient::handleSub()
{
const QMqttTopicFilter *topic = new QMqttTopicFilter("button");
subscribe(*topic, quint8(0));
qDebug() << "Subscribed";
}
void QmlMqttClient::brokerDisconnected()
{
qDebug() << "Session closed";
}
Thanks a lot for your help and by the way, I am also new to c++ and qt. So excuse any not so nice written code.
So, I found my problem. The subscriber didn't subscribe to my specified topic, because of loading this method to fast. With a delay it works fine now.
Related
How are you solving signals/slots mechanism between two classes, if you do not make an object from class(only inherit from class) etc? QTimer, QSerialPort, which is the source of SIGNAL, and in the second class you make connection?
Is such an approach even possible?
In my case. I have two classes usb2can_driver and canview. The usb2can_driver inherit from QSerialPort, which inherit QIODevice contained SIGNAL(readyRead()). This is used in the canview for connection with handler subroutine read_u2c()
I know, in the code is a lot of garbage from testing.
In the canview.cpp void CANview::on_connectPort_released() is made connection, and in the usb2can_driver.cpp int USB2CAN_driver::connectToPort(QString portName) is part of inherit from QSerialPort.
I will be pleasure for every answer. If you think, that question is posed incorrectly, please give me feedback.
usb2can_driver.h
#ifndef USB2CAN_DRIVER_H
#define USB2CAN_DRIVER_H
#include "QSerialPort"
#include "QTimer"
#include "QObject"
#include "QSignalSpy"
class USB2CAN_driver : public QSerialPort
{
Q_OBJECT;
public:
USB2CAN_driver();
//virtual ~USB2CAN_driver();
//QSerialPort *port_USB2CAN = new QSerialPort();
int temporary_init_Counter = 0;
int init();
void USB_LoopBack();
void Boot_Mode();
void Config_Mode();
void Normal_Mode();
void LoopBack_Mode();
QByteArray Get_Mode();
void WriteReg(QByteArray regAdress, QByteArray value[]);
QByteArray WriteCMD(QByteArray CMD_name, QByteArray value);
QByteArray ReadReg(QByteArray regAdress);
QString portName;
int connectToPort(QString portName);
int disconnectedFromPort();
QTimer *tim;
int tim_counter = 0;
public: signals:
void readyRead();
private slots:
QByteArray read_USB2CAN();
void initSend();
//void timEvent();
};
#endif // USB2CAN_DRIVER_H
usb2can_driver.cpp
#include "USB2CAN_define.h"
#include "QSerialPort"
#include "QSerialPort"
#include "QObject"
#include "QDebug"
#include <QSignalSpy>
USB2CAN_driver::USB2CAN_driver()
{
//USB2CAN_driver:: = new QSerialPort();
//USB2CAN_driver::Baud9600;
//USB2CAN_driver::AllDirections;
//qDebug() << "Open port" << USB2CAN_driver::open(QIODevice::ReadWrite);
}
/*
USB2CAN_driver::~USB2CAN_driver(){
QObject::disconnect(USB2CAN_driver::,SIGNAL(readyRead()),USB2CAN_driver::,SLOT(QByteArray read_USB2CAN()));
}
*/
int USB2CAN_driver::connectToPort(QString portName){
//port_USB2CAN.setPortName(portName);
USB2CAN_driver::setPortName(portName);
USB2CAN_driver::setBaudRate(QSerialPort::Baud9600,QSerialPort::AllDirections);
USB2CAN_driver::setPortName(portName);
//Reimplemented separately as signal of driver. !!!
//qDebug() << "connect S&S in the driver, status: " << QObject::connect(this,SIGNAL(readyRead),this,SLOT(read_USB2CAN));
//qDebug() << "connect S&S in the driver, status: " << connect(this,SIGNAL(readyRead()),this,SLOT(read_USB2CAN()));
//QSignalSpy spy(this, SIGNAL(readyRead()));
//qDebug() << "from driver" << spy.wait(5000) << "----" << spy.signal();
tim = new QTimer;
return USB2CAN_driver::open(QIODevice::ReadWrite);
}
/*
void USB2CAN_driver::timEvent(){
qDebug() << "Tim" << tim_counter++;
if(tim_counter >= 5){
tim_counter = 0;
tim->stop();
}
}
*/
int USB2CAN_driver::disconnectedFromPort(){
//QObject::disconnect(this,SIGNAL(readyRead()),this,SLOT(read_USB2CAN()));
USB2CAN_driver::close();
if(USB2CAN_driver::isOpen()){
return 1;
}
else{
qDebug() << "------------------Port is diconected-----------------";
return 0;
}
}
void USB2CAN_driver::USB_LoopBack(){
}
void USB2CAN_driver::Boot_Mode(){
}
void USB2CAN_driver::Config_Mode(){
}
void USB2CAN_driver::Normal_Mode(){
}
void USB2CAN_driver::LoopBack_Mode(){
}
QByteArray USB2CAN_driver::Get_Mode(){
while(!USB2CAN_driver::waitForBytesWritten(300)){
USB2CAN_driver::write(getMode);
}
return USB2CAN_driver::readAll(); //In progress...
}
void USB2CAN_driver::WriteReg(QByteArray regAdress, QByteArray value[]){
int length = regAdress.length() + value->length();
QByteArray len;
len.setNum(length);
QByteArray sendVal[] = { writeReg, len, regAdress, *value };
QByteArray sendData;
sendData.fromRawData(*sendVal,sizeof (sendVal));
while(!USB2CAN_driver::waitForBytesWritten(300)){
USB2CAN_driver::write(sendData);
}
}
QByteArray USB2CAN_driver::WriteCMD(QByteArray CMD_name, QByteArray value){
}
QByteArray USB2CAN_driver::ReadReg(QByteArray regAdress){
}
int USB2CAN_driver::init(){
}
QByteArray USB2CAN_driver::read_USB2CAN(){
qDebug() <<"From driver RX" << USB2CAN_driver::readAll();
return USB2CAN_driver::readAll();
}
void USB2CAN_driver::initSend(){
}
canview.h
#define CANVIEW_H
#include <QDialog>
#include <usb2can_driver.h>
namespace Ui {
class CANview;
}
class CANview : public QDialog
{
Q_OBJECT
public:
explicit CANview(QWidget *parent = nullptr);
~CANview();
USB2CAN_driver *u2c;
QTimer *time;
private: signals:
friend void USB2CAN_driver::readyRead();
private slots:
void on_connectPort_released();
void on_pushButton_released();
QByteArray read_u2c();
void timerSubrutine();
private:
Ui::CANview *ui;
};
#endif // CANVIEW_H
canview.cpp
#include "ui_canview.h"
#include "QSignalSpy"
CANview::CANview(QWidget *parent) : QDialog(parent),ui(new Ui::CANview)
{
ui->setupUi(this);
u2c = new USB2CAN_driver;
}
CANview::~CANview()
{
delete ui;
}
//connect fcn
void CANview::on_connectPort_released()
{
if(u2c->isOpen()){
u2c->disconnectedFromPort();
}
else{
u2c->connectToPort(ui->inputNamePort->text());
qDebug() << "Connect rx task, status: " << connect(???,SIGNAL(readyRead()),this,SLOT(read_u2c()));
connect(u2c->tim,SIGNAL(timeout()),this,SLOT(timerSubrutine()));
u2c->tim->start(800);
}
//Controll of opened/close port
if(u2c->isOpen()){
ui->connectPort->setCheckState(Qt::CheckState::Checked);
}
else{
ui->connectPort->setCheckState(Qt::CheckState::Unchecked);
}
}
//Send function
void CANview::on_pushButton_released()
{
u2c->write(ui->TX_textBrowser->toPlainText().toLatin1(),static_cast<int>(ui->TX_textBrowser->toPlainText().length()));
qDebug() << "Send: " << static_cast<int> (ui->TX_textBrowser->toPlainText().length());
QSignalSpy spy(u2c,SIGNAL(readyRead()));
qDebug() << spy.signal() << spy.signalsBlocked() << spy.isValid();
}
QByteArray CANview::read_u2c(){
qDebug() << "RX:" << u2c->readAll();
ui->RX_textBrowser_2->setPlainText(u2c->readAll());
return u2c->readAll();
}
void CANview::timerSubrutine(){
qDebug() << "TimerEvent" << u2c->tim_counter++;
if(u2c->tim_counter >= 5){
u2c->tim->stop();
}
}```
It is impossible to connect classes as mentioned by #Scheff's Cat.
The solution is do not use inheritance from QSerialPort in the usb2can_driver. If I want connect signal of QSerialPort with slot (which is part of second class), I had to create a object from QSerialPort in the constructor of USB2CAN_driver.
This object to allow use signal/slot mechanism.
So in short: USB2CAN_driver:: was replaced by object port_USB2CAN
For the connection in the second class (canview), i used this syntax:
connect(u2c->port_USB2CAN,SIGNAL(readyRead()),this,SLOT(read_u2c()));
Thank to Scheff's Cat, your comment was helpfully. This solution is working, but if somebody see the non-standard syntax please warning me.
I've successfully redirected qDebug() output to a QTextEdit widget. For several reasons, I'd like every qDebug() message to be included in an emitted signal. One reason is that the object which shall receive the output isn't available. Another reason is that I want to redirect the output to different objects depending on which activity is active at the moment (using connect/disconnect of the signal to different slots).
I've made a working example code that redirects qDebug to a QTextEdit widget. Can someone please help me to get this code to emit a signal which includes the qDebug message?
I'm not sure if its possible to have Q_DebugStream emit a signal (I've tried and failed to make a Qt Class out of it).
It must be possible to pass a pointer to a function/slot instead of a pointer to a QTextEdit when calling Q_DebugStream, but I'm not sure how this is done.
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void logSignal(QString);
public slots:
void logSlot(QString);
private:
QTextEdit *logView;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "q_debugstream.h"
#include <QGridLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QWidget *mainWidget = new QWidget(this);
setCentralWidget(mainWidget);
logView = new QTextEdit;
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(logView,0,0,1,1);
mainWidget->setLayout(mainLayout);
connect(this, SIGNAL(logSignal(QString)),
this, SLOT(logSlot(QString)));
emit logSignal("Message from a signal\n");
new Q_DebugStream(std::cout, logView); //Redirect Console output to QTextEdit
Q_DebugStream::registerQDebugMessageHandler(); //Redirect qDebug() output to QTextEdit
qDebug() << "DEBUG MODE ACTIVE";
}
MainWindow::~MainWindow(){}
void MainWindow::logSlot(QString log) {
logView->append(log);
}
q_debugstream.h
//As per forum:
//http://www.qtforum.org/article/39768/redirecting-std-cout-std-cerf-qdebug-to-qtextedit.html
//A couple of lines added to ensure newlines go between each call.
//Thanks, James!
#ifndef Q_DEBUGSTREAM_H
#define Q_DEBUGSTREAM_H
#include <iostream>
#include <streambuf>
#include <string>
#include <QTextEdit>
class Q_DebugStream : public std::basic_streambuf<char>
{
public:
Q_DebugStream(std::ostream &stream, QTextEdit* text_edit) : m_stream(stream)
{
log_window = text_edit;
m_old_buf = stream.rdbuf();
stream.rdbuf(this);
}
~Q_DebugStream()
{
m_stream.rdbuf(m_old_buf);
}
static void registerQDebugMessageHandler(){
qInstallMessageHandler(myQDebugMessageHandler);
}
private:
static void myQDebugMessageHandler(QtMsgType, const QMessageLogContext &, const QString &msg)
{
std::cout << msg.toStdString().c_str();
}
protected:
//This is called when a std::endl has been inserted into the stream
virtual int_type overflow(int_type v)
{
if (v == '\n')
{
log_window->append("");
}
return v;
}
virtual std::streamsize xsputn(const char *p, std::streamsize n)
{
QString str(p);
if(str.contains("\n")){
QStringList strSplitted = str.split("\n");
log_window->moveCursor (QTextCursor::End);
log_window->insertPlainText (strSplitted.at(0)); //Index 0 is still on the same old line
for(int i = 1; i < strSplitted.size(); i++){
log_window->append(strSplitted.at(i));
log_window->append("\n");
}
}else{
log_window->moveCursor (QTextCursor::End);
log_window->insertPlainText (str);
log_window->insertPlainText ("\n");
}
return n;
}
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
QTextEdit* log_window;
};
#endif // Q_DEBUGSTREAM_H
When application is started, I get both messages in my QTextEdit:
"Message from a signal"
"DEBUG MODE ACTIVE"
(This answer extracted from an edit to the question - now rolled back).
Here's how I solved this:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
void logSignal(QString);
public slots:
void logSlot(QString);
private:
void dbgMsg(QString);
QTextEdit *logView;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "q_debugstream.h"
#include <QGridLayout>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QWidget *mainWidget = new QWidget(this);
setCentralWidget(mainWidget);
logView = new QTextEdit;
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(logView,0,0,1,1);
mainWidget->setLayout(mainLayout);
connect(this, SIGNAL(logSignal(QString)),
this, SLOT(logSlot(QString)));
emit logSignal("Now call Q_DebugStream");
//Redirect qDebug() output to dbgMsg(QString)
new Q_DebugStream(std::cout, this, &MainWindow::dbgMsg);
Q_DebugStream::registerQDebugMessageHandler();
qDebug() << "Debug message";
qWarning() << "Warning!";
qCritical() << "Critical issue!";
qInfo() << "Information";
qDebug() << "This\nis\na\nlong\none.";
}
MainWindow::~MainWindow(){}
void MainWindow::logSlot(QString log) {
logView->append(log);
}
void MainWindow::dbgMsg(QString log) {
emit logSignal(log);
}
q_debugstream.h
#ifndef Q_DEBUGSTREAM_H
#define Q_DEBUGSTREAM_H
#include <iostream>
#include <streambuf>
#include <string>
#include <QString>
#include "mainwindow.h"
class Q_DebugStream : public std::basic_streambuf<char> {
public:
Q_DebugStream(std::ostream &stream, MainWindow* obj, void (MainWindow::*dbgMsgPtr)(QString log)): m_stream(stream) {
m_old_buf = stream.rdbuf();
stream.rdbuf(this);
msgObj = obj;
msgHandler = dbgMsgPtr;
}
~Q_DebugStream() {
m_stream.rdbuf(m_old_buf);
}
static void registerQDebugMessageHandler() {
qInstallMessageHandler(myQDebugMessageHandler);
}
private:
static void myQDebugMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
QString message = msg;
switch (type) {
case QtDebugMsg:
message.prepend("qDbg(): ");
break;
case QtWarningMsg:
message.prepend("qWarn(): ");
break;
case QtCriticalMsg:
message.prepend("qCrit(): ");
break;
case QtInfoMsg:
message.prepend("qInfo(): ");
break;
case QtFatalMsg:
message.prepend("qFatal(): ");
abort();
break;
}
message.append(" (" + QString::fromUtf8(context.file) + ")");
message.append(" line: " + QString::number(context.line));
std::cout << message.toStdString().c_str();
}
protected:
//This is called when a std::endl has been inserted into the stream
virtual int_type overflow(int_type v) {
if (v == '\n') {
(msgObj->*msgHandler)("\n");
}
return v;
}
virtual std::streamsize xsputn(const char *p, std::streamsize n) {
QString str(p);
if(str.contains("\n")) {
QStringList strSplitted = str.split("\n");
(msgObj->*msgHandler)(strSplitted.at(0)); //Index 0 is still on the same old line
for(int i = 1; i < strSplitted.size(); i++) {
(msgObj->*msgHandler)("\\ " + strSplitted.at(i));
}
} else {
(msgObj->*msgHandler)(str);
}
return n;
}
private:
std::ostream &m_stream;
std::streambuf *m_old_buf;
MainWindow* msgObj;
void (MainWindow::*msgHandler)(QString);
};
#endif // Q_DEBUGSTREAM_H
When application is started, I get these messages in my QTextEdit:
Now call Q_DebugStream
qDbg(): Debug message (..\qDebugFetch\mainwindow.cpp) line: 25
qWarn(): Warning! (..\qDebugFetch\mainwindow.cpp) line: 26
qCrit(): Critical issue! (..\qDebugFetch\mainwindow.cpp) line: 27
qInfo(): Information (..\qDebugFetch\mainwindow.cpp) line: 28
qDbg(): This
\ is
\ a
\ long
\ one. (..\qDebugFetch\mainwindow.cpp) line: 29
I try to get serial communication working, but struggle at waiting for the response. The logic should be to send data, wait for a response, get the response and then repeat.
To speed up my code and preventing it from blocking other independent parts of the code I run the serial communication in a separate thread.
The problem is in the send function, where I always get a "Timeout" message instead of an "Success" message.
serial.h
#ifndef SERIAL_H
#define SERIAL_H
#include <QThread>
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QStringList>
class Serial : public QThread
{
Q_OBJECT
public:
Serial();
bool send(QString text);
bool connectSerial();
void disconnectSerial();
signals:
void dataReceived(QByteArray receivedData);
protected:
void run();
private slots:
void onGetData();
private:
void readAngles();
QSerialPort qsp;
QSerialPortInfo qspi;
QByteArray receivedData;
};
#endif // SERIAL_H
serial.cpp
#include "serial.h"
Serial::Serial()
{
connect(&qsp, SIGNAL(readyRead()), this, SLOT(onGetData()));
}
bool Serial::send(QString text)
{
if (qsp.isWritable()) {
QByteArray buffer = text.toLatin1();
if (buffer.size() != qsp.write(buffer))
qDebug() << "Send does not work";
qsp.flush();
if(!qsp.waitForReadyRead(2500)) {
qDebug() << "Timeout";
} else {
qDebug() << "Success";
}
return true;
} else {
return false;
}
}
void Serial::onGetData()
{
qDebug() << "onGetData called";
qDebug() << qsp.readAll();
}
bool Serial::connectSerial(int port)
{
qDebug() << qspi.availablePorts().count();
for(int i=0; i<qspi.availablePorts().count(); i++) {
qDebug() << qspi.availablePorts().at(i).description();
}
qsp.setPort(qspi.availablePorts().at(port));
qsp.setBaudRate(QSerialPort::Baud9600);
qsp.setDataBits(QSerialPort::Data7);
qsp.setFlowControl(QSerialPort::NoFlowControl);
qsp.setParity(QSerialPort::NoParity);
qsp.setStopBits(QSerialPort::OneStop);
return qsp.open(QIODevice::ReadWrite);
}
/**
* #brief Disconnecting from serial port.
*/
void Serial::disconnectSerial()
{
if (qsp.isOpen()) {
qsp.close();
}
}
void Serial::readAngles()
{
send("012345");
}
I created a small server/client application, and for testing I put the server/client function into a separate application.
The main client functions are
Client::Client(QString purpose) : networkSession(0)
{
Client::purpose = purpose;
tcpSocket = new QTcpSocket;
Client::blockSize = 0;
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readData()));
connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
this, SLOT(displayError(QAbstractSocket::SocketError)));
QNetworkConfigurationManager manager;
if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired)
{
// Get saved network configuration
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
settings.endGroup();
// If the saved network configuration is not currently discovered use the system default
QNetworkConfiguration config = manager.configurationFromIdentifier(id);
if ((config.state() & QNetworkConfiguration::Discovered) !=
QNetworkConfiguration::Discovered) {
config = manager.defaultConfiguration();
}
networkSession = new QNetworkSession(config, this);
connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened()));
}
qDebug() << "Client set up, waiting";
}
void Client::connectToServer(QString ipAddr, quint32 port)
{
qDebug() << "Connecting to Host on port " << port << ' ' << (quint16)port;
tcpSocket->connectToHost(ipAddr, port);
emit this->connectionResult((tcpSocket->state() == QAbstractSocket::UnconnectedState)?false:true);
if (tcpSocket->waitForConnected(1000))
qDebug("Connected!");
qDebug() << "Am I connected" << tcpSocket->state();
std::cout << "Am I not connected" << tcpSocket->state();
}
and the server-functions:
Server::Server(QString ipAddr, quint32 port, QString purpose)
: tcpServer(0), networkSession(0)
{
Server::clientConnection = NULL;
Server::purpose = purpose;
Server::port = port;
QNetworkConfigurationManager manager;
if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) {
// Get saved network configuration
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
const QString id = settings.value(QLatin1String("DefaultNetworkConfiguration")).toString();
settings.endGroup();
// If the saved network configuration is not currently discovered use the system default
QNetworkConfiguration config = manager.configurationFromIdentifier(id);
if ((config.state() & QNetworkConfiguration::Discovered) !=
QNetworkConfiguration::Discovered) {
config = manager.defaultConfiguration();
}
networkSession = new QNetworkSession(config, this);
connect(networkSession, SIGNAL(opened()), this, SLOT(sessionOpened()));
//statusLabel->setText(tr("Opening network session."));
networkSession->open();
} else {
sessionOpened();
}
//connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune()));
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(openNewConnection()));
//connect(tcpServer, &QTcpServer::newConnection, this, &Server::openNewConnection);
}
void Server::sessionOpened()
{
// Save the used configuration
if (networkSession) {
QNetworkConfiguration config = networkSession->configuration();
QString id;
if (config.type() == QNetworkConfiguration::UserChoice)
id = networkSession->sessionProperty(QLatin1String("UserChoiceConfiguration")).toString();
else
id = config.identifier();
QSettings settings(QSettings::UserScope, QLatin1String("QtProject"));
settings.beginGroup(QLatin1String("QtNetwork"));
settings.setValue(QLatin1String("DefaultNetworkConfiguration"), id);
settings.endGroup();
}
tcpServer = new QTcpServer(this);
if (!tcpServer->listen(QHostAddress::Any, Server::port)) {
return;
}
qDebug() << "Server listening on: " << tcpServer->serverPort();
//! [0]
QString ipAddress;
QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
// use the first non-localhost IPv4 address
for (int i = 0; i < ipAddressesList.size(); ++i) {
if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
ipAddressesList.at(i).toIPv4Address()) {
ipAddress = ipAddressesList.at(i).toString();
break;
}
}
// if we did not find one, use IPv4 localhost
if (ipAddress.isEmpty())
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
//! [1]
}
void Server::openNewConnection(void)
{
qDebug() << "New conn incoming!";
Server::clientConnection = tcpServer->nextPendingConnection();
QVariant ipAddr_QVar(clientConnection->peerAddress().toString());
qDebug() << "Got new connection!";
emit gotNewConnection(ipAddr_QVar);
}
The main problem here is that even if I get a "Connected" from
if (tcpSocket->waitForConnected(1000))
qDebug("Connected!");
qDebug() << "Am I connected" << tcpSocket->state();
in the client function, but the server function openNewConnection() never gets called. Why? How can I find the bug?
If a minimal working example is necessary, I can provide the whole code, but here I just wanted to provide the most important functions.
Edit:
client.h:
#ifndef CLIENT_H
#define CLIENT_H
//#include <QDialog>
#include <iostream>
#include <QTcpSocket>
class QComboBox;
class QDialogButtonBox;
class QLabel;
class QLineEdit;
class QPushButton;
class QTcpSocket;
class QNetworkSession;
class Client : public QObject
{
Q_OBJECT
private:
QTcpSocket *tcpSocket;
QString currentFortune;
quint16 blockSize;
QPair<QString, QPair<QString, QVariant> > data;
QNetworkSession *networkSession;
QString purpose;
signals:
void gotData(QPair<QString, QPair<QString, QVariant> >);
void noConnection(void);
void connectionResult(bool);
void isDisconnect(bool);
public slots:
void displayError(QAbstractSocket::SocketError socketError);
void sessionOpened();
void getInfo();
void readData();
void connectToServer(QString ipAddr, quint32 port);
void disconnectFromServer();
private:
public:
Client(QString purpose);
};
#endif // CLIENT_H
server.h:
#ifndef SERVER_H
#define SERVER_H
#include <QTcpServer>
#include <iostream>
//#include <QtTest/QTest>
#include <QSignalSpy>
#include <QTcpSocket>
#include <QDebug>
//#include <QMessageBox>
#include <QNetworkInterface>
#include <typeinfo>
#include <QStringList>
//#include <QSignalSpy>
QT_BEGIN_NAMESPACE
class QTcpServer;
class QNetworkSession;
QT_END_NAMESPACE
class Server : public QObject
{
Q_OBJECT
public slots:
void sessionOpened();
void sendFortune(void);
void sendData(QPair<QString, QPair<QString, QVariant> > data);
void sendFile(QVariant fileName);
void disconnectServer(void);
void openNewConnection(void);
signals:
void gotNewConnection(QVariant);
private:
QString purpose;
QTcpServer *tcpServer;
QString ipAddr;
quint32 port;
QTcpSocket *clientConnection;
quint32 BlockSize;
bool firstTime;
QSignalSpy * m_pSignalSpy;
QStringList fortunes;
QNetworkSession *networkSession;
//QNetworkConfiguration config;
public:
Server(QString ipAddr, quint32 port, QString purpose = "");
};
#endif // SERVER_H
The problem lies with your QNetworkSession, you have declared it in scope. Meaning once you leave that function the QNetworkSession gets destroyed. A destroyed object cannot emit a signal. Maybe make it a member variable or construct it in your header.
I want to write a console chat program in qt framework.I have a problem with sending messages.
Client sends messages to server but server doesn't take the messages until client program is closed.When client is closed, server displays all messages.I don't want that.I want server to get my messages when i send to it.
I wrote the codes below.You will see what i want to do if you look at main function of client.
/*
Created BY :
Creation DATE : 26/10/2012
Client interface
*/
#ifndef CLIENT_H
#define CLIENT_H
#include <QtNetwork>
#include <QObject>
#include <QtNetwork/QTcpSocket>
namespace NetworkArdic
{
class Client : public QObject
{
Q_OBJECT
public:
Client(QObject * obj = 0,QString add="localhost", quint16 port = 4000);
void SendData(QString data);
virtual ~Client();
private slots:
void ReadData();
void connected();
private:
QTcpSocket *socket;
};
}
#endif
/*
Created BY :
Creation DATE : 26/10/2012
Client source file
*/
#include "Client.h"
#include <QHostAddress>
#include <iostream>
using namespace std;
namespace NetworkArdic{
Client::Client(QObject * obj, QString add, quint16 port) : QObject(obj)
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(ReadData()));
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
socket->connectToHost(QHostAddress(add), port);
}
Client::~Client(){
socket->close();
delete socket;
}
void Client::SendData(QString data)
{
if(!data.isEmpty())
{
socket->write(QString(data + "\n").toUtf8());
}
}
void Client::ReadData()
{
while(socket->canReadLine())
{
QString line = QString::fromUtf8(socket->readLine()).trimmed();
qDebug() << line;
}
}
void Client::connected()
{
socket->write(QString("Client : Server connection has been made (: \n").toUtf8());
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Client cli(0,"127.0.0.1",4000);
string line;
while(line!="exit"){
cout << "Message : ";
cin >> line;
cli.SendData(QString(line.c_str()));
}
return a.exec();
}
/*
Created BY :
Creation DATE : 26/10/2012
Server interface
*/
#ifndef SERVER_H
#define SERVER_H
#include <QtNetwork>
#include <QObject>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
namespace NetworkArdic
{
class Server: public QTcpServer
{
Q_OBJECT
public:
Server(QObject * parent = 0 , quint16 port = 4000);
virtual ~Server();
private slots:
void acceptConnection();
void startRead();
void disconnected();
private:
QTcpSocket * client;
};
}
#endif // SERVER_H
/*
Created BY :
Creation DATE : 26/10/2012
Server source file
*/
#include "Server.h"
#include <iostream>
using namespace std;
namespace NetworkArdic{
Server::Server(QObject* parent , quint16 port): QTcpServer(parent)
{
connect(this, SIGNAL(newConnection()),this, SLOT(acceptConnection()));
listen(QHostAddress::Any, port );
}
Server::~Server()
{
delete client;
close();
}
void Server::acceptConnection()
{
client = nextPendingConnection();
connect(client, SIGNAL(readyRead()), this, SLOT(startRead()));
connect(client, SIGNAL(disconnected()), this, SLOT(disconnected()));
qDebug() << "New client from:" << client->peerAddress().toString();
}
void Server::startRead()
{
while(client->canReadLine())
{
QString line = QString::fromUtf8(client->readLine()).trimmed();
qDebug() << "Client :" << line;
client->write(QString("Server : I've taken your message (:\n").toUtf8());
}
}
void Server::disconnected()
{
qDebug() << "Client disconnected:" << client->peerAddress().toString();
client->write(QString("Server : I wish you didn't leave ):\n").toUtf8());
}
}
Try using socket->flush() after you write the data.
http://doc.qt.digia.com/qt/qabstractsocket.html#flush
You used the code below to read socket data.
void Server::startRead()
{
while(client->canReadLine())
{
QString line = QString::fromUtf8(client->readLine()).trimmed();
qDebug() << "Client :" << line;
client->write(QString("Server : I've taken your message (:\n").toUtf8());
}
}
I suggest to adopt from the following code which I have tested works
while (tcp_server->hasPendingConnections()) {
client = tcp_server->nextPendingConnection();
client->waitForReadyRead(100);
QByteArray byteArray = client->readAll();
QString s_data = byteArray.data();
// Process s_data
client->close();
client->abort();
}