Reputation: 2367
I doing TCP file client-server inside single application.
Primarily, I send filename and file's peaces per 50000 bytes.
Client:
void client::sendFile(QString path)
{
QDataStream out(cl);
QFile toSend(path);
if (toSend.open(QIODevice::ReadOnly))
{
int s = 0;
QFileInfo fileInfo(toSend.fileName());
QString fileName(fileInfo.fileName());
out << fileName;
while (!toSend.atEnd())
{
QByteArray rawFile;
rawFile = toSend.read(50000);
out << rawFile;
qDebug() << "ToSend"<<rawFile.size();
s+=rawFile.size();
}
qDebug() << "Total:" << s;
}
}
... this is correct i guess
Server (ReadyRead slot):
void server::receive()
{
QTcpSocket *sender = (QTcpSocket*) this->sender();
QDataStream in(sender);
QString fName;
in >> fName;
QFile newFile("D:\\"+fName);
if (newFile.open(QIODevice::WriteOnly))
{
while(sender->bytesAvailable())
{
QByteArray z;
in >> z;
newFile.write(z);
qDebug () << "Received " << z.size();
}
newFile.close();
}
}
... and here's problem: while
broken after first itteration.
Look:
ToSend 50000
ToSend 50000
ToSend 50000
ToSend 31135
Total: 181135
Received 50000
As you see, only 1 block received instead of 4.
How to fix this? Why bytesAvailable
returns 0 when it's shouldn't?
Would be fine to know is this nice approach to receive files over tcp or not as well :)
Upvotes: 2
Views: 6011
Reputation: 27611
The problem is your loop which waits on bytesAvailable().
The readyRead slot is designed to handle this. When your slot is called, read the number of bytes that are available and process them. You should then return from the function.
When more data is available, you will get called again in the readyRead slot function.
Of-course, this means that you will need to buffer the data between successive calls and it is advised to start the process by sending a header of how many bytes the server is to expect for the whole file. Once the server has accumulated that number of bytes, it can then write out to the new file.
Upvotes: 1
Reputation: 35338
You have to "invent" a protocol that allows the receiver to know how much data will be transferred. bytesAvailable
only shows you the number of bytes which were received until now and which can be read from the stream, but it doesn't know how much data the sender will still transfer in the future.
See here for a very simple example of how to do that.
Upvotes: 2
Reputation: 4029
Probably because there is just this one packet available. You will need to Set up a negotiation about the file size before sending data. Then just wait for all data to be transmitted. BytesAvailable() returns false as soon as the first 50k data have been processed. If you call bytesAvailable() again waiting 1 second in between, you will get another packet probably.
Implement a 4 Byte "Size Packet" before sending data and check for those bytes being received.
So your protocoll will be:
Another option would be to have an predefined end-packet, but this can be dangerous if your file can contain this packet in raw data. If you can ensure your data does not contain your end-packet you eventually will implement the protocol as:
Upvotes: 5