C++ libcurl 如何使用 SORT 和 REST 发送 FTP 文件

C++ libcurl how to send FTP file usign STOR and REST

我有一个 XML,我想将其增量上传到 ftp 服务器。

问题是它不适用于我的 APPEND,因为我必须删除最后的标签。例如。

服务器上的文件

   < xml>< root>< a>ssss< /a>< b>kkkkk< /b>< /root>

本地文件

   < xml>< root>< a>ssss< /a>< b>kkkkk< /b>< c>hhhhh< /c>< /root>

我需要从< /root>之前上传。

   < xml>< root>< a>ssss< /a>< b>kkkkk< /b>< /root>

   ----------------------------------------^

我的代码如下

    size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) {
        curl_off_t nread;
        size_t retcode = fread(ptr, size, nmemb, (FILE*) stream);

        nread = (curl_off_t) retcode;

        fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T " bytes from file\n", nread);
        return retcode;
    }

    bool uploadFile(std::string urlFtp, std::string rutaFtp, std::string archivoOrigen, std::string userPassword, long posicion) {
        bool resultado = false;
        try {
            CURL *curl;
            CURLcode res;
            FILE *hd_src;
            struct stat file_info;
            curl_off_t fsize;

            /* get the file size of the local file */
            if (stat(archivoOrigen.c_str(), &file_info)) {
                LOGF_ERROR("Couldn't open '%s': %s\n", archivoOrigen.c_str(), strerror(errno));
                return false;
            }
            fsize = (curl_off_t) file_info.st_size;

            LOGF_INFO("Local file size: %" CURL_FORMAT_CURL_OFF_T " bytes.\n", fsize);

            hd_src = fopen(archivoOrigen.c_str(), "rb"); // get a FILE * of the same file

            curl_global_init(CURL_GLOBAL_ALL); // In windows, this will init the winsock stuff

            curl = curl_easy_init(); // get a curl handle
            if (curl) {
                // build a list of commands to pass to libcurl
                struct curl_slist *headerlist = NULL;
                std::string cadena(rutaFtp);

                curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback); // we want to use our own read function
                curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // enable uploading
                cadena = urlFtp;
                cadena.append(rutaFtp);
                curl_easy_setopt(curl, CURLOPT_URL, cadena.c_str()); // specify target
                curl_easy_setopt(curl, CURLOPT_USERPWD, userPassword.c_str());
                if (posicion > 0) {
                    curl_easy_setopt(curl, CURLOPT_RESUME_FROM, posicion);
                }
                curl_easy_setopt(curl, CURLOPT_READDATA, hd_src); // now specify which file to upload
                curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t) fsize);
                curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L);

                curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 

                res = curl_easy_perform(curl); // Now run off and do what you've been told!
                if (res != CURLE_OK)
                    LOGF_ERROR("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
                else
                    resultado = true;

                curl_slist_free_all(headerlist); // clean up the FTP commands list

                curl_easy_cleanup(curl);
            }
            fclose(hd_src); // close the local file

            curl_global_cleanup();
        } catch (std::exception &e) {
            LOGF_ERROR(e.what());
        }

        return resultado;
    }

我一直无法解决 CURL 的问题。为了解决这个问题,我在 C++ 中创建了一个 class 来进行上传。我注意到 RFC rfc3659 第 13 页的文档。

5.5.  REST Example

Assume that the transfer of a largish file has previously been
interrupted after 802816 octets had been received, that the previous
transfer was with TYPE=I, and that it has been verified that the file
on the server has not since changed.

  C> TYPE I
  S> 200 Type set to I.
  C> PORT 127,0,0,1,15,107
  S> 200 PORT command successful.
  C> REST 802816
  S> 350 Restarting at 802816. Send STORE or RETRIEVE
  C> RETR cap60.pl198.tar
  S> 150 Opening BINARY mode data connection
  [...]
  S> 226 Transfer complete.

我没有放 RETR,而是放了一个 STOR,它工作正常。