Hi,

I am writing a Client and Server application (with my own protocol) to transfer huge amounts of data (like 10GB+). I need to transfer lots of files which may be small and big.
I am using Qt 4.8.5 as I have to support CentOS and RedHat.

Flushing Issues :
Everything seems to be working except that the data written to the socket is not flushing when written to the QSslSocket. So it sits in the socket buffers. I wished it flushed on its own.

I order to flush, I need to explicitly call flush() to flush the data. (I dont want to call flush explicitly though)
Calling the flush() function often, causes the memory usage to keep on increasing although the bytestowrite and "encrypted bytes to write" are below 20MB (as per my flushing loop which is commented) e.g. if the memory usage is 50 MB with 20 MB in bytestowrite and 20 MB in "encrypted bytes to write", when the flushing loop completes (to read more data) and there is no data in the bytestowrite nor in "encrypted bytes to write", the memory should have dropped to close to 10 MB (or it could reserve the memory for next usage). But after transferring something like 100MB its total memory usage might be 70 MB with nothing in the buffers. After 500 MB transfer, it goes close to 150MB of memory usage. And as soon as the socket is closed or left to read for more data, the memory drops to 10 MB again.

Transfer Rate problem :
The transfer rate is extremely slow and I get like 4-5 MBs/second from one local VM to my desktop.
If I just read like 400 MB, it takes 12-13 seconds. With transferring data over the socket, it takes a whopping 80 seconds.

One last note is that, this protocol object is created inside the main() function and hence its running on the main thread.

Now my code is as follows :

