Linux下实现C语言的http请求实现

2023-05-16

1.     前言

Linux下的http请求有许多种方式,其中curl库是C语言封装的一个强大的库,使用curl比封装socket更加方便。cJSON是一个小型的json封装库,可以把数据封装成json格式。本文介绍了这两种技术,并通过此技术完成了Linux下的http请求,同时把代码封装到quagga下,quagga运行时可以正常创建数据到ONOS。

2.     Linux下http请求实现

2.1.    curl简介

curl命令是一个功能强大的网络工具,它能够通过http、ftp等方式下载文件,也能够上传文件。curl命令使用了libcurl库来实现,libcurl库常用在C程序中用来处理HTTP请求,curlpp是libcurl的一个C++封装,这几个东西可以用在抓取网页、网络监控等方面的开发,而curl命令可以帮助来解决开发过程中遇到的问题。本文档就是使用curl完成http请求。

2.1.1.    全局初始化

应用程序在使用libcurl之前,必须先初始化libcurl。libcurl只需初始化一次。可以使用以下语句进行初始化:

curl_global_init();

curl_global_init()接收一个参数,告诉libcurl如何初始化。参数CURL_GLOBAL_ALL 会使libcurl初始化所有的子模块和一些默认的选项,通常这是一个比较好的默认参数值。还有两个可选值:

CURL_GLOBAL_WIN32

只能应用于Windows平台。它告诉libcurl初始化winsock库。如果winsock库没有正确地初始化,应用程序就不能使用socket。在应用程序中,只要初始化一次即可。

CURL_GLOBAL_SSL

如果libcurl在编译时被设定支持SSL,那么该参数用于初始化相应的SSL库。同样,在应用程序中,只要初始化一次即可。

libcurl有默认的保护机制,如果在调用curl_easy_perform时它检测到还没有通过curl_global_init进行初始 化,libcurl会根据当前的运行时环境,自动调用全局初始化函数。但必须清楚的是,让系统自已初始化不是一个好的选择。

当应用程序不再使用libcurl的时候,应该调用curl_global_cleanup来释放相关的资源。在程序中,应当避免多次调用curl_global_init和curl_global_cleanup。它们只能被调用一次。

2.1.2.    easy interface

libcurl中被称为easy interface的api函数,所有这些函数都是有相同的前缀:curl_easy 。

要使用easyinterface,首先必须创建一个easy handle,easy handle用于执行每次操作。基本上,每个线程都应该有自己的easy handle用于数据通信(如果需要的话)。千万不要在多线程之间共享同一个easy handle。下面的函数用于获取一个easy handle:

CURL *easy_handle =curl_easy_init();

在easyhandle上可以设置属性和操作(action)。easy handle就像一个逻辑连接,用于接下来要进行的数据传输。

使用curl_easy_setopt函数可以设置easy handle的属性和操作,这些属性和操作控制libcurl如何与远程主机进行数据通信。一旦在easy handle中设置了相应的属性和操作,它们将一直作用该easyhandle。也就是说,重复使用easy hanle向远程主机发出请求,先前设置的属性仍然生效。

easy handle的许多属性使用字符串(以\0结尾的字节数组)来设置。通过curl_easy_setopt函数设置字符串属性时,libcurl内部会自动拷贝这些字符串,所以在设置完相关属性之后,字符串可以直接被释放掉(如果需要的话)。

    后面章节会根据http的get和post接口对常用的easy handle函数进行说明。

2.2.    cJSON简介

cJSON是在C语言中解析JSON的开源库,在cJSON中,一个key-value键值对被解析并存放在一个cJSON结构体变量中,其value取值集为:FALSE,TRUE,NULL,NUMBER,STRING,OBJECT,ARRAY。cJOSN库,仅有两个文件cJSON.c和cJSON.h。

2.2.1.       cJSON使用说明

下面使用cJSON组装以下json数据

{

    "mac":  "46:E4:3C:A4:11:12",

    "vlan": "-1",

    "ipAddresses":  ["222.222.233.2"],

    "location": {

        "elementId":    "of:0000001e08000fe3",

        "port": "31"

    }

}

