本文介绍了为什么发送几个数据块(使用multipart/form-data)后文件上传停止?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用libcurl将固件文件上传到硬件设备.我正在使用multipart/form-data,看起来文件上传开始正常,但不会加载整个文件.
我上传的文件为144,855,725字节,但似乎只发送了两个64k块.

I'm using libcurl to upload a firmware file to a hardware device. I'm using multipart/form-data and it looks like the file upload starts okay but it doesn't load the entire file.
The file I'm uploading is 144,855,725 bytes but it appears that only two 64k chunks are being sent.

在发布的代码中,我正在使用读取回调函数.我还尝试过仅将文件名传递给curl_mime_filedata函数,结果是相同的.
一个有趣的注意事项是,当我运行该程序时,大约有一半的时间将从curl_easy_perform获得成功的响应.另一半时间,我将收到错误消息56从对等方接收数据时失败".另一个有趣的注意事项是文件大小(144,855,725)和curl认为下载大小(144,856,042)略有差异.我认为这是因为它要考虑主体中的所有字节(而不仅仅是文件).正确吗?

In the posted code I am using a read callback function. I had also tried just passing the file name to the curl_mime_filedata function and the results were the same.
One interesting note is that when I run the program I'll get a successful response from the curl_easy_perform about half of the time. The other half of the time I'll get error 56 "Failure when receiving data from the peer".Another interesting note is that there is a slight discrepancy in the size of the file (144,855,725) and the size that curl perceives as the download size (144,856,042). I assume this is because it is accounting for all of the bytes in the body (not just the file). Is that correct?

这是我运行程序时的一些输出(缩减).
档案大小:144855725
总时间:0.000092
上:0之0下:0:0之0
上:144856042中的0下:0的0中
ReadCallback:大小= 1,Nmemb = 65267
我们从文件中读取了65267个字节
上:655856 of 144856042下:0 of 0
ReadCallback:大小= 1,Nmemb = 65536
我们从文件中读取65536个字节
向上:144856042中的131072向下:0中的0
curl结果ERROR =< 56:从对等方接收数据时失败>
无法上传固件文件

Here is some (pared down) output from when I run the program.
File size: 144855725
TOTAL TIME: 0.000092
UP: 0 of 0 DOWN: 0 of 0
UP: 0 of 144856042 DOWN: 0 of 0
ReadCallback: Size=1, Nmemb=65267
We read 65267 bytes from the file
UP: 65536 of 144856042 DOWN: 0 of 0
ReadCallback: Size=1, Nmemb=65536
We read 65536 bytes from the file
UP: 131072 of 144856042 DOWN: 0 of 0
curl result ERROR = <56: Failure when receiving data from the peer>
Failed to upload firmware file

size_t ReadCallback(char *BufferOut, size_t Size, size_t Nmemb, void *StreamIn)
{
   curl_off_t nread;
   size_t retcode = fread(BufferOut, Size, Nmemb, (FILE *)StreamIn);
   nread = (curl_off_t)retcode;
   cout << "ReadCallback: Size=" << Size << ", Nmemb=" << Nmemb << endl;
   cout << "We read " << nread << " bytes from the file" << endl;
   return retcode;
}
int main(void)
{
   CURL *pCurl;
   CURLcode res;
   std::stringstream ss;
   struct curl_slist *headerList = NULL;
   string accessToken;
   struct TransferProgress transProgress;
   string filePath;
   FILE * pFile;
   long lSize;

   curl_global_init(CURL_GLOBAL_ALL);
   pCurl = curl_easy_init();

   if (pCurl)
   {
      EC520UutComms comms;
      curl_mime *multipart;
      curl_mimepart *part;

      accessToken = comms.GetAccessToken(pCurl);
      SetOptionsToDefault(pCurl);

      // Specify the target URL
      std::string str(comms.BaseURL() + kAPI_Upgrade);
      cout << "URL <" + str + ">" << endl;
      curl_easy_setopt(pCurl, CURLOPT_URL, str.c_str());

      multipart = curl_mime_init(pCurl);
      // Add the Content-Disposition
      part = curl_mime_addpart(multipart);
      curl_mime_name(part, "Content-Disposition");
      curl_mime_data(part, "form-data; name=\"upgrade_file\"; filename=\"\"", CURL_ZERO_TERMINATED);
      // Add the file
      part = curl_mime_addpart(multipart);
      curl_mime_type(part, "application/octet-stream");

      filePath = "C:\\Temp\\TestFile.tst";
//       curl_mime_filedata(part, filePath.c_str());
       fopen_s(&pFile, filePath.c_str(), "rb");
      // obtain file size:
      fseek(pFile, 0, SEEK_END);
      lSize = ftell(pFile);
      rewind(pFile);
      cout << "File size: " << lSize << endl;

      curl_mime_data_cb(part, lSize, ReadCallback, NULL, NULL, pFile);

      curl_easy_setopt(pCurl, CURLOPT_MIMEPOST, multipart);
      // This is a long upload, disable the timeout
      curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 0L);

      // Create headers
      ss.str("");
      ss << "Authorization: Bearer " << accessToken;
      headerList = curl_slist_append(headerList, ss.str().c_str());
      // Accept
      headerList = curl_slist_append(headerList,
         "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

      curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, headerList);

      curl_easy_setopt(pCurl, CURLOPT_XFERINFOFUNCTION, TransferInfo);
      transProgress.curl = pCurl;
      curl_easy_setopt(pCurl, CURLOPT_XFERINFODATA, &transProgress);
      curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L);

      // Now send the message
      res = curl_easy_perform(pCurl);

      curl_slist_free_all(headerList);
      curl_mime_free(multipart);

      if (res == CURLE_OK)
      {
         cout << "Firmware file successfully uploaded" << endl;
      }
      else
      {
         cout << "curl result ERROR = <" + to_string(res) + ": " + curl_easy_strerror(res) + ">" << endl;
         cout << "Failed to upload firmware file" << endl;
      }
   }
   curl_easy_cleanup(pCurl);
}

