QT write another Thread data in txt file - c++

I want to write data from another thread in txt file.
Text files will be named currentTime() and created periodically every minute.
So, Txt file made very well every minute using QTimer, but In Txt file, content is null.
Of course this result is correct. Because i didn't connect data from another Thread.
How to connect or send data from another thread to QTimer make the txt file every minute?
For example, another thread get data every second and QTimer make txt file every minute.
Ideally, another thread get 60 data in minute and one text file made in minute.
I want to write 60 data to txt file one cycle.
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QTcpSocket>
#include <QThread>
#include <QDebug>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(qintptr ID, QObject *parent = 0);
void run();
signals:
void error(QTcpSocket::SocketError socketerror);
void sendValue(QString strValue);
void close(QString disconnectId);
private slots:
void readyRead();
void disconnected();
void InitThreadObjects();
void sendData();
private:
QTcpSocket *socket;
qintptr socketDescriptor;
QByteArray Data;
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QThread>
#include <QTimer>
#include <QTime>
#include <QFile>
#include <QString>
#include <QTextStream>
MyThread::MyThread(qintptr ID, QObject *parent) :
QThread(parent)
{
this->socketDescriptor = ID;
}
int count = 0;
void MyThread::run()
{
// thread starts here
qDebug() << " Thread started";
socket = new QTcpSocket();
// set the ID
if(!socket->setSocketDescriptor(this->socketDescriptor))
{
// something's wrong, we just emit a signal
emit error(socket->error());
return;
}
// connect socket and signal
// note - Qt::DirectConnection is used because it's multithreaded
// This makes the slot to be invoked immediately, when the signal is emitted.
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(this, &MyThread::started, this, &MyThread::InitThreadObjects);
// We'll have multiple clients, we want to know which is which
qDebug() << socketDescriptor << "Client connected";
QString strValue = QString::number(socketDescriptor);
emit sendValue(strValue);
// make this thread a loop,
// thread will stay alive so that signal/slot to function properly
// not dropped out in the middle when thread dies
exec();
}
void MyThread::readyRead()
{
// get the information
Data = socket->readAll();
// will write on server side window
qDebug() << socketDescriptor << " Data in: " << Data;
socket->write(Data);
}
void MyThread::disconnected()
{
qDebug() << socketDescriptor << " Disconnected";
QString disconnectId = QString::number(socketDescriptor);
emit close(disconnectId);
socket->deleteLater();
exit(0);
}
void MyThread::InitThreadObjects(){
QTimer *timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(sendData()));
timer->start(60000);
}
void MyThread::sendData(){
QTime currentTime = QTime::currentTime();
QString time = currentTime.toString("hhmmss");
QString filename = "/home/pi/"+time+".txt";
qDebug() << filename;
QFile file(filename);
if(!file.open(QFile::WriteOnly | QFile::Text))
{
qDebug() << "Could not open file for writing";
return;
}
QTextStream out(&file);
out << Data;
file.flush();
file.close();
}

You need to create QTimer in another thread
public slots:
void InitThreadObjects();
and in constructor add initialization
connect(this, &Thread::started, this, &Thread::InitThreadObjects);
void Thread::InitThreadObjects(){
m_Timer = new QTimer(this);
connect(m_Timer, &QTimer::timeout, this, &Thread::TimeWriteData);
m_Timer->start(60 * 1000);
}
record the collected data
void Thread::TimeWriteData(){
// Write data to file
}

Related

How to exchange between each other value of variables in two(or more) classes in qt 5.6?

