Win32下本地C/C++的高级HTTP客户端库

11

在Win32中,是否没有适用于本机C/C++的“高级”HTTP库,还是我只是在错误的地方寻找?

所谓“高级”,指的是一种API,它让我能够使用与.NET框架(但请注意,对我来说,使用C++/CLI不是一个选项)“差不多相同”的抽象级别在C++中进行HTTP网络请求/响应。

如何在Win32中使用C/C++执行此类操作(代码量大约相同)而又不使用.NET? 作为参考,我包括了一段示例代码,展示我如何在C#中执行此操作。

byte[] fileBytes = null;
bool successfulDownload = false;
using (WebClient client = new WebClient())
{
    WebProxy proxy = WebProxy.GetDefaultProxy();
    client.Proxy = proxy;
tryAgain:
    try
    {
        fileBytes = client.DownloadData(fileUrl);
        successfulDownload = true;
    }
    catch (WebException wEx)
    {
        if (wEx.Response != null && wEx.Response is HttpWebResponse)
        {
            string username = null, password = null;
            bool userCanceled = false;
            HttpStatusCode statusCode = ((HttpWebResponse)wEx.Response).StatusCode;
            switch (statusCode)
            {
                case HttpStatusCode.ProxyAuthenticationRequired:
                    // This is just a convenience function defined elsewhere
                    GetAuthenticationCredentials(fileUrl, true,
                        out username, out password, out userCanceled);
                    if (!userCanceled)
                    {
                        client.Proxy.Credentials = new NetworkCredential(username, password);
                        goto tryAgain;
                    }
                    break;
                case HttpStatusCode.Unauthorized:
                    // This is just a convenience function defined elsewhere
                    GetAuthenticationCredentials(fileUrl, false,
                        out username, out password, out userCanceled);
                    if (!userCanceled)
                    {
                        client.Credentials = new NetworkCredential(username, password);
                        goto tryAgain;
                    }
                    break;
            }
        }
    }
}

请问有哪些适用于HTTP客户端的C语言库? - Piotr Dobrogost
7个回答

8

这已经是我想要做的最接近的方式了,但还不太够。问题在于你需要编写相当多的代码来处理“奇特”的代理场景(如自动代理配置脚本和Web代理自动发现协议)。 - Guido Domenici
也许我很傻,但对于自动代理配置脚本,难道不只需要在InternetOpen中更改一个标志吗?但是无法提供关于WPAD的任何帮助... - Goz
在寻找完全无关的东西时,我偶然发现了这个MSDN页面:http://msdn.microsoft.com/en-us/library/aa383910.aspx它确实需要你提供大量额外的代码,但看起来并不特别复杂 :) - Goz
谢谢Goz,我在InternetOpen()中忽略了INTERNET_OPEN_TYPE_PRECONFIG标志。这正是我要找的。 - Guido Domenici

7
除了灵活而强大但我认为非常笨重的libcurl/curlpp之外,还有两个C++库引起了我的关注。这两个库都是基于Boost::ASIO构建的,但是据我所知,都不支持代理。其中cpp-netlib博客)可能更加成熟(我知道它已经进行了一些实际测试),但目前缺少超时功能(我正在解决!)。示例:
network::http::request  request("http://google.com");
network::http::client   client;
network::http::response response;

response = client.get(request);
if (response.status() == 200)
{
    std::cout << body(response));
}

Urdl文档)是由ASIO的创始人编写的,具有超时功能(但仅在上个月才宣布)。 它采用不同的模型,选择与流一起工作:

urdl::istream is("http://google.com");
std::string line;
while (std::getline(is, line))
{
    std::cout << line << std::endl;
}

我同意C++对HTTP的支持不够完善,但是这两个库都显示出了很大的潜力。


7

我认为libcurl符合这些要求。而且还有更多。

这个示例展示了如何获取一个HTTP页面,仅将其存储在内存中。虽然它比你的示例代码多一点,但它是用C编写的。


这是一个很好的答案 - libcurl确实是一个很棒的库,这也是我目前在使用的。然而,在代理区域它存在一些不足之处。例如,它不支持(像.NET类那样)自动代理配置脚本。 - Guido Domenici

4

POCO还拥有跨平台的网络组件。

举个例子,FTP程序可以像这样实现(没有错误检查):

Poco::Net::FTPStreamFactory::registerFactory();
std::ofstream localFile(inputFile, std::ios_base::out | std::ios_base::binary);
Poco::URI uri(inputURL);
std::auto_ptr<std::istream> ptrFtpStream(Poco::Net::URIStreamOpener::defaultOpener().open(uri));
Poco::StreamCopier::copyStream(*ptrFtpStream.get(), localFile);

1

你没有看错地方。这只是悲哀的现实。这就是为什么有一个名为 curlpp 的 libcurl C++ 包装器。

下面是一个示例,演示如何检索网页并将其打印到标准输出流中。

#include <curlpp/curlpp.hpp>
#include <curlpp/Easy.hpp>
#include <curlpp/Options.hpp>


using namespace curlpp::options;

int main(int, char **)
{
  try
  {
    // That's all that is needed to do cleanup of used resources (RAII style).
    curlpp::Cleanup myCleanup;

    // Our request to be sent.
    curlpp::Easy myRequest;

    // Set the URL.
    myRequest.setOpt<Url>("http://example.com");

    // Send request and get a result.
    // By default the result goes to standard output.
    myRequest.perform();
  }

  catch(curlpp::RuntimeError & e)
  {
    std::cout << e.what() << std::endl;
  }

  catch(curlpp::LogicError & e)
  {
    std::cout << e.what() << std::endl;
  }

  return 0;
}

1
Qt库的一部分,QtNetwork,也是一个可能的选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接