PDA

View Full Version : problem in transfer file with tcpip part 2



wei243
8th March 2007, 07:29
special thx to wysota, help me solve most of my problem.
now i manage to send any file form QTcpSocket to QTcpServer within 1 standalone pc.

but if i transfer a file within a network, the receiver only receive PARTIALLY, except the file size is very small.
how to slove this problem?

below is my sender program with QTcpSocket:


void sender::sending()
{
tcpSocket1 = new QTcpSocket(this);
tcpSocket1->abort();

tcpSocket1->connectToHost(targetIP,targetPort);

file.setFileName(fileName);
file.open(QIODevice::ReadOnly);

QByteArray Data;
Data = file.readAll();

tcpSocket1->write(Data);

connect(tcpSocket1, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
connect(tcpSocket1, SIGNAL(disconnected()),tcpSocket1, SLOT(deleteLater()));
connect(tcpSocket1, SIGNAL(disconnected()),this, SLOT(closeFile()));
}
void sender::closeFile()
{
file.close();
}


receiver program with QTcpServer:


void receiver::startserver()
{
tcpServer1 = new QTcpServer(this);
if (!tcpServer1->listen(QHostAddress(ownIP),0)){
QMessageBox::critical(0, tr("Listening...."),tr("Unable to start the server: ").arg(tcpServer1->errorString()));
}

timer = new QTimer(this);
connect(tcpServer1, SIGNAL(newConnection()), this, SLOT(startTimer()));
connect(timer, SIGNAL(timeout()), this, SLOT(readIncoming()));
}
void receiver::startTimer()
{
timer->start(500);
}
void receiver::readIncoming()
{
timer->stop();

QTcpSocket *clientConnection = tcpServer1->nextPendingConnection();
QApplication::setOverrideCursor(Qt::WaitCursor);

QByteArray Data = clientConnection->readAll();

file.setFileName(fileName);
file.open(QIODevice::WriteOnly);
file.write(Data);

connect(clientConnection, SIGNAL(disconnected()),clientConnection, SLOT(deleteLater()));
connect(clientConnection, SIGNAL(disconnected()),this, SLOT(closeFile()));

clientConnection->disconnectFromHost();

QApplication::restoreOverrideCursor();
}
void receiver::closeFile()
{
file.close();
}

guilugi
8th March 2007, 09:31
Well, it seems that timeout() signal is triggered too early, and if you transfer large files, they won't be send in 500ms through the network ! :)

What you could do, is connect your server to readyRead() signal, and just send a special ending message with your sender socket, to notify server that file is transferred.

wysota
8th March 2007, 11:50
but if i transfer a file within a network, the receiver only receive PARTIALLY, except the file size is very small.
how to slove this problem?

I already told you - Qt handles network in an asynchronous way:
1. when connectToHost() returns, you are not connected to the remote host
2. when write() returns, the data is not written to the socket
3. Qt will emit signals when events happen and you can connect to those signals to handle events such as new connection, data is ready to read, data has been written, disconnected from host - no need to use any timers.

wei243
9th March 2007, 08:09
i have try all the methods provided, but cannot function properly.
the problem i hv face:
1. the clientConnection->disconnect() signal wont emit unless i run the clientConnection->disconnectFromHost(). bcoz i dont know when the clientConnection has finished reading data from sender. so i cant get the correct timming to run clientConnection->disconnectFromHost().

2. the tcpserver->newConnection() signal will emit again even the last connection data is being reading.

3. i try readyRead(), but it wont emit at all.....

how to know when the clientConnection(in server) is finished reading the data from sender?give me some example pls.

maybe i m stupid.....

wysota
9th March 2007, 10:11
A quick, dirty and untested implementation:

class FileSender : public QTcpSocket {
Q_OBJECT
public:
FileSender(QObject *parent) : QTcpSocket(parent){
_ready = false;
connect(this, SIGNAL(connected()), SLOT(onConnected()));
connect(this, SIGNAL(disconnected()), SLOT(onDisconnected()));
connect(this, SIGNAL(bytesWritten(qint64)), SLOT(onWritten(qint64)));
}
bool sendFile(QIODevice *file){
if(!_ready) return false;
_ready = false;
device = file;
sendChunk();
}
signals:
void fileTransfered();
void ready();
private slots:
void onConnected(){
_ready = true;
emit ready();
}
void onWritten(qint64 s){
if(device->atEnd()){
// file sent
_ready = true;
emit fileTransfered();
emit ready();
} else sendChunk();
}
void onDisconnected(){
_ready = false;
}
private:
QIODevice *device;
bool _ready;
void sendChunk(){
QByteArray ba = device->read(64000); // about 64kB
qint64 writ = write(ba); // write data to socket
if(writ<ba.size()){ // not all written
for(int i=writ;i<ba.size(); i++) device->ungetChar(ba[i]); // write back to the file buffer
}
}
};


FileSender *fs = new FileSender(this);
connect(fs, SIGNAL(ready()), this, SLOT(send()));
connect(fs, SIGNAL(fileTransfered()), this, SLOT(finish()));
fs->connectToHost("...", 3456);

//...
// slot send():
QFile *file = new QFile("...");
file->open(QFile::ReadOnly);
disconnect(fs, SIGNAL(ready()), this, SLOT(send()));
fs->sendFile(file);
//...
// slot finish():
file->close();
delete file;
connect(fs, SIGNAL(disconnected()), fs, SLOT(deleteLater())); // so that fs deletes itself
fs->disconnectFromHost();