由浅入深C系列五:使用libcurl进行基于http get/post模式的C语言交互应用开发

这篇具有很好参考价值的文章主要介绍了由浅入深C系列五:使用libcurl进行基于http get/post模式的C语言交互应用开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

大多数在linux下的开发者,都会用到curl这个命令行工具。对于进行restful api的测试等,非常方便。其实,这个工具还提供了一个C的开发库,可以很方便的在C语言开发环境下完成基于http的请求和响应交互,高效的开发基于http/smtp等的网络应用程序

/* 2023-08-14 更新宏定义 
    1. 使用可变参数,支持多项输出; 
    2. 去除Z中默认加上的双引号; 
*/
#define X_LOG_DEBUG(Z, X...) \
    printf("[%s %s] [%s.%d] [%s] [DEBUG] " Z "\n", __DATE__, __TIME__, __FILE__, __LINE__, __FUNCTION__, ##X)

环境准备

下载并安装curl的开发包

yum install libcurl-devel.x86_64

在线资源

开发过程中主要参考CURL官方介绍及API参考文档 | link

示例代码

多余的话就不多说了,直接上示例代码,通过代码中的注释来说明开发过程。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../include/xhttp.h"

/*
-  这个是一个回调函数,主要用于curl在执行过程中,当有被请求的数据到达时,被调用来向-curl_easy_setopt设置的chunk中写入数据。
  这个回调函数在curl_easy_perform执行完成前会被调用多次。当执行完成后,从chunk中取出这次交互返回的数据。
*/
static size_t cb_write_data(void *data, size_t size, size_t nmemb, void *clientp)
{
    size_t realsize = size * nmemb;
    http_response *mem = (http_response *)clientp;

    char *ptr = realloc(mem->response, mem->size + realsize + 1);
    if(ptr == NULL)
        return 0;  /* out of response_st! */
 
    mem->response = ptr;
    memcpy(&(mem->response[mem->size]), data, realsize);
    mem->size += realsize;
    mem->response[mem->size] = 0;
    
    return realsize;
}

/*
  这个是向外发布的一个函数,调用的方式示例如下:
  char* payload = "{\"code\":\"\",\"codeUuid\":\"\",\"loginName\":\"user@domain\",\"loginPwd\":\"xxxxxxxx\"}";
  http_response *resp = http_post("https://local.domain/admin-api/session/login", NULL, payload);
  使用完返回数据后,记得释放resp->reesponse,避免内存漏。
*/
http_response* http_post(char* url, char* token, char* payload) 
{
    http_response chunk = {0};
    /* 设置curl上下文,对curl实例进行初始化 */
    curl_global_init(CURL_GLOBAL_ALL);
    CURL *curl = curl_easy_init();
    CURLcode res;
    if(curl) 
    {
        X_LOG_DEBUG("%s", "libcurl curl_easy_setopt start ...");
        /* 设置curl各个参数: 请求地址 */
        curl_easy_setopt(curl, CURLOPT_URL, url);
        /* 设置curl各个参数: 请求方式为post */
        curl_easy_setopt(curl, CURLOPT_POST, 1L);

		/* 设置curl各个参数: http中的请求头部分的内容 */
        X_LOG_DEBUG("%s", "libcurl curl_easy_setopt CURLOPT_HTTPHEADER start ...");
        struct curl_slist *list = {0};
        list = curl_slist_append(NULL, "Content-Type: application/json;charset=utf8");
        list = curl_slist_append(list, "routeurl: /project/project-list");
        /* 设置curl各个参数: 可选部分,如果请求中要求token,可以设置上 */
        if (token != NULL)
        {
            char* x_access_token_str = (char*)malloc( MAX_UTMP_TOKEN_SIZE );
            sprintf(x_access_token_str, "x-access-token: %s", token);
            X_LOG_DEBUG("%s", x_access_token_str);
            list = curl_slist_append(list, x_access_token_str);
        }
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);

        X_LOG_DEBUG("%s", "libcurl curl_easy_setopt CURLOPT_USERAGENT start ...");
        /* some servers do not like requests that are made without a user-agent 
            field, so we provide one */
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0");

		/* 设置curl各个参数: http的请求体部分,主要是请求中携带的数据 */
        /* POST data */
        X_LOG_DEBUG("%s", "libcurl curl_easy_setopt CURLOPT_POSTFIELDSIZE/CURLOPT_POSTFIELDS start ...");
        X_LOG_DEBUG("request body data is:%s", payload);
        X_LOG_DEBUG("request body len is:%d", strlen(payload));
        /* size of the POST data */
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(payload));
        /* pass in a pointer to the data - libcurl will not copy */
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload);

		/* 设置curl各个参数: 重要部分,设置了返回值的回调函数和返回值的内存放置区域 */
        /* RECEIVE DATA */
        X_LOG_DEBUG("%s", "libcurl curl_easy_setopt CURLOPT_WRITEFUNCTION/CURLOPT_WRITEDATA start ...");
        /* send all data to this function  */
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb_write_data);
        /* we pass our 'chunk' struct to the callback function */
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

        X_LOG_DEBUG("%s", "libcurl curl_easy_setopt successfully complete ...");

		/* 执行curl请求,并获取返回值:CURLE_OK,表示执行成功 */
        X_LOG_DEBUG("%s", "libcurl curl_easy_perform start ...");
        res = curl_easy_perform(curl);
        X_LOG_DEBUG("%s", "libcurl curl_easy_perform successfully complete ...");
    
        if(res != CURLE_OK) {
            fprintf(stderr, "curl_easy_perform() is failed: %s", curl_easy_strerror(res));
            curl_slist_free_all(list); /* free the list again */
            curl_easy_cleanup(curl);
        } else {
        	/* 处理curl返回的数据 */
            X_LOG_DEBUG("chunk size %d", chunk.size);

            http_response response = {0};
            response.response = (char*)malloc(1048576*5);
            memset(response.response, 0, chunk.size+1);
            memcpy(response.response, chunk.response, chunk.size+1);
            response.size = chunk.size;

            /* remember to free the buffer */
            free(chunk.response);
            curl_slist_free_all(list); /* free the list again */ 
            curl_global_cleanup();
            
            return &response;
        }
    } 
}

