PDA

View Full Version : qftp in qthread canot upload file



cxl2253
5th April 2007, 05:05
I used qftp in the qthread,but when i upload file ,I Cannot find the uploaded file and the signal code cannot be executed when debug.the following is code


//////////////storethread.h/////////
class storescpThread:public QThread
{
Q_OBJECT
public:
storescpThread(QTextEdit *txtEdit,QObject *parent = 0);
~storescpThread();
private slots:
void connectOrDisconnect();
void ftpListInfo(const QUrlInfo &urlInfo);
void ftpCommandFinished(int commandId, bool error);
void updateDataTransferProgress(qint64 readBytes,qint64 totalBytes);
private :
QTextEdit * textEdit;
QFtp *ftp;
QFile *file;
QStringList fileList;
}
/////////////////////////storethread.cxx//////////
storescpThread::storescpThread(QTextEdit *txtEdit,QObject *parent): QThread(parent)
{
ftp=0;
}
void storescpThread::connectOrDisconnect()
{
if (ftp) {
ftp->abort();
ftp->deleteLater();
ftp = 0;
}

ftp = new QFtp(this);

//the SLOT function not be perfomed! why?
connect(ftp, SIGNAL(commandFinished(int, bool)),
this, SLOT(ftpCommandFinished(int, bool)));
connect(ftp, SIGNAL(listInfo(const QUrlInfo &)),
this, SLOT(ftpListInfo(const QUrlInfo &)));
connect(ftp, SIGNAL(dataTransferProgress(qint64, qint64)),
this, SLOT(updateDataTransferProgress(qint64, qint64)));

ftp->connectToHost("192.168.1.1");
ftp->login("ftpuser","ftpuser");
ftp->cd("/data"); //init dir
fileList.clear();
ftp->list();
QFile file("c:\\testdata.jpg");
if (!file.open(QIODevice::ReadOnly))
return false;
QFileInfo fi(filename);
ftp->put(&file,"testtest.jpg"); //the file not be uploaded!!!!!


}
// the following SLOT not be perfomed!where is the emited message?
void storescpThread::ftpCommandFinished(int, bool error)
{

if (ftp->currentCommand() == QFtp::ConnectToHost) {
if (error) {
QMessageBox::information(0, tr("FTP"),
tr("error"));
return;
}
return;
}

if (ftp->currentCommand() == QFtp::Get) {

}
if (ftp->currentCommand() == QFtp::List) {
QMessageBox::information(0, tr("FTP"),"LIST");
}
if (ftp->currentCommand() == QFtp::Put) {

}
}

void storescpThread::updateDataTransferProgress(qint64 readBytes, qint64 totalBytes)
{
}

void storescpThread::ftpListInfo(const QUrlInfo &urlInfo)
{
fileList<<urlInfo.name() ;
}

marcel
5th April 2007, 05:58
I can tell you why it doesn't work.

QFtp uses QTimer to schedule commands. QTimer posts timer events in the thread that created it. But your QThread does not have an event handler (can be started only with exec() ).

Funny thing is that sometimes, when an event is posted in a thread that does not have an event handler, it will break your main thread's event handler ( just happened to my yesterday). You should see a message in the console: "QObject: startTimer - timers cannot be started from another thread" and everything stops in the main thread..

Solution - Post events from your thread in the QApplication thread (which has an event loop ), and create the FTP server, handle ftp commands ( clients, etc ... ), as responses to these events.

If you decide to use this then you will need to implement your own custom events classes.

Or, maybe someone else has a better solution that this.

Regards.
Marcel.

cxl2253
5th April 2007, 08:27
thanks,can you tell me how post event to main thread?I never thought QFP is so poor!

marcel
5th April 2007, 09:18
With QApplication::postEvent.

Take a look at the QApplication and QEvent descriptions in the Assistant.

Are you sure you need a thread for the ftp server? Since it uses a timer to schedule commands, it will probably not block your interface... Never used it, though...

wysota
5th April 2007, 12:56
You have to start the event loop of the thread by reimplementing run() and calling exec() there. Without that signals/slots won't work in the thread.

cxl2253
5th April 2007, 14:29
In fact I have reimplement the run() and call exec(),but it's still not success.I am very disppointed.Maybe anybody can give a demo ,how to call QFTP in Qthread??thanks.

