Data size limit in Android socket transmission?
-
Hi!
I am developing a very basic server-client implementation using Qt. From the server side, I have a Linux server. This is the main part of the code:Server::Server() : QObject() { server = new QTcpServer(this); connect(server, SIGNAL(newConnection()), this, SLOT(sendFile())); if (!server->listen(QHostAddress::Any, 8080)) qDebug() << "Server could not start!"; else qDebug() << "Server started!"; } void Server::sendFile() { QTcpSocket *socket = server->nextPendingConnection(); QString path = "/home/data/file.bin"; QFile file(path); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); qint64 fileSize = file.size(); int length = 128; int index = 0; while (index < fileSize) { QByteArray segment = data.mid(index, length); qint64 result = socket->write(segment); if (result == -1) { qDebug() << "Error while writing data"; } else { if ((index + length) == fileSize) { break; } else { index += length; if ((index + length) > fileSize) length = fileSize - index; } } } } else { qDebug() << "Couldn't read file -> " << path; } socket->disconnectFromHost(); file.close(); }
From the (Android) client side, this is the main part of the code:
Client::Client() : QObject() { socket = new QTcpSocket; socket->setSocketOption(QAbstractSocket::LowDelayOption, 1); socket->connectToHost("192.168.1.1", 8080, QIODevice::ReadWrite); connect(socket, SIGNAL(connected()), this, SLOT(initFile())); connect(socket, SIGNAL(readyRead()), this, SLOT(readFileFromServer())); connect(socket, SIGNAL(disconnected()), this, SLOT(closeFile())); } void Client::initFile() { QString filename = "/path/to/file.bin"; file = new QFile(filename); if (!file->open(QIODevice::WriteOnly)) { #ifdef TUP_DEBUG qDebug() << "Insufficient permissions to create file -> " << file.fileName(); #endif } } void Client::readFileFromServer() { while (true) { QByteArray data = socket->read(64); if (data.isEmpty()) break; file->write(data); } } void Client::closeFile() { file->close(); qDebug() << "File saved!"; }
Initially I started running some tests between two computers using Linux. The code works like a charm and I can transmit any file through the network without any issue.
Now, when I tried the same test but running the client from my cellphone running Android, I detected an strange issue: If the file I am transmitting is larger than 14480 bytes, then, the file is limited to that size and the rest of the data is lost.
To confirm the constraint, I sent several files with different sizes and the constant value is evident for every case: 14480 bytes.Looking for an answer I started to google for that number and I found that this limitation is related to some TCP/IP parameter: https://en.wikipedia.org/wiki/Maximum_segment_size
Any way, if I want to transmit files bigger than 14460 bytes to Android devices, what should I do? Any suggestion?
Thanks!
-
Hi!
I am developing a very basic server-client implementation using Qt. From the server side, I have a Linux server. This is the main part of the code:Server::Server() : QObject() { server = new QTcpServer(this); connect(server, SIGNAL(newConnection()), this, SLOT(sendFile())); if (!server->listen(QHostAddress::Any, 8080)) qDebug() << "Server could not start!"; else qDebug() << "Server started!"; } void Server::sendFile() { QTcpSocket *socket = server->nextPendingConnection(); QString path = "/home/data/file.bin"; QFile file(path); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); qint64 fileSize = file.size(); int length = 128; int index = 0; while (index < fileSize) { QByteArray segment = data.mid(index, length); qint64 result = socket->write(segment); if (result == -1) { qDebug() << "Error while writing data"; } else { if ((index + length) == fileSize) { break; } else { index += length; if ((index + length) > fileSize) length = fileSize - index; } } } } else { qDebug() << "Couldn't read file -> " << path; } socket->disconnectFromHost(); file.close(); }
From the (Android) client side, this is the main part of the code:
Client::Client() : QObject() { socket = new QTcpSocket; socket->setSocketOption(QAbstractSocket::LowDelayOption, 1); socket->connectToHost("192.168.1.1", 8080, QIODevice::ReadWrite); connect(socket, SIGNAL(connected()), this, SLOT(initFile())); connect(socket, SIGNAL(readyRead()), this, SLOT(readFileFromServer())); connect(socket, SIGNAL(disconnected()), this, SLOT(closeFile())); } void Client::initFile() { QString filename = "/path/to/file.bin"; file = new QFile(filename); if (!file->open(QIODevice::WriteOnly)) { #ifdef TUP_DEBUG qDebug() << "Insufficient permissions to create file -> " << file.fileName(); #endif } } void Client::readFileFromServer() { while (true) { QByteArray data = socket->read(64); if (data.isEmpty()) break; file->write(data); } } void Client::closeFile() { file->close(); qDebug() << "File saved!"; }
Initially I started running some tests between two computers using Linux. The code works like a charm and I can transmit any file through the network without any issue.
Now, when I tried the same test but running the client from my cellphone running Android, I detected an strange issue: If the file I am transmitting is larger than 14480 bytes, then, the file is limited to that size and the rest of the data is lost.
To confirm the constraint, I sent several files with different sizes and the constant value is evident for every case: 14480 bytes.Looking for an answer I started to google for that number and I found that this limitation is related to some TCP/IP parameter: https://en.wikipedia.org/wiki/Maximum_segment_size
Any way, if I want to transmit files bigger than 14460 bytes to Android devices, what should I do? Any suggestion?
Thanks!
How did you connect the devices? is there a router between linux and android?
if I were you, I'd start Wireshark on the Linux machine and compare the communication to the second Linux vs. Android. Dont know if you can run a packet sniffer on Android too? that might give some more insight.
Btw: why don't you use an established protocol like ftp or http for file transfer?
-
How did you connect the devices? is there a router between linux and android?
if I were you, I'd start Wireshark on the Linux machine and compare the communication to the second Linux vs. Android. Dont know if you can run a packet sniffer on Android too? that might give some more insight.
Btw: why don't you use an established protocol like ftp or http for file transfer?
Btw: why don't you use an established protocol like ftp or http for file transfer?
You are right. I am going to take a look to Qt WebSockets to enhance my implementation.
PS: Talking to Android developers, they told me about a native class called AsyncTask, commonly used by them to do actions like download a file from a given URL.
You will find more info about it in this link:
https://developer.android.com/reference/android/os/AsyncTask.htmlThe key to deal with network requirements from Android using Qt, seems to be work with threads. I wonder if using QThread I can make a work-around for this problem.
-
Making a little experimentation, I decided to mix this example I found in the Qt documentation:
http://doc.qt.io/qt-5/qtnetwork-download-example.html
With this article about threads:
https://wiki.qt.io/QThreads_general_usage
So, basically I took an http request and I execute it from a thread. The result is really interesting, I could transmit files bigger than 14480 bytes.In most of the cases, the size of the transmitted files is the same, including the md5 hash. In other few, the downloaded file is a little bigger than the original but just for few bytes, I don't know why.
Anyway, my new approach is a lot better than the first one. Definitive solution? I think I need to run more tests ;)