c语言httppost

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

使用 libcurl 库(最推荐、最简单)

libcurl 是一个功能强大且广泛使用的开源客户端 URL 传输库,它支持 HTTP, HTTPS, FTP, SMTP 等多种协议,是进行网络请求的首选。

c语言httppost
(图片来源网络,侵删)

安装 libcurl

在 Linux (Ubuntu/Debian) 上:

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

在 Linux (CentOS/RHEL) 上:

sudo yum install libcurl-devel

在 Windows 上:

  1. 访问 libcurl 官网 下载预编译的二进制包(curl-8.x.x-win64-mingw.zip)。
  2. 解压文件,并将 bin 目录(curl-8.x.x-win64-mingw\bin)添加到系统的 PATH 环境变量中。
  3. 在你的 IDE(如 Visual Studio)中,需要配置包含目录(include)和库目录(lib),并链接 libcurl.lib

示例代码

这个示例演示如何向一个测试网站发送一个简单的 POST 请求,并打印响应。

c语言httppost
(图片来源网络,侵删)
#include <stdio.h>
#include <curl/curl.h> // 引入 libcurl 头文件
// 回调函数,用于处理服务器返回的数据
// 它会 libcurl 会被重复调用,直到所有数据接收完毕
size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    // contents: 服务器返回的数据块
    // size: 每个数据块中单个元素的大小 (通常是1)
    // nmemb: 每个数据块中元素的数量
    // userp: 我们在 CURLOPT_WRITEFUNCTION 中设置的指针 (这里是 stdout)
    size_t total_size = size * nmemb;
    // 将数据直接写入标准输出
    fwrite(contents, 1, total_size, (FILE *)userp);
    // 返回实际处理的数据大小,libcurl 需要这个值来判断是否成功
    return total_size;
}
int main(void) {
    CURL *curl;          // libcurl easy handle 指针
    CURLcode res;        // 操作结果码
    // 1. 初始化 libcurl 全局环境
    curl_global_init(CURL_GLOBAL_ALL);
    // 2. 获取一个 easy handle
    curl = curl_easy_init();
    if (curl) {
        // 3. 设置 easy handle 的选项
        // 目标 URL
        curl_easy_setopt(curl, CURLOPT_URL, "https://httpbin.org/post");
        // 设置为 POST 请求
        curl_easy_setopt(curl, CURLOPT_POST, 1L);
        // 要 POST 的数据
        const char *post_data = "name=John Doe&message=Hello from C";
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
        // 设置回调函数来处理响应数据
        // 我们将响应直接打印到屏幕上
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, stdout);
        // (可选) 设置 User-Agent
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
        // (可选) 如果需要发送 JSON 数据,可以设置 Content-Type
        // curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
        // struct curl_slist *headers = NULL;
        // headers = curl_slist_append(headers, "Content-Type: application/json");
        // curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        // curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"key\":\"value\"}");
        // 4. 执行请求
        printf("Sending POST request to https://httpbin.org/post...\n");
        res = curl_easy_perform(curl);
        // 5. 检查执行结果
        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("\nRequest finished with HTTP status code: %ld\n", response_code);
        }
        // 6. 清理 easy handle
        curl_easy_cleanup(curl);
    }
    // 7. 清理 libcurl 全局环境
    curl_global_cleanup();
    return 0;
}

如何编译

在 Linux/macOS 上:

gcc -o http_post http_post.c -lcurl

-lcurl 表示链接 libcurl 库。

在 Windows (使用 MinGW/g++) 上:

gcc -o http_post.exe http_post.c -lcurl

在 Windows (使用 Visual Studio) 上: 确保在项目属性中正确配置了 libcurl 的包含目录、库目录和依赖项。


使用 WinINet API(仅限 Windows)

如果你的程序只在 Windows 平台上运行,并且不想引入第三方库,可以使用 Windows 自带的 WinINet API,但它不如 libcurl 灵活,且仅限 Windows。

示例代码

