c 语言 http get

99ANYc3cd6
预计阅读时长 25 分钟
位置: 首页 C语言 正文

在 C 语言中实现 HTTP GET 请求,通常有以下几种方法,从简单到复杂,适用于不同的场景:

c 语言 http get
(图片来源网络,侵删)
  1. 使用系统命令 (最简单,但不灵活):直接调用系统的 curlwget 命令。
  2. 使用第三方库 (最常用,推荐):如 libcurl,功能强大,跨平台。
  3. 手动实现 (最复杂,用于学习底层原理):使用 socket 手动构造 HTTP 协议数据包。

使用系统命令 (最简单)

这种方法不涉及真正的 C 语言网络编程,而是通过 system() 函数调用系统自带的命令行工具。优点是极其简单,缺点是效率低、不灵活、安全性较差(易受命令注入攻击)

示例代码

#include <stdio.h>
#include <stdlib.h> // 用于 system()
int main() {
    // 定义要获取的 URL
    const char *url = "https://www.example.com";
    // 构造 curl 命令
    // -s 参数让 curl 静默运行,不显示进度条
    char command[256];
    snprintf(command, sizeof(command), "curl -s \"%s\"", url);
    printf("Executing command: %s\n", command);
    // 执行命令并将结果输出到标准输出
    int ret = system(command);
    if (ret == 0) {
        printf("\nCommand executed successfully.\n");
    } else {
        perror("Error executing command");
    }
    return 0;
}

编译和运行:

# gcc -o http_get_simple http_get_simple.c
# ./http_get_simple

使用 libcurl 库 (最常用,推荐)

libcurl 是一个功能强大、支持多种协议(HTTP, HTTPS, FTP, 等)的客户端 URL 传输库,它是 C 语言中进行网络请求的事实标准。

安装 libcurl

在 Linux (Debian/Ubuntu) 上:

sudo apt-get update
sudo apt-get install libcurl4-openssl-dev

在 macOS 上 (使用 Homebrew):

brew install curl

Homebrew 安装的 curl 通常会自带开发头文件和库。

在 Windows 上,可以从 libcurl 官网 下载预编译的二进制包或源码进行编译。

示例代码

这个例子会获取网页内容并将其打印到控制台。

#include <stdio.h>
#include <curl/curl.h> // 包含 libcurl 的头文件
// 回调函数:用于处理 libcurl 接收到的数据
// 它会以 chunk (块) 的形式接收数据
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    // 计算接收到的数据块的大小
    size_t realsize = size * nmemb;
    // 将数据块追加到 userp 指向的缓冲区中
    // 假设 userp 是一个 FILE* 指针
    fwrite(contents, 1, realsize, (FILE *)userp);
    return realsize;
}
int main(void) {
    CURL *curl;          // libcurl 的句柄
    CURLcode res;        // 执行结果码
    FILE *fp;            // 文件指针,用于将响应写入文件或 stdout
    // 初始化 libcurl 全局环境
    curl_global_init(CURL_GLOBAL_ALL);
    // 初始化一个 curl 句柄
    curl = curl_easy_init();
    if (curl) {
        // 设置要请求的 URL
        curl_easy_setopt(curl, CURLOPT_URL, "https://www.example.com");
        // 设置一个回调函数,用于处理接收到的数据
        // 我们将数据直接写入标准输出 stdout
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, stdout); // 将数据写入 stdout
        // 设置一个 User-Agent,有些网站会检查这个
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
        // 如果是 HTTPS,可以跳过证书验证(仅用于测试,不安全!)
        // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        // curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
        // 执行请求
        res = curl_easy_perform(curl);
        // 检查执行结果
        if (res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));
        } else {
            // 获取并打印响应码
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            printf("\nHTTP Response Code: %ld\n", response_code);
        }
        // 清理 curl 句柄
        curl_easy_cleanup(curl);
    }
    // 清理 libcurl 全局环境
    curl_global_cleanup();
    return 0;
}

编译和运行:

Linux/macOS: 你需要链接 curl 库。