Qt Code:
  1. // protocol.h
  2. #ifndef PROTOCOL_H
  3. #define PROTOCOL_H
  4. #include <QtNetwork>
  5.  
  6. // myproto Thread class
  7. class Protocol : public QObject {
  8.  
  9. Q_OBJECT
  10.  
  11. public:
  12.  
  13. // Constructor
  14. Protocol(QObject *parent = 0);
  15.  
  16. // Destructor
  17. ~Protocol();
  18.  
  19. // The Socket pointer
  20. QSslSocket * socket;
  21.  
  22. // Variables for logging in etc
  23. QMap<QString, QString> vars;
  24.  
  25. unsigned int bblen; // The len of data in the bbuffer
  26.  
  27. int Compress; // Is the current partition to be compressed ?
  28. unsigned int written; // How many packets have been written
  29. unsigned int maxtx; // The amount of packets that can be written in one shot
  30. int socket_rw_time; // The last time there was a socket read write
  31. int sleepFor; // Will sleep for these many milliseconds
  32. int doneCalled; // Is set to 1 or greater when done is called
  33. QList<quint64> badBlocks; // Any bad blocks found
  34.  
  35. // Finish the backup process
  36. void done();
  37.  
  38. // Write the data with the length header
  39. qint64 rite (const QByteArray & data, bool keptAlive = false);
  40.  
  41. // Start the process to backup - Issues the login command
  42. bool doit();
  43.  
  44. // Send Data
  45. void sendBlocks();
  46.  
  47. signals:
  48.  
  49. void quit();
  50.  
  51. void finished();
  52.  
  53. private slots:
  54.  
  55. // When any data is available, it goes through this
  56. void socketReadyRead();
  57.  
  58. // Called when the Encryption starts over SSL Sockets
  59. void socketEncrypted();
  60.  
  61. // More slots
  62.  
  63. };
  64.  
  65. #endif
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. // protocol.cpp
  2. #include "protocol.h"
  3.  
  4. // The constructor
  5. Protocol::Protocol(QObject *parent) : QObject(parent) {
  6.  
  7. NULOG2("[Protocol::Protocol] Start");
  8.  
  9. // Codes
  10.  
  11. socket = new QSslSocket();
  12. }
  13.  
  14. // Destructor
  15. Protocol::~Protocol(){
  16.  
  17. NULOG2("[Protocol::~Protocol] Destructor");
  18.  
  19. delete socket;
  20.  
  21. }
  22.  
  23.  
  24. // Finish the backup process, even in case of error
  25. void Protocol::done(){
  26.  
  27. // Had to comment due to large post
  28.  
  29. }
  30.  
  31. // Socket write safe as it appends the length to the beginning of the string
  32. qint64 Protocol::rite(const QByteArray & data, bool keptAlive){
  33. quint16 qlen = ((quint16)data.size());
  34.  
  35. len.append(QByteArray(((char*)&qlen)+1,1));
  36. len.append(QByteArray((char*)&qlen,1));
  37.  
  38. qint64 w = socket->write(len + data);
  39. NULOG4("[Protocol::rite] Size : " << data.size() << "Written : " << w);
  40.  
  41. return w;
  42. }
  43.  
  44. // Start the whole process
  45. bool Protocol::doit(){
  46.  
  47. // Get the kernel data
  48. //this->myproto_config();
  49.  
  50. connect(socket, SIGNAL(readyRead()),
  51. this, SLOT(socketReadyRead()));
  52. connect(socket, SIGNAL(bytesWritten(qint64)),
  53. this, SLOT(socketBytesWritten(qint64)));
  54. connect(socket, SIGNAL(encryptedBytesWritten(qint64)),
  55. this, SLOT(socketencryptedBytesWritten(qint64)));
  56. connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
  57. this, SLOT(sslErrors(QList<QSslError>)));
  58. connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
  59. this, SLOT(serror(QAbstractSocket::SocketError)));
  60. /*connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
  61. this, SLOT(socketStateChanged(QAbstractSocket::SocketState)));*/
  62.  
  63. // Encrypted
  64. if(true){
  65.  
  66. NULOG1("[Protocol::doit] Connecting to Secure Server " << vars["hostname"] << "Port :" << vars["port"]);
  67.  
  68. connect(socket, SIGNAL(encrypted()),
  69. this, SLOT(socketEncrypted()));
  70.  
  71. // Connect to the server
  72. socket->connectToHostEncrypted(vars["hostname"], vars["port"].toInt());
  73.  
  74. }
  75. return true;
  76.  
  77. }
  78.  
  79. // Called when the connection is fully established
  80. void Protocol::socketEncrypted(){
  81.  
  82. NULOG1("[Protocol::socketEncrypted] Connection Established with Server");
  83.  
  84. // This is the myproto protocol
  85. socket->write("myproto\r\n");
  86. socket->waitForBytesWritten();
  87.  
  88. QByteArray username = vars["username"].toUtf8();
  89. QByteArray password = vars["password"].toUtf8();
  90.  
  91. // We first need to LOGIN
  92. this->rite("LOGIN "+ username.toBase64() +" "+ password.toBase64());
  93.  
  94. }
  95.  
  96. // Called whenever there is something to READ in the buffer
  97. void Protocol::socketReadyRead(){
  98.  
  99. QByteArray buf; // The buffer of the socket read
  100. qint64 n;
  101. QString str;
  102. int Packetlen;
  103.  
  104. while(socket->bytesAvailable() != 0){
  105.  
  106. // Find the length of the command
  107. if (dlen == 0) {
  108.  
  109. if(socket->bytesAvailable() < 2){
  110. NULOG2("[Protocol::socketReadyRead] Less than 2 packets...breaking" << socket->bytesAvailable());
  111. break;
  112. }
  113.  
  114. len = socket->read(2);
  115.  
  116. // Was there an error in reading ?
  117. if(len.size() != 2){
  118. NULOG0("[Protocol::socketReadyRead] Could not read the Length of the Packet " << len.size());
  119. return;
  120. }
  121.  
  122. dlen = (qint64)((((quint8)len[0]) << 8) | (quint8)len[1]);
  123.  
  124. // The packet cannot be greater than buffer
  125. if(dlen > 8192){
  126. NULOG0("[Protocol::socketReadyRead] The packet cannot be greater than buffer");
  127. return;
  128. }
  129.  
  130. }
  131.  
  132. // If there are not many bytes available then break
  133. if(socket->bytesAvailable() < dlen){
  134. break;
  135. }
  136.  
  137. buf = socket->read(dlen);
  138.  
  139. // Is the packet of the right size
  140. if(buf.size() != ((int)dlen)){
  141. NULOG0("[Protocol::socketReadyRead] The bytes read" << n << "dont match the packet size" << dlen);
  142. return;
  143. }
  144.  
  145. // Clear the string
  146. str = buf;
  147.  
  148. // Reset the counter
  149. Packetlen = (int)dlen;
  150. dlen = (qint64)0;
  151.  
  152. // Send data
  153. if (str[0].toLower() == QChar('gd')){
  154.  
  155. sendBlocks();
  156.  
  157. // Quit
  158. }else if (str[0].toLower() == QChar('qu')){
  159.  
  160. done();return;
  161.  
  162. // Unknown Command
  163. }else{
  164.  
  165. NULOG0("[Protocol::socketReadyRead] An Unknown Command has happened");
  166.  
  167. }
  168.  
  169. }// End of while
  170.  
  171. }
  172.  
  173. // Sends the data to the server
  174. void Protocol::sendBlocks(){
  175.  
  176. // Open File
  177. QFile fp("/path/to/large/file");
  178.  
  179. if(!fp.open(QIODevice::ReadOnly)){
  180. return false;
  181. }
  182.  
  183. qint64 read = 0;
  184.  
  185. while(fp.size() != read){
  186.  
  187. QByteArray finalData = fp.read(4096);
  188.  
  189. // Write data
  190. this->rite(finalData);
  191.  
  192. this->bblen++;
  193.  
  194. // Sleep to reduce read load
  195. if((this->bblen % 2500) == 0 && this->bblen > 0){
  196.  
  197. NULOG2("[Protocol::sendBlocks] Bytes " << this->socket->encryptedBytesToWrite() << this->socket->bytesToWrite());
  198.  
  199. /*// The following CODE is used to flush data as for some reason the data is not flushed automatically
  200. if((this->bblen % 25000) == 0){
  201.  
  202. while(this->socket->encryptedBytesToWrite() > 10000000 || this->socket->bytesToWrite() > 10000000){
  203. this->socket->flush();
  204. }
  205.  
  206. }*/
  207.  
  208. }
  209.  
  210. }
  211.  
  212. // Wait for more socket read !
  213.  
  214. return true;
  215.  
  216. }
To copy to clipboard, switch view to plain text mode 

Qt Code:
  1. // Code to execute protocol in main.cpp
  2. int main(){
  3. Protocol protObj;
  4. protObj.doit();
  5. }
To copy to clipboard, switch view to plain text mode