Implement FTP resumable upload

Source: Internet
Author: User
Tags ftp file
 

Application requirements:

Network Disk development gradually enters the integration phase of each part. When a user modifies a file on the client or adds a new file, the file must be uploaded to the user directory corresponding to the server, therefore, three transmission modes are established for data transmission (namely, upload and download), namely FTP transmission, HTTP transmission, and UDT-based transmission. The three data transmission modes are configurable and can be called through different interfaces. Compared with these three methods, the UDT-based massive file transmission is worth researching and innovating. It is based on UDP at the underlying layer and achieves reliability control at the upper layer; at the same time, it fully considers the shortcomings of the congestion control algorithm for Transmission Based on TCP in the public network environment, and implements its own congestion control algorithm, in actual tests, the performance is also significantly higher than that of TCP-based transmission. We have only conducted technical research on the implementation of UDT file transmission and have not yet implemented it. This part of content will be mentioned in subsequent articles. In the past three days, only FTP-based files that support resumable upload and download are supported.

Implementation principle:

The application example of resumable data transfer closest to us is: thunder. When using thunder to download a large file, it implements the following functions: 1> after the computer suddenly loses power or the program suddenly exits, when we restart thunder, it will continue downloading the downloaded file from the point where the program exits, instead of downloading the file from the beginning. 2> you can set multiple threads to download files at the same time. Each thread only downloads a part of the file. For example, you can use three threads to download a 9000-byte file, the first thread downloads 1-3000 bytes, the second thread downloads 1-6000 bytes, and the third thread downloads 1-9000 bytes. The three threads download an object at the same time, but download different parts. It stores the downloaded file fragments at a certain location, when all three threads are downloaded, they are combined into a complete file. It is worth noting that its advantages are obvious.

In fact, the principle of resumable upload is very simple, that is, you can record the number of bytes that have been uploaded or downloaded in real time during upload or download. If the transmission is disconnected for some reason, when the download starts, you only need to re-download or upload from the downloaded location.

Resumable Data Transfer Using qftp:

In QT, there is an FTP implementation class: qftp, which provides the basic ftp usage, connecting to the FTP server: connecttohost; login: Login; upload: Put; download: get, using these methods, you can interact with the FTP server to upload and download files. However, the put and get methods provided by the native method cannot implement resumable data transfer. Therefore, to achieve resumable upload, we need to re-implement File Transfer and add the breakpoint resume control. In fact, the essence of FTP file transmission is to use TCP to achieve underlying file transmission. The general idea is: Use the connecttohost of qftp to log on to the FTP server, use login to log on to the FTP server, use rawcommand to send the original FTP command, and use qtcpsocket to transmit file data.

First, to use qtcpsocket for file data transmission, you must set the FTP server to "PASV" for passive receiving, that is, the FTP server passively receives connection requests from clients.

All native commands that can be sent by the FTP server include: http://www.nsftools.com/tips/rawftp.htm.

The command sending process for breakpoint upload is as follows:

1. rawcommand ("type I"); set the data transmission type: binary data or ASCII

2. rawcommand ("PASV"); set the server to a passive receiving mode. After the PASV command is sent, the server returns its own data transmission port, waiting for the client to connect for data transmission. The returned data is in the format of "227 entering passive mode (192,168, 2, 18,118, 32)", and then the related information is included in the returned information. IP address of the FTP server: 192.168.2.18; port opened by the FTP server for data transmission: 118*256 + 32 = 30240. After obtaining this information, you need to establish a tcpsocket communication link to connect to the FTP server.

3. rawcommand ("appe remote-file-path"); Set remote-file-path on the server to append. If the file does not exist, the server creates one.

4. After completing the above process, you can open the local file for reading and send it through the tcpsocket Link (write ).

The command sending process for breakpoint download is as follows:

1. rawcommand ("type I"); set the data transmission type: binary data or ASCII

2. rawcommand ("PASV"); set the server to a passive receiving mode. After the PASV command is sent, the server returns its own data transmission port, waiting for the client to connect for data transmission. The returned data is in the format of "227 entering passive mode (192,168, 2, 18,118, 32)", and then the related information is included in the returned information. IP address of the FTP server: 192.168.2.18; port opened by the FTP server for data transmission: 118*256 + 32 = 30240. After obtaining this information, you need to establish a tcpsocket communication link to connect to the FTP server.

3. rawcommand ("Rest size"); this command sets the place where the FTP server starts data transmission from the local file.

4. rawcommand ("RETR remote-file-path"); transfers files from the remote host.

When a file is uploaded, you can open the local file for upload after setting the appe response. When downloading the file, you need to establish a connection to the tcpsocket after receiving the PASV response information. readyread () to read data.

Key code:

1. process the slot function after rawcommand () sends the native command return:

 

