Linux实现发送post请求

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);

    // 设置要POST的JSON数据

  //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);

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容