I work on for update STM mcu from qt program. I use qt for GUI but if I have a file that has specific format, I should begin update procedure. I send start char to STM and I must send update data according to the answer. I parsed my code to classes for usefull. So UART class send data to STM and read data incoming from STM mcu. PROTOCOL class should send update data to UART accordingly to incoming data.
My problem is here. I transfered data between classes but just one direction(from PROTOCOL to UART). I sent data from PROTOCOL class to UART class. I need incoming data from STM mcu in PROTOCOL class. UART class read data but it can not send to PROTOCOL class(or PROTOCOL class can not read incoming data). How can I accomplish this?
uart.h
#ifndef UART_H
#define UART_H
#include <QObject>
#include <QtSerialPort>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
class UART : public QObject
{
Q_OBJECT
public:
explicit UART(QObject *parent = 0);
void Start();
bool Updating = true;
QByteArray received_new_data;
signals:
public slots:
void ReadFromSerialPort();
void WriteToSerialPort(const QByteArray &update_data, const qint64 &message_size);
private:
const static QString DEBUG_IDENTIFIER;
QSerialPort serial;
QByteArray data;
qint64 messageSize;
void Initialize(const QString &portName);
void Stop();
static QString PORT_NAME;
};
#endif // UART_H
uart.cpp
#include "uart.h"
#include <QDebug>
QString const UART::DEBUG_IDENTIFIER = "[UART]"; QString
UART::PORT_NAME = "/dev/ttyS1";
UART::UART( QObject *parent) : QObject(parent) {
}
void UART::Initialize(const QString &portName) {
serial.setPortName(portName);
serial.setBaudRate(QSerialPort::Baud115200);
serial.setDataBits(QSerialPort::Data8);
serial.setParity(QSerialPort::NoParity);
serial.setStopBits(QSerialPort::OneStop);
serial.setFlowControl(QSerialPort::NoFlowControl);
serial.open(QIODevice::ReadWrite);
}
void UART::ReadFromSerialPort() {
quint64 available_byte_amount = serial.bytesAvailable();
if(available_byte_amount)
{
received_new_data = serial.readAll();
qDebug() << DEBUG_IDENTIFIER << "received_data: " << received_new_data;
}
}
void UART::WriteToSerialPort(const QByteArray &update_data, const
qint64 &message_size) {
data = update_data; //! max bytes lenght
messageSize = message_size;
//! When incoming hex "10" program continue send "U" char
serial.write(data,messageSize);
serial.flush();
qDebug() <<"send";
qDebug() << "data: " << received_new_data;
}
void UART::Start() {
Initialize(PORT_NAME);
if(serial.isOpen())
{
serial.clear();
serial.clearError();
connect(&serial,SIGNAL(readyRead()), this, SLOT(ReadFromSerialPort()));
}
else
{
qDebug() << DEBUG_IDENTIFIER << "(Start)"
<< "Serial device is not open";
}
if(serial.error() == QSerialPort::NoError)
{
qDebug() << DEBUG_IDENTIFIER << "No Error";
}
else
{
qDebug() << DEBUG_IDENTIFIER << "An error occured:" << serial.errorString();
} }
void UART::Stop() {
disconnect(&serial,SIGNAL(readyRead()), this, SLOT(ReadFromSerialPort())); }
protocol.h
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include <QObject>
#include <QTimer>
#include "uart.h"
class UART;
class PROTOCOL : public QObject
{
Q_OBJECT
public:
explicit PROTOCOL(UART *target_STM, QObject *parent = 0);
static UART *ptr_uart;
void gentnuma();
signals:
public slots:
void readSTM(const QByteArray &readData);
void writeSTM(const QByteArray &stm_data, const qint64 &stm_message_size);
void read_data();
private:
const static QString DEBUG_IDENTIFIER;
QTimer *m_timer;
};
#endif // PROTOCOL_H
protocol.cpp
#include <QByteArray>
#include <QDebug>
#include "protocol.h"
#include "uart.h"
QString const PROTOCOL::DEBUG_IDENTIFIER = "[PROTOCOL]";
UART *PROTOCOL::ptr_uart = NULL;
PROTOCOL::PROTOCOL(UART *target_uart, QObject *parent) : QObject(parent)
{
ptr_uart = target_uart;
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(read_data()));
timer->start(1);
}
void PROTOCOL::gentnuma()
{
UART begin;
QByteArray a = begin.received_new_data;
qDebug() << DEBUG_IDENTIFIER << "TEST:";
qDebug() << DEBUG_IDENTIFIER << "COMING DATA:"<< a; // I expected read data here
}
void PROTOCOL::readSTM(const QByteArray &readData)
{
qDebug() << DEBUG_IDENTIFIER << "read_STM_request:" << readData;
}
void PROTOCOL::writeSTM(const QByteArray &stm_data, const qint64 &stm_message_size)
{
qDebug() << DEBUG_IDENTIFIER << "send STM_data: " << stm_data;
qDebug() << DEBUG_IDENTIFIER << "send STM_data size: " << stm_message_size;
ptr_uart->WriteToSerialPort(stm_data,stm_message_size); //send data to uart
}
void PROTOCOL::read_data()
{
gentnuma();
}
Sorry bad English and long code lines. Thanks.
Solution is just a few steps away: have a signal in your UART class:
signals:
void newData();
emit it when new data are read:
void UART::ReadFromSerialPort()
{
quint64 available_byte_amount = serial.bytesAvailable();
if(available_byte_amount)
{
received_new_data = serial.readAll();
qDebug() << DEBUG_IDENTIFIER << "received_data: " << received_new_data;
emit newData();
}
}
You then connect the UART signal to the PROTOCOL slot you happen to already have, so, in PROTOCOL constructor, instead of
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(read_data()));
timer->start(1);
do:
connect(ptr_uart, SIGNAL(newData()), this, SLOT(read_data()));
This way, instead of polling for new data every second, your PROTOCOL class will be able to read new data from 'UART' whenever there's any.
But, watch out, you're doing it wrong here:
void PROTOCOL::gentnuma()
{
UART begin;
QByteArray a = begin.received_new_data;
qDebug() << DEBUG_IDENTIFIER << "TEST:";
qDebug() << DEBUG_IDENTIFIER << "COMING DATA:"<< a; // I expected read data here
}
since you're instantiating a new UART object out of the blue, and it has not (and never will have) new data to show. You already have a pointer to UART as a private class member, so you must use that one:
void PROTOCOL::gentnuma()
{
QByteArray a = ptr_uart->received_new_data;
qDebug() << DEBUG_IDENTIFIER << "TEST:";
qDebug() << DEBUG_IDENTIFIER << "COMING DATA:"<< a; // I expected read data here
}
(just as a footnote: as far as I can see, that ptr_uart doesn't really need to be static ...)

Using QNetworkAccessManager->Post() causes SEGV on closing the application

****UPDATED: I noticed that I get the segfault only on Windows, on Linux it's fine. On Windows I use QT 5.5 and MinGW32. I still want to know why.
**** Initial Question:
Nothing tricky here, I create a basic Console Application. I have a QNetworkAccessManager sending a Post() request. When I close the console, there is a segfault.
Note that the request is sent and received successfully, my question is only about that segfault.
If no Post() request are sent, no crash on closing the console. There is not much help from the stack.
Stack
0 ntdll!RtlFreeHeap 0x77b5e041
1 ucrtbase!free 0x5e4c5eab
2 LIBEAY32!CRYPTO_free 0x5e5a123e
Main.cpp
#include <QCoreApplication>
#include "CNetworkHandleTest.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
CNetworkHandleTest net;
net.start();
return a.exec();
}
CNetworkHandleTest.cpp
#include "CNetworkHandleTest.h"
CNetworkHandleTest::CNetworkHandleTest()
{
m_Manager = new QNetworkAccessManager(this);
// Connect the network manager so we can handle the reply
connect(m_Manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
m_nTotalBytes = 0;
}
CNetworkHandleTest::~CNetworkHandleTest()
{
disconnect();
m_Manager->deleteLater();
}
void CNetworkHandleTest::onFinished(QNetworkReply* reply)
{
// Look at reply error
// Called when all the data is receivedqDebug() << "Error code:" << reply->error();
qDebug() << "Error string:" << reply->errorString();
reply->close();
reply->deleteLater();
}
void CNetworkHandleTest::start()
{
// Configure the URL string and then set the URL
QString sUrl(BASE_URL);
sUrl.append("/console/5555/upload");
m_Url.setUrl(sUrl);
// Make the request object based on our URL
QNetworkRequest request(m_Url);
// Set request header (not sure how or why this works, but it works)
// \todo investigate
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlenconded");
// Make file object associated with our DB file
QFile file("/tx_database.db");
if(!file.open(QIODevice::ReadOnly))
{
qDebug() << "Failed to open file";
}
// Read the entire file as a binary blob
QByteArray data(file.readAll());
// Set our request to our request object
// Note: there should probably be a flag so that when start is called it does not do
// any processing in case we are already in the middle of processing a request
m_Request = request;
// Send it
m_Reply = m_Manager->post(m_Request, data);
// Need to connect the signals and slots to the new reply object (manager makes a new
// reply object every post; may need to investigate if memory should be freed when
// done processing a response)
connect(m_Reply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(m_Manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
this, SLOT(onAuthenticationRequired(QNetworkReply*, QAuthenticator*)));
}
void CNetworkHandleTest::onReadyRead()
{
// Whenever data becomes available, this slot is called. It is called every time data
// is available, not when all the data has been received. It is our responsibility to
// keep track of how much we have received if we want to show progress or whatever
// but we do not need to keep track if we have received all the data. The slot
// OnFinished will be called when the all the data has been received.
qDebug() << "Bytes available:" << m_Reply->bytesAvailable();
m_nTotalBytes += m_Reply->bytesAvailable();
qDebug() << "Bytes thus far:" << m_nTotalBytes;
QByteArray responseData = m_Reply->readAll();
qDebug() << "Response" << responseData;
m_Reply->size();
}
void CNetworkHandleTest::onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator)
{
}
CNetworkHandleTest.h
#ifndef CNETWORKHANDLETEST_H
#define CNETWORKHANDLETEST_H
// Required packages
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QByteArray>
#include <QUrlQuery>
#include <QHostInfo>
#include <QObject>
#include <QUrl>
// Helper packages
#include <QCoreApplication>
#include <QFile>
#include <QDir>
// Our packages
#include <iostream>
#include <fstream>
#include <cstdlib>
#define BASE_URL "localhost:5000"
#define BOUNDARY "123456787654321"
class CNetworkHandleTest : public QObject
{
Q_OBJECT
public:
CNetworkHandleTest();
~CNetworkHandleTest();
void start();
protected Q_SLOTS:
void onFinished(QNetworkReply* reply);
void onReadyRead();
void onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator);
private:
QNetworkAccessManager* m_Manager;
QNetworkRequest m_Request;
QNetworkReply* m_Reply;
QUrl m_Url;
int m_nTotalBytes;
};
#endif // CNETWORKHANDLETEST_H
When you close the console, your program dies in a most ungraceful manner. You need to write some code to make it graceful instead:
The below is a complete test case:
// https://github.com/KubaO/stackoverflown/tree/master/questions/network-cleanup-40695076
#include <QtNetwork>
#include <windows.h>
extern "C" BOOL WINAPI handler(DWORD)
{
qDebug() << "bye world";
qApp->quit();
return TRUE;
}
int main(int argc, char *argv[])
{
SetConsoleCtrlHandler(&handler, TRUE);
QCoreApplication a(argc, argv);
QNetworkAccessManager mgr;
int totalBytes = 0;
QObject::connect(&mgr, &QNetworkAccessManager::finished, [](QNetworkReply *reply){
qDebug() << "Error string:" << reply->errorString();
});
QNetworkRequest request(QUrl{"http://www.google.com"});
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlenconded");
auto reply = mgr.post(request, QByteArray{"abcdefgh"});
QObject::connect(reply, &QIODevice::readyRead, [&]{
qDebug() << "Bytes available:" << reply->bytesAvailable();
totalBytes += reply->bytesAvailable();
qDebug() << "Bytes thus far:" << totalBytes;
reply->readAll();
});
QObject::connect(reply, &QObject::destroyed, []{
qDebug() << "reply gone";
});
QObject::connect(&mgr, &QObject::destroyed, []{
qDebug() << "manager gone";
});
return a.exec();
}
If you press Ctrl-C or click [x] on the console window, the shutdown is orderly, the output being:
[...]
bye world
reply gone
manager gone