代码如下:

//创建一个object

    cJSON *root =cJSON_CreateObject();

    cJSON_AddItemToObject(root,"mac",cJSON_CreateString("46:E4:3C:A4:13:12"));

    cJSON_AddStringToObject(root,"vlan","-1");

    cJSON*array = NULL;

    cJSON_AddItemToObject(root,"ipAddresses",array=cJSON_CreateArray());

    cJSON_AddItemToArray(array,cJSON_CreateString("192.168.10.2"));

    //创建一个子object,将此object添加到root

    cJSON*location = NULL;

    cJSON_AddItemToObject(root,"location",location=cJSON_CreateObject());

    cJSON_AddStringToObject(location,"elementId","of:0000001e08000fe3");

    cJSON_AddStringToObject(location,"port","31");

    //json结构格式化到缓冲区

    char*buf = cJSON_Print(root);

    //执行http请求函数

    http_client_thttp_read_client;

    http_client_read_init(&http_read_client,temp, buf);

    //数据使用完之后,把内存释放掉

    cJSON_Delete(json);

    free(buf);

2.3.    http的post请求

int http_client_read_init(http_client_t*http_client, const char *url, char *szJsonData)

{

   if (!url) {

        return -1;

    }

    //初始化libcurl,设置默认参数

   CURLcode return_code = curl_global_init(CURL_GLOBAL_ALL);

   if (CURLE_OK != return_code) {

        printf("initlibcurl failed.\n");

       return -1;

    }

    //获取easy handle

   http_client->handle = curl_easy_init();

   if (!http_client->handle) {

       return -1;

    }

    //通过CURLOPT_URL属性设置url

   curl_easy_setopt(http_client->handle, CURLOPT_URL, url);

    //通过CURLOPT_HTTPHEADER定义http消息的header

   struct curl_slist *plist = NULL;

    plist = curl_slist_append(plist, "Content-Type:application/json"); 

    curl_easy_setopt(http_client->handle, CURLOPT_HTTPHEADER, plist);

    printf("Thejson is: %s\n", szJsonData);

    //通过CURLOPT_POSTFIELDS设置要POST的数据

    curl_easy_setopt(http_client->handle,CURLOPT_POSTFIELDS, szJsonData);

    //通过CURLOPT_USERPWD属性来设置用户名与密码。参数是”user:password “的字符串

    curl_easy_setopt(http_client->handle,CURLOPT_USERPWD, "karaf:karaf");

    //使用curl_easy_perform执行上传数据

    curl_easy_perform(http_client->handle);

    //任务执行结束使用curl_easy_cleanup把内存释放

    curl_easy_cleanup(http_client->handle);

    return 0;

}

2.4.    http的get请求

int http_client_init(http_client_t*http_client, const char *url, write_cb_t *write_data, void *userp)

{

    if (!url) {

        return -1;

    }

    //初始化libcurl,设置默认参数

   CURLcode return_code;

   return_code= curl_global_init(CURL_GLOBAL_ALL);

   if (CURLE_OK != return_code) {

        printf("initlibcurl failed.\n");

        return -1;

    }

    //获取easy handle

   http_client->handle = curl_easy_init();

   if (!http_client->handle) {

       return -1;

    }

    //通过CURLOPT_URL属性设置url

    curl_easy_setopt(http_client->handle,CURLOPT_URL, url);

    //注册回调函数write_cb,回调函数将会在接收到数据的时候被调用

   curl_easy_setopt(http_client->handle, CURLOPT_WRITEFUNCTION, write_data);

    //通过CURLOPT_USERPWD属性来设置用户名与密码。参数是”user:password “的字符串

    curl_easy_setopt(http_client->handle,CURLOPT_USERPWD, "karaf:karaf");

    if (userp) {

    //设置写数据的变量

       curl_easy_setopt(http_client->handle, CURLOPT_WRITEDATA, userp);

    }

    //使用curl_easy_perform执行上传数据

    curl_easy_perform(http_client->handle);

    //任务执行结束使用curl_easy_cleanup把内存释放

    curl_easy_cleanup(http_client->handle);

   return 0;

}