wysota
5th April 2007, 15:16
Could you verify first that your slots actually get called?

marcel
5th April 2007, 15:34
Calling exec() in run() won't block everything? I mean, exec() will exit when exit() is called.
That is why I suggested the events solution. There is no need to implement an event handler in the thread.

Regards

jacek
5th April 2007, 16:43
class storescpThread:public QThread
{
Q_OBJECT
public:
storescpThread(QTextEdit *txtEdit,QObject *parent = 0);
~storescpThread();
private slots:
void connectOrDisconnect();
void ftpListInfo(const QUrlInfo &urlInfo);
void ftpCommandFinished(int commandId, bool error);
void updateDataTransferProgress(qint64 readBytes,qint64 totalBytes);
private :
QTextEdit * textEdit;
QFtp *ftp;
QFile *file;
QStringList fileList;
}
Where is storescpThread::run()? How did you manage to use storescpThread without it? Also QTextEdit shouldn't be there --- you can't use widgets in a non-GUI thread.


ftp = new QFtp(this);
Don't make "this" a parent of ftp object, as it should live the new thread, whereas "this" lives in the GUI-thread.


connect(ftp, SIGNAL(commandFinished(int, bool)), this, SLOT(ftpCommandFinished(int, bool)));
connect(ftp, SIGNAL(listInfo(const QUrlInfo &)), this, SLOT(ftpListInfo(const QUrlInfo &)));
connect(ftp, SIGNAL(dataTransferProgress(qint64, qint64)), this, SLOT(updateDataTransferProgress(qint64, qint64)));
Better add Qt::DirectConnection paremeter to each of these connect statements.

How do you start that thread? Do you make any connections between storescpThread and other objects in other parts of your application?


You should see a message in the console: "QObject: startTimer - timers cannot be started from another thread" and everything stops in the main thread..
Most likely you create objects in a wrong place. All objects that should live in a new thread should be created within QTread::run().


Calling exec() in run() won't block everything? I mean, exec() will exit when exit() is called.
That is why I suggested the events solution. There is no need to implement an event handler in the thread.
On the contrary, it will make QFtp and queued connections work.

cxl2253
6th April 2007, 11:29
thanks for your reply, i rewrite my code,but it's stiil no message.



/////////////////////////cstorescp.h//////////////
static unsigned long classAddress;
class storescpThread:public QThread
{
Q_OBJECT
public:
storescpThread(QTextEdit *txtEdit,QObject *parent = 0);
~storescpThread();
void StartStoreScp();
protected:
void run();
void connectOrDisconnect();
static void emitMsg( unsigned long user_value,char * filename)
{
storescpThread* pthis = (storescpThread*)user_value;
pthis->setText(filename);

}
private slots:
void connectOrDisconnect();
bool upLoadFile(QString checkcode,QString filename);

void ftpListInfo(const QUrlInfo &urlInfo);
void ftpCommandFinished(int commandId, bool error);
void updateDataTransferProgress(qint64 readBytes,qint64 totalBytes);


private :
QTextEdit * textEdit;
QFtp *ftp; //连接FTP
QFile *file;
QStringList fileList;

int startSCP();
void setText(T_DIMSE_StoreProgressState state,char * name);
OFCondition storeSCP();
static void storeSCPCallback();

}


/////////////////////////cstorescp.cpp//////////////
storescpThread::storescpThread(QTextEdit *txtEdit,QObject *parent): QThread(parent)
{
textEdit=txtEdit;
classAddress =(unsigned long)this ;
ftp=0;
}

int storescpThread::startSCP()
{
/////consuming operation ///////
while (!bTerminated)
{
Sleep(1); // avoid freeze!
if (!dicom_storescp_process())
break;
}
}

void storescpThread::run()
{
startSCP();
exec();
}