引用的头文件如下:文章来源地址https://www.toymoban.com/news/detail-642244.html

#ifndef __X_HTTP_H__
#define __X_HTTP_H__

#include <stdlib.h>
#include <curl/curl.h>
/* 更新宏定义 1. 使用可变参数,支持多项输出; 2. 去除Z中默认加上的双引号; */
#define X_LOG_DEBUG(Z, X...) \
    printf("[%s %s] [%s.%d] [%s] [DEBUG] " Z "\n", __DATE__, __TIME__, __FILE__, __LINE__, __FUNCTION__, ##X)

#define MAX_UTMP_TOKEN_SIZE 8192

typedef struct http_response_s {
  char *response;
  size_t size;
} http_response;

typedef struct http_request_s {
    char *request;
    size_t size;
} http_request;

http_response* http_post(char* url, char* token, char* payload);

#endif

测试调用

int main(int argc, char** argv) {
	char* payload = "{\"code\":\"\",\"codeUuid\":\"\",\"loginName\":\"user@domain\",\"loginPwd\":\"xxxxxxxx\"}";
	http_response *resp = http_post("https://local.domain/admin-api/session/login", NULL, payload);
	printf("http_response [%d] is: %s\n", resp->size, resp->response);
	char *tokenVal = strstr(resp->response, "xaccessToken");
	int end = strlen(tokenVal);
	*(tokenVal + end-2) = 0;
	char** token_arr;
	__strtok_r(tokenVal, ":", token_arr);
	char* replacementKey = strtrim(token_arr[0], '\"');
	exit(0)
}

运行结果

[Aug 11 2023 10:20:02] [src/xhttp.c.37] [http_post] [DEBUG] "libcurl curl_easy_setopt start ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.42] [http_post] [DEBUG] "libcurl curl_easy_setopt CURLOPT_HTTPHEADER start ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.55] [http_post] [DEBUG] "libcurl curl_easy_setopt CURLOPT_USERAGENT start ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.61] [http_post] [DEBUG] "libcurl curl_easy_setopt CURLOPT_POSTFIELDSIZE/CURLOPT_POSTFIELDS start ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.62] [http_post] [DEBUG] "request body data is:{"code":"","codeUuid":"","loginName":"user@domain","loginPwd":"xxxxxxxx"}"
[Aug 11 2023 10:20:02] [src/xhttp.c.63] [http_post] [DEBUG] "request body len is:75"
[Aug 11 2023 10:20:02] [src/xhttp.c.70] [http_post] [DEBUG] "libcurl curl_easy_setopt CURLOPT_WRITEFUNCTION/CURLOPT_WRITEDATA start ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.76] [http_post] [DEBUG] "libcurl curl_easy_setopt successfully complete ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.79] [http_post] [DEBUG] "libcurl curl_easy_perform start ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.81] [http_post] [DEBUG] "libcurl curl_easy_perform successfully complete ..."
[Aug 11 2023 10:20:02] [src/xhttp.c.90] [http_post] [DEBUG] "chunk size 6693"