#include <windows.h>
#include <wininet.h>
#include <stdio.h>
#pragma comment(lib, "wininet.lib")
int main(void) {
    HINTERNET hInternet = NULL;
    HINTERNET hConnect = NULL;
    HINTERNET hRequest = NULL;
    // 1. 初始化 WinINet 会话
    hInternet = InternetOpenA("My HTTP Client", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (hInternet == NULL) {
        printf("InternetOpen failed with error: %lu\n", GetLastError());
        return 1;
    }
    // 2. 连接到服务器
    hConnect = InternetConnectA(hInternet, "httpbin.org", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (hConnect == NULL) {
        printf("InternetConnect failed with error: %lu\n", GetLastError());
        InternetCloseHandle(hInternet);
        return 1;
    }
    // 3. 创建一个 HTTP 请求
    const char* accept_types[] = {"*/*", NULL};
    hRequest = HttpOpenRequestA(hConnect, "POST", "/post", NULL, NULL, (LPCSTR*)accept_types, INTERNET_FLAG_RELOAD, 0);
    if (hRequest == NULL) {
        printf("HttpOpenRequest failed with error: %lu\n", GetLastError());
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }
    // 4. 添加请求头 (可选)
    const char* headers = "Content-Type: application/x-www-form-urlencoded";
    if (!HttpAddRequestHeadersA(hRequest, headers, -1, HTTP_ADDREQ_FLAG_ADD)) {
        printf("HttpAddRequestHeaders failed with error: %lu\n", GetLastError());
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }
    // 5. 准备要发送的数据
    const char* post_data = "name=John Doe&message=Hello from WinINet";
    DWORD data_size = strlen(post_data);
    // 6. 发送请求和数据
    if (!HttpSendRequestA(hRequest, NULL, 0, (LPVOID)post_data, data_size)) {
        printf("HttpSendRequest failed with error: %lu\n", GetLastError());
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hInternet);
        return 1;
    }
    // 7. 读取响应
    char buffer[4096];
    DWORD bytes_read;
    printf("Response from server:\n");
    while (InternetReadFile(hRequest, buffer, sizeof(buffer) - 1, &bytes_read) && bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("%s", buffer);
    }
    // 8. 清理资源
    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hInternet);
    printf("\nRequest completed.\n");
    return 0;
}

如何编译

在 Visual Studio 中创建一个 C++ 控制台项目,直接编译即可(因为 #pragma comment(lib, "wininet.lib") 会自动链接),或者使用 MinGW:

gcc -o wininet_post wininet_post.c -lwininet

手动实现 Socket(最复杂,不推荐)

这种方法完全不依赖任何库,直接通过操作系统底层的 Socket API 来实现,它能让你完全理解 HTTP 协议的工作原理,但代码量巨大,容易出错,且需要处理各种网络细节(如 DNS 解析、TCP 连接、SSL/TLS 加密等)。

强烈建议初学者不要尝试这种方法,除非你有特殊的学习目的。

核心思路

  1. DNS 解析:将域名(如 httpbin.org)转换为 IP 地址。

  2. 建立 TCP 连接:使用 socket(), connect() 等函数与服务器的 80 (HTTP) 或 443 (HTTPS) 端口建立连接。

  3. 构造 HTTP POST 请求:手动拼接一个符合 HTTP 协议的请求字符串。

    POST /post HTTP/1.1
    Host: httpbin.org
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 27
    name=John Doe&message=Hello from C
  4. 发送请求:通过 send() 函数将构造好的请求字符串发送到服务器。

  5. 接收响应:通过 recv() 函数接收服务器返回的 HTTP 响应数据。

  6. 解析响应:手动解析响应头和响应体。

  7. 关闭连接:使用 close()closesocket() 关闭 Socket。

总结与对比

特性 libcurl (推荐) WinINet (仅限 Windows) 手动 Socket
易用性 非常高,API 简洁 中等,API 较旧 非常低,代码复杂
跨平台 (Windows, Linux, macOS 等) (仅 Windows)
功能 强大,支持多种协议、代理、SSL、上传下载等 基本功能,主要支持 HTTP/HTTPS 仅实现你编写的功能
依赖 需要安装第三方库 无,Windows 自带 无,但需要自己实现所有功能
稳定性 非常高,经过长期考验 较高,但 API 较老 取决于你的实现能力

对于绝大多数 C 语言项目,使用 libcurl 是最佳选择,它平衡了易用性、功能性和跨平台性,如果你确定项目只在 Windows 上运行,并且希望避免第三方依赖,WinINet 也是一个可行的选项,手动实现 Socket 则只适合学习网络协议或有特殊定制化需求的场景。

-- 展开阅读全文 --
头像
vxworks c语言开发需掌握哪些核心要点?
« 上一篇 今天
dede搜索功能如何实现?
下一篇 » 今天

相关文章

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

目录[+]