我希望整个文件都可以上传,而不仅仅是文件的几个块.

I expect the entire file to be uploaded rather than just a couple of chunks of the file.

推荐答案

您没有正确填充curl_mime结构.您显示的代码与上一个问题

You are not populating the curl_mime structure correctly. The code you have shown does not match the MIME format you described in your previous question:


--1a2fc07a-d882-4470-a1da-79716d34cd9b
Content-Disposition: form-data; name="upgrade_file"; filename=""
Content-Type: application/octet-stream

// File data goes here //
--1a2fc07a-d882-4470-a1da-79716d34cd9b
Content-Disposition: form-data; name="submit"

Install OS
--1a2fc07a-d882-4470-a1da-79716d34cd9b--

尝试以下方法:

size_t ReadCallback(char *buffer, size_t size, size_t nitems, void *arg)
{
    cout << "ReadCallback: size=" << size << ", nitems=" << nitems << endl;
    size_t retcode = fread(buffer, size, nitems, (FILE *)arg);
    cout << "We read " << retcode << " bytes from the file" << endl;
    return retcode;
}

int SeekCallback(void *arg, curl_off_t offset, int origin)
{
    if (fseek((FILE *)arg, offset, origin) == 0)
        return CURL_SEEKFUNC_OK;
    else
        return CURL_SEEKFUNC_FAIL;
}

int main()
{
    CURL *pCurl;
    CURLcode res;
    struct curl_slist *headerList = NULL;
    string accessToken;
    struct TransferProgress transProgress;
    string filePath;
    FILE * pFile;
    long lSize;

    curl_global_init(CURL_GLOBAL_ALL);
    pCurl = curl_easy_init();
    if (pCurl)
    {
        EC520UutComms comms;
        curl_mime *multipart;
        curl_mimepart *part;

        accessToken = comms.GetAccessToken(pCurl);
        SetOptionsToDefault(pCurl);

        // Specify the target URL
        std::string str(comms.BaseURL() + kAPI_Upgrade);
        cout << "URL <" + str + ">" << endl;
        curl_easy_setopt(pCurl, CURLOPT_URL, str.c_str());

        multipart = curl_mime_init(pCurl);

        part = curl_mime_addpart(multipart);
        curl_mime_name(part, "upgrade_file");
        curl_mime_filename(part, "");
        curl_mime_type(part, "application/octet-stream");
        filePath = "C:\\Temp\\TestFile.tst";
        // curl_mime_filedata(part, filePath.c_str());
        fopen_s(&pFile, filePath.c_str(), "rb");
        // obtain file size:
        fseek(pFile, 0, SEEK_END);
        lSize = ftell(pFile);
        rewind(pFile);
        cout << "File size: " << lSize << endl;
        curl_mime_data_cb(part, lSize, ReadCallback, SeekCallback, NULL, pFile);

        part = curl_mime_addpart(multipart);
        curl_mime_name(part, "submit");
        curl_mime_data(part, "Install OS", CURL_ZERO_TERMINATED);

        curl_easy_setopt(pCurl, CURLOPT_MIMEPOST, multipart);

        // This is a long upload, disable the timeout
        curl_easy_setopt(pCurl, CURLOPT_TIMEOUT, 0L);

        // Create headers
        headerList = curl_slist_append(headerList, ("Authorization: Bearer " + accessToken).c_str());
        headerList = curl_slist_append(headerList, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");

        curl_easy_setopt(pCurl, CURLOPT_HTTPHEADER, headerList);

        curl_easy_setopt(pCurl, CURLOPT_XFERINFOFUNCTION, TransferInfo);

        transProgress.curl = pCurl;
        curl_easy_setopt(pCurl, CURLOPT_XFERINFODATA, &transProgress);

        curl_easy_setopt(pCurl, CURLOPT_NOPROGRESS, 0L);

        // Now send the message
        res = curl_easy_perform(pCurl);

        fclose(pFile);
        curl_slist_free_all(headerList);
        curl_mime_free(multipart);

        if (res == CURLE_OK)
        {
            cout << "Firmware file successfully uploaded" << endl;
        }
        else
        {
            cout << "curl result ERROR = <" + to_string(res) + ": " + curl_easy_strerror(res) + ">" << endl;
            cout << "Failed to upload firmware file" << endl;
        }

        curl_easy_cleanup(pCurl);
    }

    return 0;
}

这篇关于为什么发送几个数据块(使用multipart/form-data)后文件上传停止?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-01 18:54