到了这里,关于由浅入深C系列五:使用libcurl进行基于http get/post模式的C语言交互应用开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 由浅入深Netty代码调优

    序列化,反序列化主要用在消息正文的转换上 序列化时,需要将 Java 对象变为要传输的数据(可以是 byte[],或 json 等,最终都需要变成 byte[]) 反序列化时,需要将传入的正文数据还原成 Java 对象,便于处理 目前的代码仅支持 Java 自带的序列化,反序列化机制,核心代码如

    2024年02月05日
    浏览(46)
  • 【个人笔记】由浅入深分析 ClickHouse

    项目中不少地方使用到ClickHouse,就对它做了一个相对深入一点的了解和研究。并对各种知识点及整理过程中的一些理解心得进行了汇总并分享出来,希望对其他同学能有帮助。 本文主要讲解ClickHouse的特点、读写过程、存储形式、索引、引擎、物化视图等特性。 适合 入门和

    2024年01月20日
    浏览(47)
  • 由浅入深理解C#中的事件

    本文较长,给大家提供了目录,可以直接看自己感兴趣的部分。 前面介绍了C#中的委托,事件的很多部分都与委托类似。实际上,事件就像是专门用于某种特殊用途的简单委托,事件包含了一个私有的委托,如下图所示: 有关事件的私有委托需要了解的重要事项如下: 1、事

    2024年02月03日
    浏览(44)
  • 【由浅入深学习MySQL】之索引进阶

    本系列为:MySQL数据库详解,为千锋资深教学老师独家创作 致力于为大家讲解清晰MySQL数据库相关知识点,含有丰富的代码案例及讲解。如果感觉对大家有帮助的话,可以【关注】持续追更~ 文末有本文重点总结,技术类问题,也欢迎大家和我们沟通交流! 从今天开始本系列

    2024年02月05日
    浏览(45)
  • 手拉手Vue组件由浅入深

    组件 (Component) 是 Vue.js 最强大的功能之一,它是html、css、js等的一个聚合体,封装性和隔离性非常强。 组件化开发:     1、将一个具备完整功能的项目的一部分分割多处使用     2、加快项目的进度     3、可以进行项目的复用 组件注册分为:全局注册和局部注册 目录

    2024年01月18日
    浏览(46)
  • 由浅入深介绍 Python Websocket 编程

    1.1 websocket 协议简介 Websocket协议是对http的改进,可以实现client 与 server之间的双向通信; websocket连接一旦建立就始终保持,直到client或server 中断连接,弥补了http无法保持长连接的不足,方便了客户端应用与服务器之间实时通信。 适用场景 html页面实时更新, 客户端的html页面

    2024年02月03日
    浏览(42)
  • Springboot3+EasyExcel由浅入深

    环境介绍 技术栈 springboot3+easyexcel 软件 版本 IDEA IntelliJ IDEA 2022.2.1 JDK 17 Spring Boot 3 EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。 官网https://easyexcel.opensource.ali

    2024年01月16日
    浏览(47)
  • 【由浅入深学MySQL】- MySQL连接查询

    本系列为:MySQL数据库详解,为千锋教育资深Java教学老师独家创作 致力于为大家讲解清晰MySQL数据库相关知识点,含有丰富的代码案例及讲解。如果感觉对大家有帮助的话,可以【点个关注】持续追更~ 文末有重点总结和福利内容! 技术类问题,也欢迎大家和我们沟通交流!

    2024年02月05日
    浏览(63)
  • 什么是感知机——图文并茂,由浅入深

    生活中常常伴随着各种各样的逻辑判断,比如看到远方天空中飘来乌云,打开手机看到天气预报说1小时后40%的概率下雨,此时时候我们常常会做出等会下雨,出门带伞的判断。 上述思考过程可以抽象为一个”与“的”神经逻辑“。当”看到乌云“和”天气预报40%下雨“同时

    2023年04月20日
    浏览(41)
  • 由浅入深剖析 Apollo(阿波罗)架构

    目录 一、介绍 二、架构和模块 三、架构剖析 1.最简架构  2. 高可用保障  3.多接口扩展 四、总结 Apollo(阿波罗)是携程框架部研发并开源的一款生产级的配置中心产品,它能够集中管理应用在不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的

    2024年02月13日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包