为什么文件上传在发送几个数据块(使用多部分/表单数据)后停止?

Why does file upload stop after sending a couple of chunks of data (using multipart/form-data)?

本文关键字:数据 多部 表单 几个 文件 为什么      更新时间:2023-10-16

我正在使用libcurl将固件文件上传到硬件设备。 我正在使用多部分/表单数据,看起来文件上传开始正常,但它没有加载整个文件。
我上传的文件是 144,855,725 字节,但似乎只发送了两个 64k 块。

在发布的代码中,我正在使用读取回调函数。 我也尝试将文件名传递给curl_mime_filedata函数,结果是一样的。
一个有趣的说明是,当我运行程序时,我会在大约一半的时间内得到curl_easy_perform的成功响应。 另一半时间我会得到错误 56"从对等方接收数据时失败"。 另一个有趣的说明是,文件大小(144,855,725)和curl认为下载大小的大小(144,856,042)略有差异。 我认为这是因为它考虑了正文中的所有字节(而不仅仅是文件)。 这是对的吗?

这是我运行程序时的一些(精简)输出。文件大小: 144855725 总时间: 0.000092 向上: 0 的 0 向下: 0 的 0 向上: 0 的 144856042 向下: 0 的 0 读取回调: 大小=1, nmemb=65267 我们从文件中读取 65267 字节 向上: 65536 的




144856042 向下: 0

的 0
读回调: 大小=1, nmemb=65536
我们从文件中读取 65536 字节
向上: 144856042 131072 下降: 0 的 0
卷曲结果 错误 = <56:从对等方接收数据时失败>
无法上传固件文件

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);
}

我希望上传整个文件,而不仅仅是文件的几个块。

您没有正确填充curl_mime结构。您显示的代码与您在上一个问题中描述的 MIME 格式不匹配:

--
1a2fc07a-d882-4470-a1da-79716d34cd9b 内容处置:表单数据;名称="upgrade_file";文件名=" 内容类型:应用程序/八位字节流 文件数据在这里//--1a2fc07a-d882-4470-a1da-79716d34cd9b 内容处置:表单数据;名称="提交" 安装操作系统 --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;
}