I'm starting to create my first multithread application, using the QT libraries.
Following the qt guide about QTcpServer and QTcpSocket, i wrote a server application that create the connection with this constructor:
Connection::Connection(QObject *parent) : QTcpServer(parent)
{
server = new QTcpServer();
QString ipAddress;
if (ipAddress.isEmpty())
ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
if (!server->listen(QHostAddress(ipAddress),41500))
{
qDebug() << "Enable to start server";
server->close();
return;
}
connect(server,SIGNAL(newConnection()),this,SLOT(incomingConnection()));
}
This is the incomingConnection() function which create a new thread everytime a new client try to connect:
void Connection::incomingConnection()
{
QTcpSocket *socket = new QTcpSocket();
socket = this->nextPendingConnection();
MyThreadClass *thread = new MyThreadClass(socket, server);
qDebug() << "connection required by client";
if (thread != 0)
{
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
else
qDebug() << "Error: Could not create server thread.";
}
Now, this is MyThreadClass:
MyThreadClass::MyThreadClass(QTcpSocket *socket, QTcpServer *parent) : QThread(parent)
{
tcpSocket = new QTcpSocket();
database = new Db();
blockSize = 0;
tcpSocket = socket;
qDebug() << "creating new thread";
}
MyThreadClass::~MyThreadClass()
{
database->~Db();
}
void MyThreadClass::run()
{
qDebug() << "Thread created";
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
exec();
}
void MyThreadClass::dataAvailable()
{
qDebug() << "data available";
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(qint16))
return;
in >> blockSize;
}
if (tcpSocket->bytesAvailable() < blockSize)
return;
QString string;
in >> string;
//[...]
}
The code compiles fine but when i start a client (after starting the server), i receive the following error by server:
QObject::connect: Cannot connect (null)::readyRead() to QThread::dataAvailable()
Then the server cannot receive data by the client.
does anyone have any idea?
thanks in advance
Daniele
socket = this->nextPendingConnection();
should be:
socket = server->nextPendingConnection();
because you are using the server member and not this as the active QTcpServer, the class Connection shouldn't even inherit from QTcpServer, but only from QObject.
Also, you are misusing QThread. You should read Signals and slots across threads, and probably Threads and the SQL Module, if Db is using the QtSql module.
Related
all
I want to use QUdpSocket to send udp packet to get config parameter from specific server,but It failed and I can not capture the sending packet using wireshark.here is my code:
CGetConfig.cpp:
CGetConfig::CGetConfig(const QString &conf_server,const uint16_t port)
:m_conf_server(conf_server)
,m_port(port)
{
m_socket = NULL;
}
CGetConfig::~CGetConfig()
{}
void CGetConfig::init()
{
// create a QUDP socket
m_socket = new QUdpSocket(this);
m_socket->bind(QHostAddress::LocalHost, 12345);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
m_ip_addr = get_ip_address(m_conf_server);
}
bool CGetConfig::get_reflector(const QString &mac)
{
qDebug() << "CGetConfig::get_reflector():Entry\n";
if(m_ip_addr.isEmpty())
{
qDebug() << "CGetConfig::get_reflector():ip address of cofnig server could not be resolved\n";
return 0;
}
QString msg("id=1&mac=");
msg+= mac;
msg+= "&get_config=fw_type=v.1,cfg_ver=4,set_ver=0,ip=192.168.1.101";
qDebug() << m_ip_addr;
qDebug() << m_port;
qDebug() << msg.toLatin1();
int count = 0;
while(count < 3)
{
int t = m_socket->writeDatagram(msg.toLatin1(), QHostAddress(m_ip_addr), m_port);
count++;
}
}
Main.cpp
CGetConfig cfg(cfg_server,cfg_port);
cfg.init();
local_mac = "00d033120001";
cfg.get_reflector(local_mac);
Can anyone help me figure out the problem?
I've created two simple TCP/IP communication programs (server & client). It basically just sends and receives the same message over and over again.
However when I execute client and server on the same workstation everything runs fine. It is only then, when I execute the same programs via a lokal network that the server doesn't receive any incomming connection requests.
The firewall is disabled on both stations. Has anyone an idea what I'm missing out?
Here is the code
client.cpp
#include "client.h"
#include <QHostAddress>
#include <iostream>
#include <conio.h>
Client::Client(QObject* parent): QObject(parent)
{
connect(&client, SIGNAL(connected()), this, SLOT(startTransfer()));
connect(&client, SIGNAL(readyRead()), this, SLOT(receive()));
QHostAddress addr = QHostAddress("127.0.0.1");
client.connectToHost(addr, 5200);
}
Client::~Client()
{
client.close();
}
void Client::startTransfer()
{
client.write("Hello, world", 13);
send("start client communication");
}
void Client::send(const char *buffer)
{
std::cout<<"OUT: "<<buffer<<std::endl;
client.write(buffer,strlen(buffer));
}
void Client::receive()
{
char temp[1024] = {0};
int len = client.read(temp,client.bytesAvailable());
std::cout<<"IN: "<< temp<<std::endl;
send("client to server");
}
server.cpp
#include "theserver.h"
#include <iostream>
#include <conio.h>
using namespace std;
Server::Server(QObject* parent): QObject(parent)
{
connect(&server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
server.listen(QHostAddress::Any, 5200);
}
Server::~Server()
{
server.close();
}
void Server::acceptConnection()
{
client = server.nextPendingConnection();
if(client)
{
connect(client, SIGNAL(readyRead()), this, SLOT(receive()));
}
}
void Server::startRead()
{
char buffer[1024] = {0};
client->read(buffer, client->bytesAvailable());
cout << "IN: "<<buffer << endl;
}
void Server::receive()
{
char buffer[1024] = {0};
client->read(buffer, client->bytesAvailable());
cout << "IN: "<<buffer << endl;
}
void Server::sendData(const char* buffer)
{
cout <<"OUT: "<<buffer<<endl;
if(client)
client->write(buffer);
}
I'm first initiating the server program following by the client
You need to use the remote machine's IP address to connect. Now you are always connecting to 127.0.0.1, which is the machine where the application is being run. That is why the connection is never made to a remote machine.
Firstly, I'd like to trigger an initialization process whenever this class been created. (DNS lookups for known hosts, and and pre-handshake with hosts over a specified number of slots - this shall not be hardcoded once it has been tested) - while all the classes are being created, config is being read, etc.
Secondly, I'd like to allow parallelized request sending depending on the allowed (and opened) slots present for the specific host.
Quite frankly there's multiple issues with the following code;
Google seems to redirect, upon multiple requests at the same time to this host seems to result in a catastrophic failure, when x number or request triggers the finished signal, and that signals invokes my redirect checking and the first request get redirected, and I do seem to get the first reply back, with x error messages.
I cant seem to invoke deleteLater() from httpFinished for the same reason
I've could not find a way to wait for the slot number of request to be finished to start the next request in queue
The main goal would be to gather data from multiple APIs using a single network class, those requests would maybe occur the same time, may not.
Also there would be another request emitted just as POST, etc. - maybe 1 class / API?
Please note that the code is just test of concept and for testing purposes only, and this shall be cleaned after it has been fixed, this is not how I intended it to work at all.
nebula.pro
QT += core network
QT -= gui
TARGET = nebula
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
network.cpp
HEADERS += \
network.h
network.h
#ifndef NETWORK_H
#define NETWORK_H
#include <QObject>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QHostInfo>
#include <QtNetwork/QSslConfiguration>
#include <QEventLoop>
class network : public QObject
{
Q_OBJECT
public:
explicit network(QObject *parent = 0);
~network();
void sendGet(const QUrl &url);
private:
QNetworkAccessManager networkAccessManager;
QHash<QString, QByteArray> usedSession;
QNetworkReply *reply;
QUrl url;
Q_INVOKABLE void init();
void replyFinished(QUrl &url, QNetworkReply *reply);
QList<QString> provideTcpHosts();
QList<QString> provideSslHosts();
QEventLoop eventLoop;
private slots:
void httpError();
void sslErrors(const QList<QSslError> &errors);
void httpFinished();
};
#endif // NETWORK_H
network.cpp
#include "network.h"
/**
* #brief network::network
* initialazing pre-networking initialization once the eventpool is ready
* #param parent
*/
network::network(QObject *parent) : QObject(parent)
{
QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
}
network::~network()
{
networkAccessManager.deleteLater();
}
/**
* #brief network::init
* dns chache warming for all hosts and pre-connecting to all hosts via 4 sockets
*/
void network::init()
{
QList<QString> tcpHosts = provideTcpHosts();
QList<QString> sslHosts = provideSslHosts();
// tcp hosts initialazation
for( int i=0; i<tcpHosts.count(); ++i )
{
// pre-dns lookup cache warming
QHostInfo::lookupHost(tcpHosts[i], 0, 0);
qDebug() << "pre-dns lookup cache warming for: " + tcpHosts[i];
// tcp pre-handshake with known hosts over 4 sockets with known http hosts
for(int a=0; a<4; ++a)
{
networkAccessManager.connectToHost(tcpHosts[i], 80);
qDebug() << "connecting " + QString::number(a+1) + "th socket for " + tcpHosts[i];
}
}
// tcp hosts initialazation
for( int i=0; i<sslHosts.count(); ++i )
{
// pre-dns lookup cache warming
QHostInfo::lookupHost(sslHosts[i], 0, 0);
qDebug() << "pre-dns lookup cache warming for: " + sslHosts[i];
// tcp pre-handshake with known hosts over 4 sockets with known http hosts
for(int a=0; a<4; ++a)
{
networkAccessManager.connectToHostEncrypted(sslHosts[i], 443);
qDebug() << "connecting " + QString::number(a+1) + "th socket for " + sslHosts[i];
}
}
}
/**
* #brief network::replyFinished
* storing previous ssl session tickets for re-use, and error handling for finished requests
* #param url
* #param reply
*/
void network::replyFinished(QUrl &url, QNetworkReply *reply)
{
if(!usedSession.contains((QString)url.toString()))
{
usedSession.insert((QString)url.toString(), (QByteArray)reply->sslConfiguration().sessionTicket());
qDebug() << "saved ssl session ticket for" + url.toString();
}
reply->deleteLater();
}
/**
* #brief network::sendGet
* sending a simple GET request to specified url
* #param url
*/
void network::sendGet(const QUrl &url)
{
connect(&networkAccessManager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
qDebug() << "Sending a GET request to" + (QString)url.toString();
QNetworkRequest request;
request.setUrl(url);
request.setRawHeader("User-Agent", "nebula");
// reusing an ssl session ticket if exists for url
if(usedSession.contains((QString)url.toString()))
{
QSslConfiguration qssl;
qssl.setSslOption(QSsl::SslOptionDisableSessionPersistence, false);
qssl.setSessionTicket(usedSession.value((QString)url.toString()));
request.setSslConfiguration(qssl);
qDebug() << "used ssl session ticket for" + url.toString();
}
reply = networkAccessManager.get(request);
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(httpError()));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(sslErrors(QList<QSslError>)));
connect(reply, SIGNAL(finished()), this, SLOT(httpFinished()));
}
/**
* #brief network::provideTcpHosts
* #return
*/
QList<QString> network::provideTcpHosts()
{
return QList<QString>()
<< (QString)"http://www.google.com"
<< (QString)"http://www.bing.com";
}
/**
* #brief network::provideSslHosts
* #return
*/
QList<QString> network::provideSslHosts()
{
return QList<QString>()
<< (QString)"https://www.ssllabs.com/ssltest/";
}
/*SLOTS*/
/**
* #brief network::slotTcpError
* #param tcpError
*/
void network::httpError()
{
qDebug() << "QNetworkRequest::HttpStatusCodeAttribute " << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute ) << "received";
qDebug() << reply->errorString();
reply->deleteLater();
}
/**
* #brief network::slotSslErrors
* #param sslErrors
*/
void network::sslErrors(const QList<QSslError> &errors)
{
QString errorString;
foreach (const QSslError &error, errors) {
if (!errorString.isEmpty())
errorString += ", ";
errorString += error.errorString();
}
qDebug() << "ssl error recieved: " + errorString;
reply->deleteLater();
}
void network::httpFinished()
{
// possible redirect url
QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (!redirectionTarget.isNull()) {
this->sendGet(reply->url().resolved(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl()));
} else {
qDebug() << "QNetworkRequest::HttpStatusCodeAttribute " << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute ) << "received ";
qDebug() << reply->errorString();
qDebug() << reply->readAll();
}
}
main.cpp
#include <QCoreApplication>
#include <network.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
network networkAccessManager;
for(int i = 0; i < 50; ++i)
{
networkAccessManager.sendGet((QString)"http://www.google.com");
}
return a.exec();
}
Please, note I'm quite new to advanced C++ projects and to QT, this project partially -but will be used for my awesome project once its un-screwed- is to help me being familiarized with those topics.
Could you help me out, oh glorious stranger? :)
Regards;
OneEyedSpaceFish
I'm writing an application that communicates via QTcpSocket between Server and Client.
Server is an application with gui on standard pc.
Client is a console application on Raspberry pi.
client.cpp
#include "client.h"
#include <QHostAddress>
#include <cstdio>
Client::Client() :
QObject()
{
socket = new QTcpSocket(this);
printf("try to connect.\n");
connect(socket, SIGNAL(connected()),
this, SLOT(onConnected()));
connect(socket, SIGNAL(readyRead()),
this, SLOT(readyRead()));
}
void Client::onConnected()
{
printf("Connection established.\n");
// char buffer[1024];
// forever
// {
// while(socket->canReadLine())
// {
// QByteArray ba = socket->readLine();
// printf("from server: %s", ba.constData());
// }
// printf(">> ");
// gets(buffer);
// int len = strlen(buffer);
// buffer[len] = '\n';
// buffer[len+1] = '\0';
// socket->write(buffer);
// socket->flush();
// }
}
void Client::readyRead(){
if(socket->canReadLine())
{
QByteArray ba = socket->readLine();
printf("from server: %s", ba.constData());
}else{
printf(":(");
}
}
void Client::connectToServer()
{
socket->connectToHost(QString("192.168.0.103"), 5100);
}
server.cpp
#include "server.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <cstdio>
#include <QtDebug>
Server::Server(int listenPort)
:QObject()
{
port = listenPort;
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()),
this, SLOT(onNewConnection()));
}
void Server::listen()
{
server->listen(QHostAddress::Any, port);
}
void Server::sendMessage(QString message){
qDebug() << message;
QByteArray response;
response.append(message);
qDebug() << socket->peerAddress() ;
socket->write(response);
socket->flush();
}
void Server::onNewConnection()
{
socket = server->nextPendingConnection();
if(socket->state() == QTcpSocket::ConnectedState)
{
qDebug()<<socket->peerAddress();\
emit onConnectionEstablished(socket->peerAddress().toString());
}
connect(socket, SIGNAL(disconnected()),
this, SLOT(onDisconnected()));
connect(socket, SIGNAL(readyRead()),
this, SLOT(onReadyRead()));
}
void Server::onReadyRead()
{
if(socket->canReadLine())
{
QByteArray ba = socket->readLine();
emit onMessageRecieved(QString(ba));
QByteArray response("maslO!");
// some code which parses arrived message
// and prepares response
socket->write(response);
socket->flush();
}
//else just wait for more data
}
void Server::onDisconnected()
{
printf("Connection disconnected.\n");
disconnect(socket, SIGNAL(disconnected()));
disconnect(socket, SIGNAL(readyRead()));
socket->deleteLater();
}
This is the code. So now the problem description:
I'm starting Server application and then Client application on Raspberry.
Both apps are connecting I see it in "onNewConnection" method in Server.cpp.
But when I try to send something to Client using "sendMessage" in server.cpp, Client shows nothing.
I should recieve data from server in "readyRead" method in client.cpp but it is never called. What did i wrong?
My friend told me to check if i got same version of QT on both platforms. So i checked and it is not but maybe it is the problem?
Raspberry pi, Arch linux without x server
QMake version 3.0
Using Qt version 5.2.1 in /usr/lib
Server, linux mint
QMake version 3.0
Using Qt version 5.2.0 in /home/adam/Qt/5.2.0/gcc_64/lib
Can you also give me some tips to improve this code?
im grabbing url's from a list and then sending each to a QNetworkRequest and recieving the HTML back to process. I however have thousands of requests to process. So my application kept hanging until i stopped it from producing all these requests at once.
Is this the rite way to handle the que for a great number of requests?
I tried using a Qqueue of Urls, which i would then link to a SLOT which was triggered after each QNetworkReply reponse.
Create the job list and add to que
QQueue<QString> jobs;
for (int i = 1; i <= totalPages; i++){
QString pageUrl = url + "&page=" + QString::number(i);
jobs.enqueue(pageUrl);
}
qDebug() << "Total Jobs : " << jobs.count() << endl;
for (int i = 0; i < 5; i++){
processQueue();
}
then inside the getHtml function
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QNetworkRequest *getHtmlRequest = new QNetworkRequest(pageUrl);
getHtmlRequest = new QNetworkRequest(url);
getHtmlRequest->setRawHeader( "User-Agent", "Mozilla/5.0 (X11; U; Linux i686 (x86_64); "
"en-US; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1" );
getHtmlRequest->setRawHeader( "charset", "utf-8" );
getHtmlRequest->setRawHeader( "Connection", "keep-alive" );
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyGetPageHtmlFinished(QNetworkReply*)));
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(processQueue()));
manager->get(*getHtmlRequest);
which triggers
void checkNewArrivalWorker::processQueue(){
if (jobs.isEmpty()){
qDebug() << "Jobs Completed" << endl;
emit finished();
} else {
QString pageUrl = jobs.dequeue();
QString pageNumber = pageUrl.mid(pageUrl.indexOf("page=") + 5);
getHtml(pageUrl, pageNumber);
}
}