//回调函数,将接收到的数据保存到本地文件中,同时显示在控制台上。

static size_t write_data(void *buf, size_tsize, size_t nmemb, void *userp)

{

   FILE *fp = (FILE *)userp;

   size_t return_size = fwrite(buf, size, nmemb, fp);

   printf("write_data: %ld, return_size: %ld\n", nmemb,return_size);

   return return_size;

}

2.5.    http的del请求

//获取easy handle

   http_client->handle = http_client_init();

   if (!http_client->handle) {

       return -1;

    }

    // 通过CURLOPT_URL属性设置url

   curl_easy_setopt(http_client->handle, CURLOPT_URL, url);

   // 设置http发送的内容类型为JSON 

   struct curl_slist *plist = NULL;

    //plist = curl_slist_append(plist, "Content-Type:application/json");

    curl_easy_setopt(http_client->handle,CURLOPT_HTTPHEADER, plist);

    // 设置要POSTJSON数据 

   //curl_easy_setopt(http_client->handle, CURLOPT_POSTFIELDS,szJsonData);

    curl_easy_setopt(http_client->handle,CURLOPT_CUSTOMREQUEST, "DELETE");

    curl_easy_setopt(http_client->handle,CURLOPT_USERPWD, "karaf:karaf");

2.6.    编译并执行

代码完成之后,使用gcc运行时需要带如下参数:

gcc -o http_client http_client.ccJSON.c -lcurl –lm

编译之后开始运行

./http_client

通过抓包可以看到http报文

 

注意事项:

1.  -lcurl是链接curl库,如果运行报如下错误:

mlogc.c:32:23: error: curl/curl.h: No such fileor directory

mlogc.c:1091: error: expected ‘)’ before ‘*’token

mlogc.c: In function ‘logc_init’:

 则需要安装如下依赖包:libcurl-dev, libcurl-devel

 centOS上安装依赖包:

 yum install libcurl-dev libcurl-devel  

2.   –lm是链接math的库,由于cJSON需要调用math库,如果不添加会报如下错误:

