将文件发送到 HTTP 服务器(C++ Wininet)

Posted

技术标签:

【中文标题】将文件发送到 HTTP 服务器(C++ Wininet)【英文标题】:Sending file to HTTP server (C++ Wininet) 【发布时间】:2017-06-21 10:43:06 【问题描述】:

我有用于在我的 HTTP 服务器上上传小型 .txt 文件的代码:

#include <wininet.h>
#define BUF_SIZE 4096

void __fastcall TForm1::Button1Click(TObject *Sender)


 TStringList * list = new TStringList();
 AnsiString Path = "";

 if(OpenDialog1->Execute()) 

    Path =  "filename=\""+OpenDialog1->FileName+"\"";
    list->LoadFromFile(OpenDialog1->FileName);

 

 char data[BUF_SIZE] = "";
 static char hdrs[] = "Content-Type: multipart/form-data; boundary=---------------------------7d82751e2bc0858";

 strcat(data,"-----------------------------7d82751e2bc0858");
 strcat(data,"\n");
 strcat(data,"Content-Disposition: form-data; name=\"files[]\"; ");
 strcat(data,Path.c_str());
 strcat(data,"\n");
 strcat(data,"Content-Type: application/octet-stream");
 strcat(data,"\n\n");
 strcat(data,list->Text.c_str());
 strcat(data,"\n");
 strcat(data,"-----------------------------7d82751e2bc0858");
 strcat(data,"\n");
 strcat(data,"Content-Disposition: form-data; name=\"user\"");
 strcat(data,"\r\n\r\n");
 strcat(data,"username");
 strcat(data,"\r\n");
 strcat(data,"-----------------------------7d82751e2bc0858");
 strcat(data,"\n");

 HINTERNET hSession = InternetOpen("MyAgent",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
 HINTERNET hConnect = InternetConnect(hSession, "localhost",INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
 HINTERNET hRequest = HttpOpenRequest(hConnect, "POST", "new_upltest.php", NULL, NULL, NULL, 0, 1);

 HttpSendRequest(hRequest, hdrs, strlen(hdrs), data, strlen(data));

 delete list;

它工作正常,但现在我需要上传大文件(超过 70-100 mb),可以是图像(.jpg、.png、.bmp)和其他文档类型(.pdf、.docx、等)。

是否可以使用此代码解决我的任务?我将不胜感激每一个建议...

P.S.我的IDE是C++ Builder 6,不过我觉得没关系。

【问题讨论】:

如果你用 C++ 编程,为什么不用std::string 作为“数据”呢?或者使用std::ostringstream 进行格式化?以及为什么要动态分配list 而不是仅仅将其定义为一个简单的对象实例? @Someprogrammerdude,问题中的 IDE 将回答您的所有问题 :) 2002 年的编译器 facepalm。嗯,它至少比 TurboC++ 3 更新。 看来您的学习材料已经过时了。你应该得到一本好的、现代的 C++ 书。 看你的cmets很有趣,但我真的需要用Wininet上传文件。 (不是印地等) 【参考方案1】:

这是一个文件上传的工作示例:

void http_upload_file(PCHAR szServer, PCHAR szScript, PCHAR szParam, PCHAR szValue, PCHAR szFile)

    PCHAR szHeaders = "Content-Type: multipart/form-data; boundary=----qwerty";
    PCHAR szData    = "------qwerty\r\n"
                      "Content-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n"
                      "------qwerty\r\n"
                      "Content-Disposition: form-data; name=\"files[]\"; filename=\"%s\"\r\n"
                      "Content-Type: application/octet-stream\r\n"
                      "Content-Transfer-Encoding: binary\r\n\r\n";
    PCHAR szDataEnd = "\r\n------qwerty--\r\n";
    char  szHeader[512];

    HINTERNET hSession, hConnect, hRequest;
    DWORD     dwFileSize, dwBytesRead, dwContentLength,dwBytesWritten;

    hSession = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);

    if (hSession)
    
        hConnect = InternetConnect(hSession, szServer, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP,0, 0);

        if (hConnect)
        
            hRequest = HttpOpenRequest(hConnect, "POST", szScript, NULL, NULL, 0, 0, 0);

            if (hRequest)
            
                HANDLE hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

                if (hFile != INVALID_HANDLE_VALUE)
                
                    dwFileSize      = GetFileSize(hFile, NULL);
                    wsprintf(szHeader, szData, szParam, szValue, szFile);
                    dwContentLength = lstrlen(szHeader) + dwFileSize + lstrlen(szDataEnd);
                    LPBYTE pBuf     = (LPBYTE)malloc(dwContentLength);
                    CopyMemory(&pBuf[0], szHeader, lstrlen(szHeader));
                    ReadFile(hFile, &pBuf[lstrlen(szHeader)], dwFileSize, &dwBytesRead, NULL);
                    CopyMemory(&pBuf[lstrlen(szHeader) + dwFileSize], szDataEnd, lstrlen(szDataEnd));
                    HttpSendRequest(hRequest, szHeaders, lstrlen(szHeaders), pBuf, dwContentLength);
                    CloseHandle(hFile);
                    free(pBuf);
                
            

            InternetCloseHandle(hRequest);
        

        InternetCloseHandle(hConnect);
    

    InternetCloseHandle(hSession);

【讨论】:

您能否编辑并添加示例函数调用,我无法弄清楚 szparam 和 szvalue 到底是什么

以上是关于将文件发送到 HTTP 服务器(C++ Wininet)的主要内容,如果未能解决你的问题,请参考以下文章

使用 Microsoft.Net.Http 将文件发送到服务

wininet api 将文件发送到 http web 服务

将字节数组从java程序发送到c++

C++ 如何使用 Socket 类向 HTTP 服务器发送数据和接收响应

将数据发送到另一个 C++ 程序

将字符串从 C# 发送到 C++ dll 文件