Multithread server doesn't work

I am writing simple client server program in Qt that server is multi thread.
For one server it work correctly and it can send message from client to server but in multi thread form it doesn't work, it connect to thread and also show the message "client connected" but it can't show message sent from client!
I searched a lot bud I couldn't find what is the problem and any solution for it.. Here is my code:
Could you please help me. Thanks in advance.
myserver.cpp
#include "myserver.h"
#include "mythread.h"
myserver::myserver(QObject * parent): QTcpServer(parent)
{
}
void myserver::startserver()
{
int port = 6666;
if (!this - > listen(QHostAddress::Any, port)) {
qDebug() << "Could not start server ";
} else {
qDebug() << "Listening to port ";
}
}
void myserver::incomingConnection(qintptr socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting...";
mythread * thread = new mythread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread - > start();
}
mythread.cpp
#include "mythread.h"
#include "myserver.h"
mythread::mythread(qintptr ID, QObject *parent) : QThread(parent)
{
this->socketDescriptor = ID;
}
void mythread::run()
{
qDebug() << " Thread started";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(this->socketDescriptor)) {
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readSocket()));
qDebug() << socketDescriptor << " Client connected";
}
void mythread::readSocket()
{
QByteArray Data = socket->readAll();
qDebug()<< socketDescriptor <<" Data in: " << Data;
socket->write(Data);
}
If you read the documentation for the QThread::run function you will see
Returning from this method will end the execution of the thread.
You need to call the QThread::exec function to enter the thread event loop.