void storescpThread::setText(T_DIMSE_StoreProgressState state,char * name)
{
textEdit->append(name);
upLoadFile("030600030230","c:\\1.jp2");
}
void storescpThread::connectOrDisconnect()
{
if (ftp) {
ftp->abort();
ftp->deleteLater();
ftp = 0;
}
ftp = new QFtp;
connect(ftp, SIGNAL(commandFinished(int, bool)),
this, SLOT(ftpCommandFinished(int, bool)),Qt::DirectConnection );
connect(ftp, SIGNAL(listInfo(const QUrlInfo &)),
this, SLOT(ftpListInfo(const QUrlInfo &)),Qt::DirectConnection );
connect(ftp, SIGNAL(dataTransferProgress(qint64, qint64),Qt::DirectConnection ),
this, SLOT(updateDataTransferProgress(qint64, qint64)),Qt::DirectConnection );

ftp->connectToHost("192.168.1.3");
ftp->login("ftpuser","ftpuser");
ftp->cd("/pisdata"); //init dir
fileList.clear();
ftp->list();
}
bool storescpThread::upLoadFile(QString checkcode,QString filename)
{
connectOrDisconnect();
QString ftpPath="/pisdata/";
ftp->cd(ftpPath);
QFile file(filename);
if (!file.open(QIODevice::ReadOnly))
return false;
QFileInfo fi(filename);
ftp->put(&file,"111.jp2");
return true;
}
void storescpThread::ftpCommandFinished(int, bool error)
{

if (ftp->currentCommand() == QFtp::ConnectToHost) {
return;
}
return;
}

if (ftp->currentCommand() == QFtp::Get) {
}
if (ftp->currentCommand() == QFtp::List) {
QMessageBox::information(0, tr("FTP"),"LIST");
}
if (ftp->currentCommand() == QFtp::Put) {

}
}

void storescpThread::updateDataTransferProgress(qint64 readBytes,
qint64 totalBytes)
{
//progressDialog->setMaximum(totalBytes);
//progressDialog->setValue(readBytes);
}


void storescpThread::ftpListInfo(const QUrlInfo &urlInfo)
{
fileList<<urlInfo.name() ;
}

void storescpThread::storeSCPCallback()
{
//now call the static function to ftp
emitMsg(classAddress,progress->state,cbdata->imageFileName);
}
OFCondition storescpThread::storeSCP()
{
storeProvider(storeSCPCallback); ////////third party callback function
}

void storescpThread::StartStoreScp()
{
if (!isRunning()) {
start(NormalPriority);
}
}
////////////frmmain.cpp
//textEdit constructed in SetUpUI
frmMainWindow::frmMainWindow()
{
setupUi(this);
mystorescpThread=new storescpThread(textEdit);
mystorescpThread->StartStoreScp();
}

wysota
6th April 2007, 12:00
This won't work. In StartSCP you enter an endless loop and exec() doesn't have a chance to execute. What does dicom_storescp_process() do?

jacek
6th April 2007, 12:12
QFile file("c:\\testdata.jpg");
if (!file.open(QIODevice::ReadOnly)) return false;
QFileInfo fi(filename);
ftp->put(&file,"testtest.jpg"); //the file not be uploaded!!!!!
You create file on the stack and then you pass a pointer to it to a non-blocking method --- this won't work, because QFtp::put() only stores that pointer and returns... and then file gets destroyed leaving ftp with a dangling pointer.



void storescpThread::setText(T_DIMSE_StoreProgressState state,char * name)
{
textEdit->append(name);
upLoadFile("030600030230","c:\\1.jp2");
}
You can't access widgets from a non-GUI thread directly. Better define a signal and connect it via queued connection to that text edit's append() slot.

cxl2253
6th April 2007, 13:59
thanks for your help.But the emitMsg is called in static callback function.Maybe it's difficult to use SIGNAL/SLOTS. I have posted simililar problem,much people tell me that it is imposible to post signal in static function.
Anymore ,you said dangling pointer, Do you mean I should decalre the QFile file variable as private member variable of storescpThread?

jacek
6th April 2007, 15:10
But the emitMsg is called in static callback function.
setText() isn't a static method and you can emit signals from it. Touching widgets from a non-GUI thread will end with random crashes.


Do you mean I should decalre the QFile file variable as private member variable of storescpThread?
You already have one, but you don't use it.

jacek
6th April 2007, 15:24
classAddress =(unsigned long)this ;
Better use void * and reinterpret_cast, just in case you stumble upon an architeture where unsigned long has a different size than pointers.

cxl2253
7th April 2007, 02:27
thanks,jacek. I will try it . if there are any questions,can you help me again?

cxl2253
7th April 2007, 03:44
thanks ,jacek,I have emit the mssage and receive it now ,I must delete the moc file and re-moc it. Before i only re-moc it, thanks again.