[CPP]View plaincopy
  1. Void lhtfiletransfer: procrawcommandreply (INT nreplycode, qstring strdetail)
  2. {
  3. //! Type
  4. If (200 = nreplycode)
  5. {
  6. M_ftphandle-> rawcommand ("PASV ");
  7. If (currentitem. task_type.compare ("Upload") = 0)
  8. {
  9. OP = qstring ("put ");
  10. }
  11. Else if (currentitem. task_type.compare ("Download") = 0)
  12. {
  13. OP = qstring ("get ");
  14. }
  15. }
  16. //! PASV
  17. Else if (227 = nreplycode)
  18. {
  19. Const qstring backresult = strdetail;
  20. If (null! = M_senddatasocket)
  21. {
  22. M_senddatasocket-> close ();
  23. Delete m_senddatasocket;
  24. }
  25. M_senddatasocket = new qtcpsocket ();
  26. Connect (m_senddatasocket, signal (readyread (), this, slot (procreadyread (), QT: uniqueconnection );
  27. Connect (m_senddatasocket, signal (readchannelfinished (), this, slot (procreadchannelfinished (), QT: uniqueconnection );
  28. Connect (m_senddatasocket, signal (byteswritten (qint64), this, slot (procbyteswritten (qint64), QT: uniqueconnection );
  29. Qstringlist lstr = backresult. Split ("("). Last (). Split (")"). First (). Split (",");
  30. Int naddress = lstr. At (0). toint () <24 |
  31. Lstr. at (1). toint () <16 |
  32. Lstr. At (2). toint () <8 |
  33. Lstr. At (3). toint ();
  34. Qhostaddress hostaddress (naddress );
  35. Int nport = lstr. At (lstr. Length ()-2). toint () * 256 + lstr. Last (). toint ();
  36. M_senddatasocket-> connecttohost (hostaddress, nport );
  37. //! APPE, the absolute path of the remote file to be connected
  38. Qstring appeshell;
  39. If (op. Compare ("put") = 0)
  40. {
  41. Appeshell = qstring ("appe % 1"). Arg (currentitem. file_remote_path );
  42. }
  43. Else if (op. Compare ("get") = 0)
  44. {
  45. //! The size after rest here should be the size of the local saved price.
  46. Appeshell = qstring ("Rest 0 ");
  47. }
  48. M_ftphandle-> rawcommand (appeshell );
  49. }
  50. //! Send data
  51. Else if (150 = nreplycode)
  52. {
  53. If (op. Compare ("put") = 0)
  54. {
  55. M_filehandle = new qfile (currentitemfilepath );
  56. If (! M_filehandle-> open (qiodevice: readonly ))
  57. {
  58. Qdebug () <"file open error ...";
  59. Return;
  60. }
  61. Const qint64 filesize = m_filehandle-> size ();
  62. M_filehandle-> seek (currentitem. uploaded_size );
  63. While (! M_filehandle-> atend ())
  64. {
  65. Const qint64 nblocksize = 16*1024;
  66. Char Buf [16*1024];
  67. Qint64 nowpos = m_filehandle-> pos ();
  68. Qint64 readlen = m_filehandle-> Read (BUF, nblocksize );
  69. If (readlen! = 0 & readlen! =-1)
  70. {
  71. M_senddatasocket-> write (BUF, readlen );
  72. M_senddatasocket-> flush ();
  73. Emit datatransferprogress (nowpos, filesize );
  74. }
  75. }
  76. M_senddatasocket-> flush ();
  77. M_senddatasocket-> close ();
  78. M_senddatasocket = NULL;
  79. Emit datatransferprogress (m_filehandle-> pos (), m_filehandle-> size ());
  80. M_proctask.remove (currentitemfilepath );
  81. M_filehandle-> close ();
  82. // Emit startnexttask ();
  83. }
  84. Else if (op. Compare ("get") = 0)
  85. {
  86. M_filehandle = new qfile (currentitem. file_remote_path );
  87. If (! M_filehandle-> open (qiodevice: writeonly ))
  88. {
  89. Qdebug () <"file open error ...";
  90. Return;
  91. }
  92. }
  93. }
  94. Else if (350 = nreplycode)
  95. {
  96. Qstring shell = qstring ("retr % 1"). Arg (currentitemfilepath );
  97. M_ftphandle-> rawcommand (Shell );
  98. }
  99. }
2. Implement the buffer READ function during breakpoint download:

 

 

[CPP]View plaincopy
  1. Void lhtfiletransfer: procreadyread ()
  2. {
  3. Qdebug () <"[Download] procreadyready ....";
  4. Qbytearray buffer = m_senddatasocket-> readall ();
  5. M_filehandle-> write (buffer );
  6. M_filehandle-> flush ();
  7. Emit datatransferprogress (m_filehandle-> size (), 0 );
  8. }
Problems and problems to be optimized in the future:

 

1. character encoding problem, that is, when the file name to be uploaded is a Chinese name, it needs to be transcoded.

2. The current implementation is a single thread, and multi-thread breakpoint download and queue implementation have not yet been added.

Implement FTP resumable upload

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.