CURL(Client URL)是一个开源的命令行工具和库,用于在各种网络协议下传输数据。它支持HTTP、HTTPS、FTP、FTPS等多种协议,并且可以轻松地集成到C语言程序中。CURL库的核心功能是通过简单的API调用,实现网络请求和数据传输。
CURL库由两个主要部分组成:libcurl
(CURL库)和curl
(命令行工具)。libcurl
是一个跨平台的C语言库,提供了丰富的API用于网络通信,而curl
命令行工具则是基于libcurl
开发的,用于在终端中执行网络请求。
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
典型的三段式结构包含初始化、配置执行和资源回收。但生产环境需要更复杂的控制逻辑。
if(!curl) {
fprintf(stderr, "CURL实例创建失败: 内存分配错误");
exit(EXIT_FAILURE);
}
在初始化失败时立即终止程序,避免后续操作引发段错误。
CURLcode opt_res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
if(opt_res != CURLE_OK) {
handle_config_error(opt_res);
}
虽然多数开发者忽略配置返回值检查,但严格模式下应对每个设置操作进行验证。
switch(res) {
case CURLE_COULDNT_CONNECT:
handle_connection_error();
break;
case CURLE_OPERATION_TIMEDOUT:
retry_with_backoff();
break;
case CURLE_SSL_CONNECT_ERROR:
verify_certificate_chain();
break;
default:
log_unexpected_error(res);
}
建立错误类型到处理策略的映射关系,实现精准错误恢复。
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if(http_code != 200) {
analyze_http_error(http_code);
}
状态码验证应区分客户端错误(4xx)和服务端错误(5xx)。
size_t validate_content(const char *ptr, size_t size) {
if(size < MIN_CONTENT_LENGTH) {
trigger_content_alert();
}
// 添加哈希校验逻辑
update_sha256(ptr, size);
return size;
}
通过MD5/SHA校验防止内容篡改,设置最小长度阈值过滤异常响应。
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
int header_callback(char *buffer, size_t size, void *userdata) {
if(strncmp(buffer, "Content-Type:", 13) == 0) {
validate_content_type(buffer);
}
return size;
}
验证Content-Type、Content-Encoding等头部信息确保数据格式符合预期。
#include <stdio.h>
#include <curl/curl.h>
#include <openssl/sha.h>
#include <unistd.h> // 用于sleep函数
#define MAX_RETRY 3
#define TIMEOUT_MS 5000
struct MemoryChunk {
char *memory;
size_t size;
SHA256_CTX sha_ctx;
};
size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t real_size = size * nmemb;
struct MemoryChunk *mem = (struct MemoryChunk *)userp;
// 哈希校验
SHA256_Update(&mem->sha_ctx, contents, real_size);
// 内存动态扩展
char *ptr = realloc(mem->memory, mem->size + real_size + 1);
if (!ptr) return 0;
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, real_size);
mem->size += real_size;
mem->memory[mem->size] = 0;
return real_size;
}
CURL* init_curl_engine() {
CURL *curl = curl_easy_init();
if (!curl) return NULL;
// 基础配置
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; AdvancedCrawler/1.0)");
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, TIMEOUT_MS);
// 设置代理信息
const char* proxyHost = "www.16yun.cn";
const char* proxyPort = "5445";
const char* proxyUser = "16QMSOML";
const char* proxyPass = "280651";
// 设置代理服务器
curl_easy_setopt(curl, CURLOPT_PROXY, proxyHost);
curl_easy_setopt(curl, CURLOPT_PROXYPORT, atoi(proxyPort));
// 设置代理认证信息
char proxyAuth[256];
snprintf(proxyAuth, sizeof(proxyAuth), "%s:%s", proxyUser, proxyPass);
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxyAuth);
return curl;
}
int execute_crawl(CURL *curl, const char *url) {
struct MemoryChunk chunk = {0};
SHA256_Init(&chunk.sha_ctx);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk);
CURLcode res;
int retry_count = 0;
do {
res = curl_easy_perform(curl);
if (res == CURLE_OK) {
// 验证阶段
long http_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code == 200) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_Final(hash, &chunk.sha_ctx);
printf("抓取成功!内容大小: %zu bytes\n哈希校验值: ", chunk.size);
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
printf("%02x", hash[i]);
putchar('\n');
free(chunk.memory);
return 0;
} else {
printf("HTTP错误代码: %ld\n", http_code);
}
} else {
fprintf(stderr, "CURL错误: %s\n", curl_easy_strerror(res));
}
// 指数退避重试
sleep((1 << retry_count) * 1000);
} while (retry_count++ < MAX_RETRY);
free(chunk.memory);
return -1;
}
int main() {
curl_global_init(CURL_GLOBAL_DEFAULT);
CURL *curl = init_curl_engine();
if (!curl) {
fprintf(stderr, "CURL引擎初始化失败\n");
return 1;
}
int result = execute_crawl(curl, "https://example.com");
curl_easy_cleanup(curl);
curl_global_cleanup();
return result;
}
CURLM *multi_handle = curl_multi_init();
// 添加多个easy_handle实现并行
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。