# -lcurl 表示链接 curl 库
gcc -o http_get_libcurl http_get_libcurl.c -lcurl
# ./http_get_libcurl

Windows (Visual Studio):

  1. curl.h, curlbuild.h, easy.h, typecheck-gcc.h, curlrules.h 等头文件放入项目目录。
  2. libcurl.lib 静态库文件加入项目链接器设置。
  3. 运行时需要将 libcurl.dll 放在可执行文件同目录下。

手动实现 (Socket 编程,用于学习)

这种方法完全不依赖任何外部库,直接使用操作系统提供的 Socket API,它能让你深刻理解 HTTP 协议的工作原理,但代码量巨大,且需要处理很多细节(如 DNS 解析、TCP 连接、SSL/TLS 加密等),这里只展示一个不加密的 HTTP/1.0 GET 请求的简化版。

示例代码 (仅 HTTP, 无加密)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#define PORT 80
#define BUFFER_SIZE 4096
int main() {
    int sockfd;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char buffer[BUFFER_SIZE];
    // 1. 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("ERROR opening socket");
        exit(1);
    }
    // 2. 获取服务器地址信息 (DNS 解析)
    // 使用 "www.example.com" 或 IP 地址 "93.184.216.34"
    server = gethostbyname("www.example.com");
    if (server == NULL) {
        fprintf(stderr, "ERROR, no such host\n");
        exit(1);
    }
    // 3. 设置服务器地址结构
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
    serv_addr.sin_port = htons(PORT);
    // 4. 连接服务器
    if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("ERROR connecting");
        exit(1);
    }
    printf("Connected to server.\n");
    // 5. 构造 HTTP GET 请求
    char request[BUFFER_SIZE];
    snprintf(request, BUFFER_SIZE,
             "GET / HTTP/1.1\r\n"  // 请求行
             "Host: www.example.com\r\n" // 必须的 Host 头
             "User-Agent: Simple-C-HTTP-Client/1.0\r\n" // 自定义 User-Agent
             "Connection: close\r\n" // 告诉服务器请求结束后关闭连接
             "\r\n"); // 空行,表示头部结束
    // 6. 发送请求
    if (send(sockfd, request, strlen(request), 0) < 0) {
        perror("ERROR writing to socket");
        exit(1);
    }
    printf("Request sent:\n%s\n", request);
    // 7. 接收响应
    printf("\n--- Receiving Response ---\n");
    long total_received = 0;
    while ((total_received = recv(sockfd, buffer, BUFFER_SIZE - 1, 0)) > 0) {
        buffer[total_received] = '\0'; // 确保字符串以 null 
        printf("%s", buffer);
    }
    if (total_received < 0) {
        perror("ERROR reading from socket");
    }
    printf("\n--- End of Response ---\n");
    // 8. 关闭套接字
    close(sockfd);
    return 0;
}

编译和运行 (Linux/macOS):

# gcc -o http_get_socket http_get_socket.c
# ./http_get_socket

局限性:

  • 不安全: 只支持 HTTP,不支持 HTTPS。
  • 不完整: 没有处理重定向、分块传输编码、压缩等复杂情况。
  • 复杂: 需要手动处理所有网络细节。

总结与对比

方法 优点 缺点 适用场景
系统命令 极其简单,无需额外库 效率低,不灵活,有安全风险 快速测试、脚本自动化,对性能和灵活性要求不高的场景
libcurl 库 功能强大,支持多种协议,跨平台,稳定,有良好文档 需要安装依赖库,学习曲线比方法一稍陡 绝大多数 C 语言网络应用的首选
手动实现 无依赖,能深入理解网络协议 代码复杂,功能有限,难以维护(如添加 HTTPS) 学习网络编程、教学、或者有非常特殊且无法使用 libcurl 的嵌入式环境

对于任何实际的项目,强烈推荐使用 libcurl,它为你处理了所有底层的复杂性,让你能专注于业务逻辑。

-- 展开阅读全文 --
头像
织梦列表如何调用文章图片?
« 上一篇 今天
dede如何调用栏目简介?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]