I'm trying to receive some packets using a udpReceiver class that I have written using qUdpSocket in a separate QThread :
class udpThread : public QThread
{
private:
QObject * parent;
public:
udpThread(QObject * parent = 0)
{
this->parent = parent;
}
void run()
{
UdpReceiver * test = new UdpReceiver(parent);
}
};
class UdpReceiver : public QObject
{
Q_OBJECT
private:
QUdpSocket * S;
int port;
public:
UdpReceiver(QObject* parent = 0) : QObject(parent)
{
port = 9003;
initialize();
}
UdpReceiver(int p,QObject* parent = 0) : QObject(parent)
{
port = p;
initialize();
}
void initialize()
{
S = new QUdpSocket();
S->bind(port);
S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
qDebug() << "Waiting for UDP data from port " << port << " ... \n";
}
public slots:
void readPendingDiagrams()
{
while(S->waitForReadyRead())
{
QByteArray datagram;
datagram.resize(S->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
qDebug() << datagram.size() << " bytes received .... \n";
qDebug() << " bytes received .... \n";
}
}
};
And here is the main() method :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// UdpReceiver * net = new UdpReceiver();
MainWindow w;
udpThread * ut = new udpThread();
ut->start();
w.show();
return a.exec();
}
Now when I use the udpReceiver class to get the packets without the QThread it works just fine, but when I use the udpThread class it doesn't get the packets or at least the raedyread() signal does not activate some how.
When I try to get the packets without the QThread my GUI crashes somehow and the whole program hangs, that's why I want to use QThread.
I appreciate if you could help me solve this :)
Regards,
You've fallen into the same trap as many do when working with threads in Qt: http://blog.qt.io/blog/2010/06/17/youre-doing-it-wrong/.
It is almost always a bad idea to subclass QThread (see http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html for counterexamples).
Change your code as follows to do it the "intended" way (create a new QThread and call moveToThread on your QObject to move it to the new thread). You'll see from the output that the thread the UdpReceiver is created on is not the same as the one it receives data on, which is what you want:
#include <QApplication>
#include <QDebug>
#include <QThread>
#include <QUdpSocket>
class UdpReceiver : public QObject
{
Q_OBJECT
private:
QUdpSocket * S;
int port;
public:
UdpReceiver(QObject* parent = 0) : QObject(parent)
{
qDebug() << "Construction thread:" << QThread::currentThreadId();
port = 9003;
initialize();
}
UdpReceiver(int p,QObject* parent = 0) : QObject(parent)
{
port = p;
initialize();
}
void initialize()
{
S = new QUdpSocket();
S->bind(port);
S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
qDebug() << "Waiting for UDP data from port " << port << " ... \n";
}
public slots:
void readPendingDiagrams()
{
qDebug() << "Reading thread:" << QThread::currentThreadId();
while(S->waitForReadyRead())
{
QByteArray datagram;
datagram.resize(S->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
qDebug() << datagram.size() << " bytes received .... \n";
qDebug() << " bytes received .... \n";
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread *t = new QThread();
t->start();
UdpReceiver * net = new UdpReceiver();
net->moveToThread(t);
return a.exec();
}
#include "main.moc"
I don't have your UI code, so I don't know about any issues there. Feel free to post another question if you get stuck there and mention it in a comment and I'll try to help.
Vahid Nateghi, the init codes and the work codes must run in the same thread. But the constructor of UdpReceiver runs in the main thread against the one readPendingDiagrams runs in, that was the bug. Try this:
#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QUdpSocket>
class UdpReceiver : public QObject
{
Q_OBJECT
private:
QUdpSocket * S;
int port;
public:
UdpReceiver(QObject* parent = 0) : QObject(parent)
{
qDebug() << ">HERE was the bug! thread:" << QThread::currentThreadId() << "in Construction of UdpReceiver:" << __LINE__ ;
}
public slots:
void init_thread(){
port = 10000;
qDebug() << ">thread:" << QThread::currentThreadId() << "in init_thread:" << __LINE__ ;
S = new QUdpSocket();
S->bind(port);
S->connect(S,SIGNAL(readyRead()),this,SLOT(readPendingDiagrams()));
qDebug() << "Waiting for UDP data from port " << port << " ... \n";
}
void readPendingDiagrams()
{
qDebug() << ">thread:" << QThread::currentThreadId() << "in readPendingDiagrams:" << __LINE__ ;
while(S->waitForReadyRead())
{
QByteArray datagram;
datagram.resize(S->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
S->readDatagram(datagram.data(), datagram.size(),&sender, &senderPort);
qDebug() << datagram.size() << " bytes received in thread " << QThread::currentThreadId() << "in readPendingDiagrams:" << __LINE__ ;
}
}
};
int main(int argc, char *argv[])
{
qDebug() << ">Main thread:" << QThread::currentThreadId() << "in main:" << __LINE__ ;
QCoreApplication a(argc, argv);
QThread *t = new QThread();
UdpReceiver * net = new UdpReceiver();
net->moveToThread(t);
net->connect(t,SIGNAL(started()),net,SLOT(init_thread()));
t->start();
return a.exec();
}
#include "main.moc"
Related
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 ...)
Here is a short UDP server example in Qt below which does work but what I don't like is that I'm polling to see if new data is available. I've come across some examples of a readyRead() but they all seem to introduce a qt class. Do I need to use a qt class in order to take advantage of the readyRead() signal?
Here is the working but simple UDP server implemented entirely in main:
#include <QDebug>
#include <QUdpSocket>
#include <QThread>
int main(int argc, char *argv[])
{
QUdpSocket *socket = new QUdpSocket();
u_int16_t port = 7777;
bool bindSuccess = socket->bind(QHostAddress::AnyIPv4, port);
if (!bindSuccess) {
qDebug() << "Error binding to port " << port << " on local IPs";
return a.exec();
}
qDebug() << "Started UDP Server on " << port << endl;
QHostAddress sender;
while (true) {
while (socket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
qDebug() << "Message From :: " << sender.toString();
qDebug() << "Port From :: "<< port;
qDebug() << "Message :: " << datagram.data();
}
QThread::msleep(20);
}
return 0;
}
Here is an example of the readyRead() signal:
https://www.bogotobogo.com/Qt/Qt5_QUdpSocket.php
I haven't really figured out how to get this to work yet. I must be doing something wrong. Here is the UDP connection code i'm trying:
#include "myudp.h"
MyUDP::MyUDP(QObject *parent) : QObject(parent) {
}
void MyUDP::initSocket(u_int16_t p) {
port = p;
udpSocket = new QUdpSocket(this);
bool bindSuccess = udpSocket->bind(QHostAddress::LocalHost, port);
if (!bindSuccess) {
qDebug() << "Error binding to port " << port << " on local IPs";
return;
}
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
void MyUDP::readPendingDatagrams() {
QHostAddress sender;
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
qDebug() << "Message From :: " << sender.toString();
qDebug() << "Port From :: " << port;
qDebug() << "Message :: " << datagram.data();
}
}
myudp.h
#include <QObject>
#include <QUdpSocket>
class MyUDP : public QObject
{
Q_OBJECT
public:
explicit MyUDP(QObject *parent);
void initSocket(u_int16_t p);
u_int16_t port;
QUdpSocket *udpSocket;
signals:
public slots:
void readPendingDatagrams();
};
new main.cpp
int main(int argc, char *argv[])
{
MyUDP *myUDP = new MyUDP(0);
myUDP->initSocket(port);
while (true) {
usleep(1000);
}
return 0;
}
I am testing with:
netcat 127.0.0.1 -u 7777
{"cid"="0x1234123412341", "fill_level"=3245 }<cr>
What you're doing wrong is that you're not letting Qt's event loop run. i.e. this is incorrect:
int main(int argc, char *argv[])
{
MyUDP *myUDP = new MyUDP(0);
myUDP->initSocket(port);
while (true) {
usleep(1000);
}
return 0;
}
... instead, you should have something like this:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// connect needs to occur after QCoreApplication declaration
MyUDP *myUDP = new MyUDP(0);
myUDP->initSocket(port);
return app.exec();
}
... it is inside the app.exec() call where a Qt application spends most of its time (app.exec() won't return until Qt wants to quit), and there is where Qt will handle your UDP socket's I/O and signaling needs.
Please modify your processPendingDatagrams like this, to let newer incoming data be processed:
void MyUDP::readPendingDatagrams() {
QHostAddress sender;
uint16_t port;
QByteArray datagram; // moved here
while (udpSocket->hasPendingDatagrams()) {
//QByteArray datagram; // you don't need this here
datagram.resize(udpSocket->pendingDatagramSize());
udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
qDebug() << "Message From :: " << sender.toString();
qDebug() << "Port From :: " << port;
qDebug() << "Message :: " << datagram.data();
}
// God knows why, there is always one more "dummy" readDatagram call to make,
// otherwise no new readyRead() will be emitted, and this function would never be called again
datagram.resize(udpSocket->pendingDatagramSize());
socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
}
I am trying write a QT program to receive UDP packet.I am trying to receive from Packet Sender software
This is my code
socket = new QUdpSocket(this);
bool result = socket->bind(QHostAddress("150.100.50.88"),45454);
qDebug() << result;
if(result)
{
qDebug << "PASS";
}
else
{
qDebug << "FAIL";
}
processPendingDatagrams();
connect(socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()),Qt::QueuedConnection);
void UDP::processPendingDatagrams()
{
QHostAddress sender;
u_int16_t port;
while (socket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
qDebug() <<"Message From :: " << sender.toString();
qDebug() <<"Port From :: "<< port;
qDebug() <<"Message :: " << datagram;
} //! [2]
}
UDP.h:
class UDP : public QObject
{
Q_OBJECT public:
explicit UDP(QObject *parent = 0);
signals:
public slots:
void SendDatagram(u_int8_t,u_int8_t,u_int8_t);
private slots:
void processPendingDatagrams();
private :
QUdpSocket *socket;
};
The readReady signal and corresponding slot are not working . I can see the packets in Wireshark.
If a I try receive the packets in continuously in a loop I am able see the datagrams.What can be the reason for signals and Slots for not working.Sending operation is working well.
This code work for me. Try it please.
.pro:
#-------------------------------------------------
#
# Project created by QtCreator 2017-03-10T11:44:19
#
#-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = test
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
mainwindow.cpp:
#include "mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
socket = new QUdpSocket(this);
bool result = socket->bind(QHostAddress::AnyIPv4, 45454);
qDebug() << result;
if(result)
{
qDebug() << "PASS";
}
else
{
qDebug() << "FAIL";
}
processPendingDatagrams();
connect(socket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()),Qt::QueuedConnection);
}
MainWindow::~MainWindow()
{
}
void MainWindow::processPendingDatagrams()
{
qDebug() << "in !";
QHostAddress sender;
u_int16_t port;
while (socket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
qDebug() <<"Message From :: " << sender.toString();
qDebug() <<"Port From :: "<< port;
qDebug() <<"Message :: " << datagram;
}
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QUdpSocket>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void processPendingDatagrams();
private:
QUdpSocket *socket = nullptr;
};
#endif // MAINWINDOW_H
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
tried with netcat with the command:
netcat -u 127.0.0.1 45454
once you ran the command, just type anything and press return.
In my case this did not work, because there was always a "dummy" datagram left somewhere in memory, even if hasPendingDatagrams() returned false, I had to call readDatagram one more time to let my program receive newer datagrams. My answer is here anyways https://stackoverflow.com/a/74056997/11414500
Good luck!
#Gabriel answer did't work for me because it's using the old connect syntax. I updated it to the following (Qt 6):
// udpclient.h
#ifndef UDPCLIENT_H
#define UDPCLIENT_H
#include <QObject>
#include <QUdpSocket>
class UdpClient: public QObject
{
Q_OBJECT
public:
explicit UdpClient(QObject *parent);
void initSocket();
private:
void processPendingDatagrams();
QUdpSocket *socket=nullptr;
};
#endif // UDPCLIENT_H
// udpclient.cpp
#include "udpclient.h"
UdpClient::UdpClient(QObject *parent) : QObject(parent) {
}
void UdpClient::initSocket()
{
socket = new QUdpSocket(this);
bool result = socket->bind(QHostAddress::AnyIPv4, 4999);
if(result)
{
qDebug() << "Socket PASS";
}
else
{
qDebug() << "Socket FAIL";
}
processPendingDatagrams();
connect(socket, &QUdpSocket::readyRead, this, &UdpClient::processPendingDatagrams);
}
void UdpClient::processPendingDatagrams()
{
qDebug() << "in !";
QHostAddress sender;
quint16 port;
while (socket->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(),datagram.size(),&sender,&port);
qDebug() <<"Message From :: " << sender.toString();
qDebug() <<"Port From :: "<< port;
qDebug() <<"Message :: " << datagram;
}
}
It can be used in a function or main() as:
auto udpClient = new UdpClient(0);
udpClient->initSocket();
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.
Programm works, but client can't connect to the server. (i run 2 examples of programm: client and server). I can't find where is my mistake.
I wrote the codes below.You will see what i want to do if you look at main function.
//main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//выбор клиента или сервера
cout << "1.Client\n2.Server\n";
switch (_getch())
{
case 49:
{
cout<<"client init\n";
Client* cli = new Client("localhost",1922);
string line;
while(line!="exit") {
cout << "Message : ";
cin >> line;
cli->SendData(QString(line.c_str()));
}
break;
}
case 50:
{
cout<<"server init\n";
Server* srv = new Server(0, 1922);
break;
}
}
return a.exec();
}
//server.h
class Server : public QTcpServer {
Q_OBJECT public : Server(QObject *parent = 0, quint16 port = 1922);
virtual ~Server();
private
slots:
void acceptConnection();
void startRead();
void disconnected();
private:
QTcpServer *tcpServer;
QTcpSocket *client;
};
//server.cpp
Server::Server(QObject *parent, quint16 port) : QTcpServer(parent) {
//tcpServer = new QTcpServer(this);
connect(this, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
if (!this->listen(QHostAddress::Any, port))
std::cout << "unable to start server\n"
<< this->errorString().toUtf8().constData() << endl;
else
std::cout << "server started\n";
}
Server::~Server() {
//delete client;
close();
}
void Server::acceptConnection() {
std::cout << "new connection!\n";
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() {
client = (QTcpSocket *)sender();
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());
}
//} <-- EDIT: THIS IS PROBABLY AN EXTRA
//***************************************************************
//client.h
class Client : public QObject {
Q_OBJECT public : Client(const QString &add, int port, QObject *obj = 0);
void SendData(QString data);
virtual ~Client();
int status();
QString err;
private
slots:
void ReadData();
void slotConnected();
void slotError(QAbstractSocket::SocketError);
private:
QTcpSocket *socket;
};
//client.cpp
Client::Client(const QString &add, int port, QObject *obj) : QObject(obj) {
//create socket
socket = new QTcpSocket(this);
//connect
socket ->connectToHost(add, port);
connect(socket, SIGNAL(readyRead()), SLOT(ReadData()));
connect(socket, SIGNAL(connected()), SLOT(slotConnected()));
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
SLOT(slotError(QAbstractSocket::SocketError)));
}
Client::~Client() {
socket->close();
delete socket;
}
void Client::SendData(QString data) {
if (!data.isEmpty()) {
QByteArray arrBlock;
QDataStream out(&arrBlock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_1);
out << quint16(0) << QTime::currentTime() << data;
out.device()->seek(0);
out << quint16(arrBlock.size() - sizeof(quint16));
socket->write(arrBlock);
socket->flush();
}
}
void Client::ReadData() {
QDataStream in(socket);
in.setVersion(QDataStream::Qt_5_1);
while (socket->canReadLine()) {
QString line = QString::fromUtf8(socket->readLine()).trimmed();
qDebug() << line;
}
}
void Client::slotConnected() {
socket->write(QString("Client : Server connection has been made (: \n")
.toUtf8());
}
void Client::slotError(QAbstractSocket::SocketError err) {
QString strError =
"Error: " + (err == QAbstractSocket::HostNotFoundError
? "The host was not found."
: err == QAbstractSocket::RemoteHostClosedError
? "The remote host is closed."
: err == QAbstractSocket::ConnectionRefusedError
? "The connection was refused."
: QString(socket->errorString()));
std::cout << strError.toUtf8().constData() << endl;
}
int Client::status() { return socket->state(); }
help me pls!
It's probably becouse of the while loop in main.cpp, it blocks client's event loop, and will return to event loop right after 'exit' will be typed. I mean this lines:
while (line != "exit") {
cout << "Message : ";
cin >> line;
cli.SendData(QString(line.c_str()));
}
How this can be avoided: main.cpp MUST reach return a.exec(); line to start event loop (i am excluding some ugly processEvent solutions right away ).
To send commands to cmd and NOT block event loop i used class i saw somewhere here on stackoverflow:
example of main.cpp:
QCoreApplication a(argc, argv);
qDebug()<<"Press 'q' to quit";
QTcpServer server;
qDebug()<<"Server is started -"<<server.isListening();
// Console reader to filter console input
ConsoleReader reader;
QObject::connect(&reader,SIGNAL(shutdown()),&a,SLOT(quit()));
return a.exec();
aaand behold, ConsoleReader class, header:
#ifndef CONSOLEREADER_H
#define CONSOLEREADER_H
#pragma once
#include <QObject>
#include <QSocketNotifier>
class ConsoleReader : public QObject
{
Q_OBJECT
public:
explicit ConsoleReader(QObject *parent = 0);
~ConsoleReader();
signals:
void shutdown();
public slots:
void text();
private:
QSocketNotifier* notifier;
};
#endif // CONSOLEREADER_H
source:
#include "consolereader.h"
#include <QTextStream>
#include <QDebug>
#include <unistd.h> //Provides STDIN_FILENO
ConsoleReader::ConsoleReader(QObject *parent) :
QObject(parent)
{
notifier = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read);
connect(notifier, SIGNAL(activated(int)), this, SLOT(text()));
}
void ConsoleReader::text()
{
QTextStream qin(stdin);
QString line = qin.readLine();
if (line==QString("q")){
qDebug()<<"Shutting down the server..";
emit shutdown();
}
else qDebug()<<"Unknown command: "<<line;
}
ConsoleReader::~ConsoleReader(){
delete notifier;
}
In your main function, you create both the client and the server on the stack, which will then be deleted when they go out of scope of the switch statement.
You need to dynamically allocate the objects on the heap: -
Server* pServer = new Server(0, 1922);
Client* pClient = new Client("localhost" 1922);
Although the client will remain, due to the while loop after its creation, the server will be created, start listening, then be deleted, along with the QTcpSocket, as it is has the server as its parent.
As I mentioned in my comment there is no need to create a separate QTCpServer as the server isa QTcpServer. So where you have:
Server::Server(QObject *parent, quint16 port) : QTcpServer(parent) {
tcpServer = new QTcpServer(this);
connect(this, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
if (!tcpServer->listen(QHostAddress::Any, port))
std::cout << "unable to start server\n"
<< tcpServer->errorString().toUtf8().constData() << endl;
else
std::cout << "server started\n";
}
Change to:
Server::Server(QObject *parent, quint16 port) : QTcpServer(parent) {
connect(this, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
if (!this->listen(QHostAddress::Any, port))
std::cout << "unable to start server\n"
<< this->errorString().toUtf8().constData() << endl;
else
std::cout << "server started\n";
}
I think the problem could be that its trying to do stuff with a different object rather than the 'this' object.