Multi Thread server

I am writing multi thread server but i have problem in accept connection and start read function. i don't know where i should write them..
here is my code:
"mythread.cpp"
#include "mythread.h"
#include "myserver.h"
mythread::mythread(qintptr ID, QObject *parent) :
QThread(parent)
{
this->socketDescriptor = ID;
}
void mythread::run()
{
qDebug() << " Thread started";
}
void mythread::acceptConnection()
{
c_client = s_server.nextPendingConnection();
connect(c_client,SIGNAL(readyRead()),
this, SLOT(startRead()));
}
void mythread::startRead()
{
char buffer[1024] = {0};
c_client->read(buffer, c_client->bytesAvailable());
qDebug() << buffer;
}
void mythread::readyRead()
{
QByteArray Data = socket->readAll();
qDebug() << socketDescriptor << " Data in: " << Data;
socket->write(Data);
}
void mythread::disconnected()
{
qDebug() << socketDescriptor << " Disconnected";
socket->deleteLater();
exit(0);
}
"myserver.cpp"
#include "myserver.h"
#include "mythread.h"
myserver::myserver(QObject *parent) :
QObject(parent)
{
}
void myserver::startserver()
{
int port = 1234;
if(s_server.listen(QHostAddress::Any, port))
{
qDebug() << "Could not start server";
}
else
{
qDebug() << "Listening to port " << port ;
}
}
void myserver::incomingconnection(int socketDescriptor)
{
connect(&s_server, SIGNAL(newConnection()),
this, SLOT(acceptConnection()));
s_server.listen(QHostAddress::Any, 1234);
qDebug() << socketDescriptor << " Connecting...";
mythread *thread = new mythread(socketDescriptor,this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
i would be grateful if you help me.
You are not using QThread very well. you can use SIGNAL and SLOTS ,and MoveToThread() function. google it.
when you use QThread, the code in Run() function will be run in another thread. acceptConnection will run in main thread.
also search for nextPendingConnection();
void myserver::incomingconnection(int socketDescriptor)
{
connect(&s_server, SIGNAL(newConnection()),this, SLOT(acceptConnection()));
...
is not OK. this connect should be called once (maybe constructor). not for any incomming connection.

newConnection() signal does not get emitted in QTcpSever even when I am clearly connecting to the server

QTcpServer is supposed to emit the newConnection() signal whenever it receives a new client connection. I am able to connect to the server I created, even telnet to it. But in the server implementation, I have connected the newConnection() signal to a slot and it never gets invoked.
Can you please look at my code and tell me what is it that I am doing wrong ?
First the header :
#include <data_model.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <QtNetwork>
#include <QVector>
#include <iostream>
#include <QAbstractSocket>
#include <QDebug>
class QTcpServer;
class QNetworkSession;
class superServer : public QObject
{
Q_OBJECT
public:
explicit superServer(QObject *parent = 0);
data_model::terminal_data fetch_next_record();
void route_data();
private slots:
void sessionOpened();
public slots:
void newTerminalConnection();
void errorconnecting(QAbstractSocket::SocketError socketError);
private:
QTcpServer *tcpServer;
QNetworkSession *networkSession;
QVector<QTcpSocket*> liveConnections;
};
#endif // SUPERSERVER_HPP
Now the implementation:
#include <superServer.hpp>
void superServer::newTerminalConnection()
{
qDebug() << "someone connected ...";
std::cout << "someone connected ..." << std::endl;
QTcpSocket *socket = tcpServer->nextPendingConnection();
liveConnections.push_back(socket);
}
superServer::superServer(QObject *parent) :
QObject(parent)
{
tcpServer = new QTcpServer();
if(!tcpServer->listen(QHostAddress::Any, 9889))
qDebug() << "Server could not start";
else
qDebug() << "Server started!";
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newTerminalConnection()));
connect(tcpServer, SIGNAL(acceptError(QAbstractSocket::SocketError)), this, SLOT(errorconnecting(QAbstractSocket::SocketError)));
}
void superServer::errorconnecting(QAbstractSocket::SocketError socketError)
{
qDebug() << "error connecting to client";
}
Also, I am connecting like this:
void tradeView::doConnect()
{
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()),this, SLOT(connected()));
connect(socket, SIGNAL(disconnected()),this, SLOT(disconnected()));
connect(socket, SIGNAL(bytesWritten(qint64)),this, SLOT(bytesWritten(qint64)));
connect(socket, SIGNAL(readyRead()),this, SLOT(readyRead()));
qDebug() << "connecting...";
// this is not a blocking call
socket->connectToHost("localhost", 9889);
// we need to wait...
if(!socket->waitForConnected(5000))
{
qDebug() << "Error: " << socket->errorString();
}
}
void tradeView::connected()
{
qDebug() << "connected...";
}
void tradeView::disconnected()
{
qDebug() << "disconnected...";
}
void tradeView::bytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
The client connects !!! Even Telnet works !!!
But that signal does not get emitted. Can you please tell me what is wrong ?
Trust me I have looked at more than a dozen related threads here on SO and qt-center etc. None give a solution.
Please help.