【问题标题】:WinInet : How to send multiple http get request with C++WinInet:如何使用 C++ 发送多个 http get 请求
【发布时间】:2016-09-13 17:45:14
【问题描述】:

我正在尝试编写一个从远程服务器下载一些东西的程序,

#include <iostream>
#include <string>
#include <Windows.h>
#include <WinInet.h>
#pragma comment(lib,"wininet.lib")

using namespace std;

string Get(){
    DWORD size = 0;
    DWORD wrt;
    string msg = "";
    HINTERNET io=InternetOpen("Downloader",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
    HINTERNET ic=InternetConnect(io,"192.168.1.15",8080,NULL,NULL,INTERNET_SERVICE_HTTP,0,0);
    HINTERNET hreq=HttpOpenRequest(ic,NULL,"/cgi-bin/cmd.py","HTTP/1.0",NULL,NULL,0,0);
    HttpSendRequest(hreq,NULL,0,NULL,0);
    InternetQueryDataAvailable(hreq,&size,0,0);
    char* buffer = new char[size+1];
    memset(buffer,0,size+1);
    InternetReadFile(hreq,buffer,size,&wrt);
    msg += buffer;
    free(buffer);
    InternetCloseHandle(io);
    InternetCloseHandle(ic);
    InternetCloseHandle(hreq);
    return msg;
}


int main(){
    while(TRUE){
        string msg=Get();
        if(msg.length()>1){
            cout<<msg<<endl;
        }
        Sleep(2000);
    }
return 0;
}

在另一端(在服务器上)我运行一个 python CGI 脚本来发送文本。 问题是程序只发送一次 GET 请求,即使有一个循环并且 msg.length() 等于 0 ,在另一边我可以看到我刚刚收到一个 GET 请求。 有人可以解决我的问题,或者任何想法....

【问题讨论】:

  • 在调试器下运行应用程序可以收集到哪些见解?
  • 您显示的代码是您正在运行的实际代码吗?如果不是,那么在您的实际情况中,您确实会检查您调用的所有函数是否有错误?其中许多可能会失败,而您似乎并未对此进行检查(如果您显示的代码是您的实际代码)。
  • 我还没有尝试调试器
  • @TarekRadah 始终在此处发布之前进行调试。
  • char* buffer = new char[size+1]; 后跟 free(buffer) 是错误的。 newdelete,或者 mallocfree

标签: c++ http winapi wininet winhttp


【解决方案1】:

您需要为每个 WinInet API 调用添加错误处理。

您还需要循环InternetReadFile(),因为可能需要多次读取才能收到完整的响应。在将每个缓冲区附加到 std::string 时,您需要考虑实际读取的字节数。

试试这样的:

#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>

#pragma comment(lib, "wininet.lib")

struct sHINTERNET
{
    HINTERNET hInet;

    sHINTERNET(HINTERNET AInet = NULL) : hInet(AInet) {}
    ~sHINTERNET() { InternetCloseHandle(hInet); }

    operator HINTERNET() { return hInet; }
    bool operator!() const { return !hInet; }
}

void WinInetError(const char *FuncName)
{
    DWORD dwErr = GetLastError();

    std::ostringstream oss;
    oss << FuncName << " failed!";

    if (dwErr != ERROR_INTERNET_EXTENDED_ERROR)
        oss << " Error: " << dwErr;
    else
    {
        DWORD dwLen = 0;
        InternetGetLastResponseInfo(&dwErr, NULL, &dwLen);

        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            std::basic_string<TCHAR> msg;

            ++dwLen;
            msg.resize(dwLen);

            if (InternetGetLastResponseInfo(&dwErr, &msg[0], &dwLen))
            {
                msg.resize(dwLen);
                oss << " Error: " << msg;
            }
        }
    }

    throw std::runtime_error(oss.str());
}

std::string Download()
{
    sHINTERNET io = InternetOpen("Downloader", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    if (!io)
        WinInetError("InternetOpen");

    sHINTERNET ic = InternetConnect(io, "192.168.1.15", 8080, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (!ic)
        WinInetError("InternetConnect");

    sHINTERNET hreq = HttpOpenRequest(ic, NULL, "/cgi-bin/cmd.py", "HTTP/1.0", NULL, NULL, 0, 0);
    if (!hreq)
        WinInetError("HttpOpenRequest");

    if (!HttpSendRequest(hreq, NULL, 0, NULL, 0))
        WinInetError("HttpSendRequest");

    std::string data;
    char buffer[1024];
    DWORD wrt;

    do
    {
        if (!InternetReadFile(hreq, buffer, sizeof(buffer), &wrt))
            WinInetError("InternetReadFile");

        if (wrt == 0)
            break; 

        data.append(buffer, wrt);
    }
    while (true);

    return data;
}

int main()
{
    while (true)
    {
        try
        {
            std::string data = Download();
            std::cout << data << std::endl;
        }
        catch (const std::exception &e)
        {
            std::cerr << "Error! " << e.what() << std::endl;
        }

        Sleep(2000);
    }

    return 0;
}

【讨论】:

  • Tnks!!!其实我的问题是每次验证对方是否有东西要下载
  • 循环和错误处理没问题,但我不明白这一点:struct sHINTERNET {HINTERNET hInet; sHINTERNET(HINTERNET AInet = NULL) : hInet(AInet) {} ~sHINTERNET() { InternetCloseHandle(hInet); } 运营商 HINTERNET() { 返回 hInet; } bool operator!() const { return !hInet; } }
  • 它类似于智能指针(std::auto_ptrstd::unique_ptr 等)。它使用 RAII 来自动调用 InternetCloseHandle(),从而允许代码更清晰和异常安全。如果您使用的是 C++11 或更高版本,则可以使用 std::unique_ptr 而不是定义自定义结构。最终效果是一样的。
猜你喜欢
  • 1970-01-01
  • 2015-03-15
  • 2013-09-25
  • 1970-01-01
  • 2010-12-21
  • 2017-06-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多