3.   如果有多个方法例如:get/post/delete等用到的URL一样,需要把如下代码,包含URL的头部注释掉,否则报文发布出去。

    // 设置http发送的内容类型为JSON 

    struct curl_slist *plist = NULL;

    //plist = curl_slist_append(plist, "Content-Type:application/json");

    curl_easy_setopt(http_client->handle,CURLOPT_HTTPHEADER, plist);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下实现C语言的http请求实现 的相关文章

  • 如何增加asp classic的请求接受限制

    我从java小程序向asp classic发送post请求 我在此请求中发送非常大的数据 即 csv 数据 当此请求中的字符数增加并超过 138000 时 asp 不接受该请求 java 小程序给出 500 错误 所以有人可以告诉我如何才能
  • 如何使用 Emacs 通过 HTTP 打开远程文件?

    大多数开源软件都通过某些 HTTP 服务公开其代码 我想从 Emacs 打开并浏览此类代码 但 AFAICS trapmp 只允许ssh and ftp 因此 我的第一个问题是如何打开 HTTP URL 以便在 Emacs 中进行读取 然后
  • 如何使用AWK脚本检查表的所有列数据类型? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 在这里 我正在检查表中第一列的数据类型 但我想知道AWK中表的所有列数据类型 我尝试过 但只能获得一列数据类型 例如 Column 1
  • Linux 中热插拔设备时检测设备是否存在

    我正在运行 SPIcode http lxr free electrons com source drivers spi spi omap2 mcspi c在熊猫板上 我想知道其中的哪个功能code http lxr free electr
  • 防止 ASP.Net 中的表单重新提交(不重定向到我自己)

    我有一个带有表单元素的母版页
  • 从 TypeScript 运行任何 Linux 终端命令?

    有没有办法直接从 TypeScript 类中执行 Linux 终端命令 这个想法是做类似的事情 let myTerminal new LinuxTerminal let terminalResult myTerminal run sudo
  • 适用于 KDE 和 Gnome 的 Gui [重复]

    这个问题在这里已经有答案了 我想为一个现在是 CLI 的应用程序编写一个 gui 它需要在 KDE 和 Gnome DE 中 看起来不错 充分利用用户的外观设置 如果我选择 Qt 或 GTK 我能够做到这一点吗 它们与两个 DE 集成良好吗
  • C 程序从连接到系统的 USB 设备读取数据

    我正在尝试从连接到系统 USB 端口的 USB 设备 例如随身碟 获取数据 在这里 我可以打开设备文件并读取一些随机原始数据 但我想获取像 minicom teraterm 这样的数据 请让我知道我可以使用哪些方法和库来成功完成此操作以及如
  • HttpWebRequest vs Webclient(特殊场景)

    我知道这个问题之前已经回答过thread https stackoverflow com questions 1694388 webclient vs httpwebrequest httpwebresponse 但我似乎找不到详细信息 在
  • Linux 桌面快捷方式和安装图标

    我需要添加什么到我的 spec文件来创建桌面快捷方式并在安装过程中为快捷方式分配一个图标 rpm 如果需要脚本 一个示例将非常有帮助 您在 Linux 下使用 desktop 文件作为图标 图标放置的位置取决于您使用的发行版和桌面环境 由于
  • 设置 Apache POI 的路径

    我想创建 Excel 文件并使用 java 程序在该文件中写入数据 That is here http www techbrainwave com p 554我在 java 文件所在的位置提取了 Apache POI 并将该路径包含在路径变
  • python 2.7 中的 HTTP 2 请求

    在 python 中向 HTTP 1 和 HTTP 2 发出请求有什么区别吗 我可以像这样在 python 中进行 HTTP 1 x 调用 url http someURL values param1 key param2 key2 dat
  • 在java中轮询Http服务器(重复发送http get请求)

    当对其进行 REST 调用时 我的 Web 服务器会发送一些信息 我想不断轮询该服务器 间隔5秒后重复发送HTTP GET请求 以检查返回的信息是否有任何变化 做到这一点最有效的方法是什么 您能提供一些代码示例吗 请注意 我只想开发客户端代
  • AJAX 发送数据到 Node.js 服务器

    我尝试使用 AJAX 将数据发送到 Node js 服务器 但不断遇到同样的问题 即接收问题 这是客户端 JavaScript AJAX 代码 var objects function return new XMLHttpRequest f
  • 没有可用的符号表信息

    我正在测试第三方的库 它崩溃了 当我想查看崩溃的原因时 我的 gdb 告诉我没有可用的调试符号 Program received signal SIGSEGV Segmentation fault Switching to Thread 0
  • 在 Linux 上的 Python 中使用受密码保护的 Excel 工作表

    问题很简单 我每周都会收到一堆受密码保护的 Excel 文件 我必须解析它们并使用 Python 将某些部分写入新文件 我得到了文件的密码 当在 Windows 上完成此操作时 处理起来很简单 我只需导入 win32com 并使用 clie
  • 如何在flutter项目中使用http拦截器?

    我必须向我的所有 Api 添加标头 有人告诉我为此使用 http 拦截器 但我无法理解如何做到这一点 因为我是颤振的新手 谁能帮我举个例子吗 您可以使用http 拦截器 https pub dev packages http interce
  • 如何更改 Ubuntu 14.04 上的 php-cli 版本?

    我是 Linux 新手 在篡改时破坏了一些 php 设置 如果我执行一个包含以下内容的 php 脚本 phpinfo 它显示 php 版本为 5 6 但通过命令行 如果我运行php v它返回 7 0 版本 我想让两个版本匹配 我怎样才能修复
  • 在 Linux 中禁用历史记录 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 要在 Linux 环境中禁用历史记录 我执行了以下命令 export HISTFILESIZE 0 export HISTSIZE 0 u
  • QFileDialog::getSaveFileName 和默认的 selectedFilter

    我有 getSaveFileName 和一些过滤器 我希望当用户打开 保存 对话框时选择其中之一 Qt 文档说明如下 可以通过将 selectedFilter 设置为所需的值来选择默认过滤器 我尝试以下变体 QString selFilte

随机推荐