FTPClient using QTcpSocket and signals and slots
-
Hi and welcome to devnet,
Without seeing your code, it's pretty much crystal ball debugging. Can you share it ?
Out of curiosity, are you tied to QTcpSocket ?
-
Hi, thank you for the reply:) Infortunately I can use only QTcpSocket for this project :/ It's the requirement to pass the course ony my studies.
Here come's my source code and a screenshot from the project so you can see what files I have.
!http://przeklej.org/file/vlK2gP/snapshot1.png(QTCreator-snapshot)!MAINWINDOW.h:
@#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <exitdialog.h>
#include <QString>
#include <QDirModel>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{
Q_OBJECTpublic:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void Refresh();
QString url, login, password, port;
private slots:
void on_actionZako_cz_triggered();void on_actionKonfiguruj_triggered(); void on_pushButton_clicked(); void on_pushButton_3_clicked(); void on_pushButton_2_clicked(); void on_pushButton_5_clicked();
private:
QDirModel dirModel;
Ui::MainWindow *ui;
void addRoot(QString name, QString size, QString type);
};#endif // MAINWINDOW_H
@ -
MAINWINDOW.cpp
@#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "exitdialog.h"
#include "konfigurujdialog.h"
#include "socketconnection.h"
#include <QMessageBox>
#include <stdio.h>
#include <QRegExp>MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Refresh();
}MainWindow::~MainWindow()
{
delete ui;
}void MainWindow::on_actionZako_cz_triggered()
{
ExitDialog *exit = new ExitDialog();
exit->setModal(true);
exit->exec();
}void MainWindow::on_actionKonfiguruj_triggered()
{
KonfigurujDialog *konfig = new KonfigurujDialog();
konfig->setModal(true);
konfig->exec();
}void MainWindow::on_pushButton_clicked() //connect button
{
ui->textBrowser->clear();
ui->treeWidget_2->clear();
url = ui->urlValue->text();
login = ui->loginValue->text();
password = ui->passwordValue->text();
port = ui->portValue->text();socketconnection *s = new socketconnection(url, login, password, port); QString komunikat, komunikat2; QString* listaFolderow; QString* sciezkaFolderow; komunikat = s->test(); listaFolderow = &(s->directoryList); // downloading the content from the public variable that's carreing the dirlisting sciezkaFolderow = &(s->currentPath); // downloading the content from the public variable that's carreing the currentpath on the ftp server ui->textBrowser->insertPlainText(komunikat); QRegExp regex1("\n"); QRegExp regex2("[ ]+|\n"); std::string DirPath = sciezkaFolderow->toStdString(); *sciezkaFolderow = ""; for(int i = 0; i < DirPath.length(); i++) { int j = i+1; if(DirPath[i] == '\"') { while(DirPath[j] != '\"') { *sciezkaFolderow += DirPath[j]; j++; } break; } } qDebug() << *sciezkaFolderow; ui->lineEdit_6->setText(*sciezkaFolderow); QStringList listing; // lista zawierająca całe wiersze listingu plików listing = listaFolderow->split(regex1); std::string part; std::string partI, partII; QStringList QpartI; int i = 0, globalCounter = 0; foreach (QString var, listing) globalCounter++; QString czyFolder[globalCounter], Rozmiar[globalCounter], Nazwa[globalCounter]; foreach (QString var, listing) { part = var.toStdString(); int licznik = 0; for(int j = 0; j < part.length(); j++) { if(licznik < 55) partI += part[j]; else { if(licznik == part.length()-1) break; partII += part[j]; } licznik++; } QpartI << QString::fromStdString(partI).split(regex2); Nazwa[i] = QString::fromStdString(partII); partI = ""; partII = ""; i++; } QpartI.removeAll(""); i = 0; int j = 0; foreach(QString var, QpartI) { i++; if(i == 1) { if(var.left(1) == "d") czyFolder[j] = "Directory"; else czyFolder[j] = "File"; } if(i == 5) Rozmiar[j] = var; if(i == 8) { i = 0; j++; } } for(i = 0; i < globalCounter; i++) { addRoot(Nazwa[i], Rozmiar[i], czyFolder[i]); }
}
void MainWindow::addRoot(QString name, QString size, QString type)
{
QTreeWidgetItem pWidgetItem = new QTreeWidgetItem(ui->treeWidget_2);
pWidgetItem->setText(0, name);
pWidgetItem->setText(1, size);
pWidgetItem->setText(2, type);
ui->treeWidget_2->addTopLevelItem(pWidgetItem);
}
void MainWindow::Refresh()
{
dirModel.setParent(this);
dirModel.setReadOnly(false);
QDirModel model = &dirModel;
ui->treeView->setModel(model);model->setSorting(QDir::DirsFirst | QDir::IgnoreCase | QDir::Name); QModelIndex index = model->index("/"); ui->treeView->expand(index); ui->treeView->scrollTo(index); ui->treeView->setCurrentIndex(index); ui->treeView->resizeColumnToContents(0); // geting the filepath QFileInfo informacja; index = ui->treeView->currentIndex(); informacja = model->fileInfo(index); ui->lineEdit->setText(informacja.filePath());
}
void MainWindow::on_pushButton_3_clicked() //button do przodu sekcji KOMPUTER LOKALNY
{
QDirModel* model = &dirModel;
QModelIndex index = ui->treeView->currentIndex();
ui->treeView->expand(index);
QFileInfo informacja = model->fileInfo(index);
ui->lineEdit->setText(informacja.filePath());
index = ui->treeView->indexBelow(ui->treeView->currentIndex());ui->treeView->setCurrentIndex(index);
}
void MainWindow::on_pushButton_2_clicked() //button cofnij sekcji KOMPUTER LOKALNY
{
QDirModel* model = &dirModel;
ui->treeView->collapse(ui->treeView->currentIndex());
QModelIndex index = ui->treeView->indexAbove(ui->treeView->currentIndex());
// QModelIndex index = ui->treeView->indexAbove(ui->treeView->currentIndex());ui->treeView->setCurrentIndex(index); QFileInfo informacja = model->fileInfo(index); ui->lineEdit->setText(informacja.filePath());
}
void MainWindow::on_pushButton_5_clicked() //butto do przodu sekcji SERWER
{}
@ -
SOCKETCONNECTION.h
@#ifndef SOCKETCONNECTION_H
#define SOCKETCONNECTION_H#include <QMainWindow>
#include <QObject>
#include <iostream>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QString>class socketconnection : public QObject
{
Q_OBJECT
public:
explicit socketconnection(QString url, QString login, QString password, QString port, QObject *parent = 0);
QString test();
QString komunikat, message, command;
QString url, login, password, port;
QString directoryList; //pointer to the downloaded directory listing
QString currentPath;
signals:public slots:
void connected();
private:
QTcpSocket *socket;
QTcpSocket socketTransmit;
};#endif // SOCKETCONNECTION_H
@ -
SOCKETCONNECTION.cpp
@#include "socketconnection.h"
#include "mainwindow.h"
#include <stdio.h>
socketconnection::socketconnection(QString url, QString login, QString password, QString port, QObject *parent) :
QObject(parent)
{
this->url = url;
this->login = login;
this->password = password;
this->port = port;
}
QString socketconnection::test(){
komunikat = "Status: ";
socket = new QTcpSocket(this);
connect(socket, SIGNAL(connected()), this, SLOT(connected()));
komunikat += "Łączenie do serwera FTP...\n";
socket->connectToHost((url.toUtf8().constData()), port.toShort());
if(!socket->waitForConnected(3000)){
komunikat += "Message: ";
komunikat += "Przekroczony limit czasu...\n";
}
return komunikat;
}
void socketconnection::connected()
{
QString adresIP, transfer_port;
std::string passive_connection = "";
std::string oktet[6];
int licznik = 0, portA, portB, portC;
komunikat += "Message: ";
while(message.length() == 0) message = socket->readLine();
komunikat += message;
komunikat += "Polecenie: ";
message = "";
command = "USER " + login + "\r\n";
komunikat += "Polecenie: ";
komunikat += command;
socket->write(command.toUtf8().constData());
socket->waitForBytesWritten(5000);
while(message.length() == 0) message = socket->readLine();
komunikat += "Message: ";
komunikat += message;
message = "";
command = "PASS " + password + "\r\n";
komunikat += "Polecenie: PASS <nie pokażę Ci hasła>\n";
socket->write(command.toUtf8().constData());
socket->waitForBytesWritten(5000);
while(message.length() == 0) message = socket->readLine();
komunikat += "Message: ";
komunikat += message;
message = "";
command = "OPTS UTF8 ON\r\n";
komunikat += "Polecenie: ";
komunikat += command;
socket->write(command.toUtf8().constData());
socket->waitForBytesWritten(5000);
while(message.length() == 0) message = socket->readLine();
komunikat += "Message: ";
komunikat += message;
message = "";
komunikat += "Status: Connected succesfully. Now I'm checking the directory list...\n";
command = "TYPE I\r\n";
komunikat += "Polecenie: ";
komunikat += command;
socket->write(command.toUtf8().constData());
socket->waitForBytesWritten(5000);
while(message.length() == 0) message = socket->readLine();
komunikat += "Message: ";
komunikat += message;
message = "";
command = "PWD \r\n";
komunikat += "Polecenie: ";
komunikat += command;
socket->write(command.toUtf8().constData());
socket->waitForBytesWritten(5000);
int i = 0;
while(message.length() == 0){
message = socket->readLine();
}
currentPath = message;
komunikat += "Message: ";
komunikat += message;
message = "";
command = "PASV \r\n";
komunikat += "Polecenie: ";
komunikat += command;
socket->write(command.toUtf8().constData());
socket->waitForBytesWritten(5000);
while(message.length() == 0) message = socket->readLine();
komunikat += "Message: ";
komunikat += message;
passive_connection = message.toUtf8().constData();
message = "";
for(int i = 3; i < passive_connection.length()-2; i++){
if(passive_connection[i] >= '0' && passive_connection[i] <= '9'){
oktet[licznik] += passive_connection[i];
if(passive_connection[i+1] == ',')
{
licznik++;
continue;
}
}
}
adresIP = QString::fromStdString(oktet[0]) + "." + QString::fromStdString(oktet[1]) + "." + QString::fromStdString(oktet[2])
+ "." + QString::fromStdString(oktet[3]);
portA = QString::fromStdString(oktet[4]).toInt();
portB = QString::fromStdString(oktet[5]).toInt();
portC = (portA * 256 + portB);
transfer_port.setNum(portC);
komunikat += "Tworzę połączenie na następujący adres i port: \n";
komunikat += "Adres: " + adresIP + "\n";
komunikat += "Port: " + transfer_port + "\n";socketTransmit.connectToHost(adresIP, portC); socketTransmit.waitForConnected(2000); komunikat += "Polecenie: "; command = "LIST \r\n"; komunikat += command; socket->write(command.toUtf8().constData()); socket->waitForBytesWritten(5000); socketTransmit.waitForBytesWritten(5000); socketTransmit.waitForReadyRead(5000); socket->waitForBytesWritten(5000); socket->waitForBytesWritten(5000); message = socket->readLine(); //czekamy na odpowiedź kolejną z socketu poleceń komunikat += "Message: "; komunikat += message; message = ""; message = socketTransmit.readAll(); directoryList = message; // pobieramy do zmiennej directoryList listing plików i folderów if (directoryList != ""){ komunikat += "Listing plików i folderów przesłąny z powodzeniem!!!:\n"; } else komunikat += "Błąd! Nie udało mi się pobrać listy plików i folderów!!!\n"; //komunikat += message; message = ""; i = 0; while(message.length() == 0){ i++; message = socket->readLine(); if(i == 32768) { message = "Błąd podczas transmisji polecenia"; break; } } komunikat += "Message: "; komunikat += message; message = ""; }
@
-
I know my code isn't nice but I've just started my QT experience, so I hope that you'll understand and can help me. Thanks a lot :)
-
There are indeed several things that I don't follow:
- Why are you mixing std::string and QString ? Currently it just complicates your code without any benefits
- Why are you using pointers to QString ?
You are also creating memory leaks with your custom dialogs.
Anyway, for your original problem. You are doing everything in the connected slot, which is a bad idea. You need to refactor that and split the logic for the various commands you want to send in their own functions
-
I'm mixing QString with std::string because I couldn't filter the QString like a simple array, so I decided to go on the easiest way and parse it to std::string.
I need pointers to QString because I have no idea how get access to one variable from one class in another class. I think pointers are a good method to get the content from variables....
Which custom dialogs do you mean? I thinked about your advice to split to signal and slot system but I have trouble with it..... now i have something like that:
@#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}MainWindow::~MainWindow()
{
delete ui;
}void MainWindow::on_pushButton_clicked() // connect Button
{
commandSocket = new QTcpSocket(this);login = ui->loginValue->text(); url = ui->urlValue->text(); password = ui->passwordValue->text(); port = ui->portValue->text(); qint64 timeout = 4000; connect(commandSocket, SIGNAL(connected()), this, SLOT(connected())); connect(commandSocket, SIGNAL(bytesWritten(timeout)), this, SLOT(getMessage())); qDebug() << "Connecting..."; commandSocket->connectToHost(url, port.toShort()); if(!commandSocket->waitForConnected(3000)){ qDebug() << "Przekroczony limit czasu...\n"; }
}
void MainWindow::connected()
{
qDebug() << "In connected()...";
sendMessage("USER ", login);}
void MainWindow::sendMessage(QString message, QString argument)
{
qDebug() << "in sendMessage...";
QString displayedArgument, command;
if(message == "PASS ")
displayedArgument = "SECRET_PASSWORD...";
else
displayedArgument = argument;
command = message + argument + "\r\n";
commandSocket->write(command.toUtf8().constData());
commandSocket->waitForBytesWritten(10000);ui->textBrowser->setOverwriteMode(false); ui->textBrowser->setText("Polecenie: " + message + displayedArgument + "\n"); qDebug() << "send message done...";
}
void MainWindow::getMessage()
{
qDebug() << "In getMessage()...";
QString message = "";
//while(message == "")
message = commandSocket->readLine();qDebug() << message; ui->textBrowser->setOverwriteMode(false); ui->textBrowser->setText(message);
}@
and unfortunately it's not working:/
PS. I decidet to put everything in the mainwindow.cpp. -
What do you mean by "can't filter like a simple array" ?
You should have a look at the fortune client/server example for inspiration
-
I mean something like that:
@
QString someQString = "I like Qt!", outputQString = "";
for(int i = 0; i < someQString.length(); i++)
{
if(someQString[i] != " ")
outputString += someQString[i];
}
@ -
You want to remove all white spaces in the string ?
From the top of my head:
@
someQString.replace(QRegular[removed]"\s"), "");
@Replace QRegularExpression by QRegExp if you are on Qt 4
-
Thanks:) I moved forward with my project and now i need help with downloading files. The problem is that, when I download a file (first .txt) the data go on the socket but not everything. When i download a small file it works fine, but when I download a bigger file it looses data. :/ Do you have a advice form me?
P.S. I start the download from the transfer socket, when on the commandLineSocket is the command RETR succesfully transmited.
-
Look at readyRead and the asynchronousness handling of IO devices