下面是《白话C++练武篇》书中658页,访问ftp服务器得到报头数据的程序
#include <curl/curl.h>
#include <iostream>
using namespace std;
size_t to_stream(char* data, size_t size, size_t nmemb, void* userdata)
{
ostream& p = * static_cast <ostream *> (userdata);
//从一个C风格的字符串构造字符串,但最多取n个字符或遇到'\0'
std::string line(data, size*nmemb);
//将字符串写入到指定的ostream对象中
p << line;
return size*nmemb;
}
int main()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* handle = curl_easy_init();
string url = "ftp://d2school:123456@127.0.0.1/:21";
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
/*在libcurl库中,CURLOPT_HEADERFUNCTION是一个选项,它允许你设置一个回调函数来处理接收到的HTTP头信息。*/
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, to_stream);
/*libcurl常数CURLOPT_HEADERDATA是libcurl的一个选项,它用于传递指针给libcurl*/
curl_easy_setopt(handle, CURLOPT_HEADERDATA, static_cast <void*> (&cout));
curl_easy_perform(handle);
curl_easy_cleanup(handle);
curl_global_cleanup();
return 0;
}
26行,使用to_stream函数,被设置为访问报头数据,需要的回调函数。它将访问得到的网络数据打印出来。
29行,为了将报头数据打印到控制台,将cout传递给了to_stream, 因为仅仅to_stream是不够的,还需要cout的辅助。
运行结果为。
下面我们使用模板技术实现更强大的回调方式
#include <curl/curl.h>
#include <iostream>
#include <fstream>
#include <string>
#include <functional>
using namespace std;
struct CURLFunctionHelper
{
CURLFunctionHelper(CURL* curl, CURLoption opt_function, CURLoption opt_data)
{
curl_easy_setopt(curl, opt_function, inner_function);
curl_easy_setopt(curl, opt_data, this);
}
template <typename Fn>//使用模板技术
void Bind(Fn&& fn) //fn的类型是个右值
{
//对象fn并非简单复制给了_callback,而是转移给了_callback,即:若是fn含有指针
//类型的成员,则指针复制给_callback, fn的指针成员被赋值为nullptr
_callback = std::move(fn);
}
private:
//简化function类型表达
typedef std::function <size_t(char*, size_t, size_t)> CURLCallback;
//负责转接的静态成员函数
static size_t inner_function(char* data
, size_t size, size_t nmemb
, void* userdata)
{
auto self = static_cast <CURLFunctionHelper*> (userdata);
return self->_callback(data, size, nmemb); //在此处转发
}
//function<>成员
CURLCallback _callback;
};
int main()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL* handle = curl_easy_init();
string url = "ftp://d2school:123456@127.0.0.1/:21";
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
//构造一个CURLFunctionHelper对象,指明配置项和HEADER相关,在构造函数中,完成handle的设置
CURLFunctionHelper helper(handle, CURLOPT_HEADERFUNCTION, CURLOPT_HEADERDATA);
//绑定一个lambda表达式,注意它的入参和返回值
helper.Bind([](char* data, size_t size, size_t nmemb)->size_t
{
std::string line(data, size*nmemb);
cout << line;
return size*nmemb;
});
curl_easy_perform(handle);
curl_easy_cleanup(handle);
curl_global_cleanup();
return 0;
}
50行,声明一个helper对象,该对象的构造函数中,完成了回调函数的设置
其中,13行,将静态成员函数inner_function设置为回调函数,而inner_function中需要访问非静态成员_call_back, 这需要一个CURLFunctionHelper对象,所以14行,将this对象传递给了inner_function。
53行,调用helper的Bind() 成员函数,Bind()函数,通过转移的方式,将Lambda表达式
[](char* data, size_t size, size_t nmemb)->size_t
{
std::string line(data, size*nmemb);
cout << line;
return size*nmemb;
}
赋给了_callback成员。
实际执行过程,将执行30行的静态成员函数inner_function,而inner_function中,self是14行传递过来的this,35行,调用_callback, 而_callback就是Bind函数转移过来的Lambda表达式,从而实现了对ftp报头数据的打印。
运行效果如下图: