code:https://gitee.com/chuankong/tall-raspi
一、libcurl库介绍
https://curl.haxx.se/libcurl/c/
libcurl is a free and easy-to-use client-side URL transfer library, supporting DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP. libcurl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, cookies, user+password authentication (Basic, Digest, NTLM, Negotiate, Kerberos), file transfer resume, http proxy tunneling and more! libcurl is highly portable, it builds and works identically on numerous platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS and more… libcurl is free, thread-safe, IPv6 compatible, feature rich, well supported, fast, thoroughly documented and is already used by many known, big and successful companies.
二、安装libcurl
apt-cache search libcurl
//-----xxxx
libcurl4 - easy-to-use client-side URL transfer library (OpenSSL flavour)
libcurl4-doc - documentation for libcurl
libcurl4-gnutls-dev - development files and documentation for libcurl (GnuTLS flavour)
libcurl4-nss-dev - development files and documentation for libcurl (NSS flavour)
libcurl4-openssl-dev - development files and documentation for libcurl (OpenSSL flavour)
//xxxxxx
其中libcurl4-gnutls-dev、libcurl4-nss-dev、libcurl4-openssl-dev 都是curl4的实现,gnutls、nss、openssl都是ssl协议的实现库,选择其中一个安装即可
sudo apt-get install libcurl4-gnutls-dev
三、编写工具类
实现基本的get和post(restful)请求
cc_http.h
#ifndef CC_HTTP_H
#define CC_HTTP_H
#include <curl/curl.h>
#define HTTP_RESPONSE_ERR_LEN 255
typedef struct http_response
{
ssize_t errcode;
char errtext[HTTP_RESPONSE_ERR_LEN];
char *data;
char *header;
size_t datasize;
size_t headersize;
} HttpResponse;
struct http_response *http_response_new();
int http_response_free(struct http_response *p_resp);
int http_response_error(struct http_response *p_resp, size_t errcode, const char *errtext);
int http_client_global_init();
int http_client_global_cleanup();
struct http_response *curl_request_get(const char *url);
struct http_response *curl_request_post(const char *url, const char *body);
#define http_request_get curl_request_get
#define http_request_post curl_request_post
#endif
cc_http.c
#include "common.h"
#include "http.h"
int http_client_global_init()
{
curl_global_init(CURL_GLOBAL_DEFAULT);
return 0;
}
int http_client_global_cleanup()
{
curl_global_cleanup();
return 0;
}
struct http_response *http_response_new()
{
struct http_response *p_resp = malloc(sizeof(struct http_response));
if (p_resp)
{
memset(p_resp, 0, sizeof(struct http_response));
}
return p_resp;
}
int http_response_free(struct http_response *p_resp)
{
if (p_resp)
{
if (p_resp->data)
{
free(p_resp->data);
}
if (p_resp->header)
{
free(p_resp->header);
}
free(p_resp);
}
return 0;
}
int http_response_error(struct http_response *p_resp, size_t errcode, const char *errtext)
{
if (p_resp)
{
p_resp->errcode = errcode;
strncpy(p_resp->errtext, errtext, HTTP_RESPONSE_ERR_LEN);
}
return 0;
}
static size_t resp_callback(char *contents, size_t size, size_t nmemb, void *userdata)
{
size_t realsize = size * nmemb;
struct http_response *mem = (struct http_response *)userdata;
char *ptr = realloc(mem->data, mem->datasize + realsize + 1);
if (ptr == NULL)
{
/* out of data! */
printf("not enough data (realloc returned NULL)\n");
return 0;
}
mem->data = ptr;
memcpy(mem->data + mem->datasize, contents, realsize);
mem->datasize += realsize;
mem->data[mem->datasize] = 0;
return realsize;
}
static size_t header_callback(char *contents, size_t size, size_t nmemb, void *userdata)
{
size_t realsize = size * nmemb;
struct http_response *mem = (struct http_response *)userdata;
char *ptr = realloc(mem->header, mem->headersize + realsize + 1);
if (ptr == NULL)
{
/* out of data! */
printf("not enough data (realloc returned NULL)\n");
return 0;
}
mem->header = ptr;
memcpy(mem->header + mem->headersize, contents, realsize);
mem->headersize += realsize;
mem->header[mem->headersize] = 0;
return realsize;
}
struct http_response *curl_request_get(const char *url)
{
CURL *curl;
CURLcode rescode;
struct http_response *p_resp;
if ((p_resp = http_response_new()) == NULL)
{
return p_resp;
}
if ((curl = curl_easy_init()) == NULL)
{
http_response_error(p_resp, -1, "curl_easy_init failed");
return p_resp;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, p_resp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, resp_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, p_resp);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 5000); //libcurl存在毫秒超时bug,如果设备小于1000ms立即返回失败
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000); //设置超时时间
rescode = curl_easy_perform(curl);
if (rescode)
{
http_response_error(p_resp, rescode, curl_easy_strerror(rescode));
}
curl_easy_cleanup(curl);
return p_resp;
}
struct http_response *curl_request_post(const char *url, const char *body)
{
CURL *curl;
CURLcode rescode;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type:application/json;charset=UTF-8");
struct http_response *p_resp;
if ((p_resp = http_response_new()) == NULL)
{
return p_resp;
}
if ((curl = curl_easy_init()) == NULL)
{
http_response_error(p_resp, -1, "curl_easy_init failed");
return p_resp;
}
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, p_resp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, resp_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, p_resp);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 5000); //libcurl存在毫秒超时bug,如果设备小于1000ms立即返回失败
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 5000); //设置超时时间
rescode = curl_easy_perform(curl);
if (rescode)
{
http_response_error(p_resp, rescode, curl_easy_strerror(rescode));
}
curl_easy_cleanup(curl);
return p_resp;
}
四、调用测试类
以tall登录为例
int signin(const char *url, const char *identifier, const char *credential)
{
struct http_response *p_resp;
cJSON *root = NULL, *data = NULL, *tmp = NULL;
char *json = NULL;
char signinbody[1024];
//0.构造参数和返回对应的数据类型
struct
{
int client;
int type;
struct
{
const char *identifier;
const char *credential;
} data;
} param = {1, 3, {identifier, credential}};
struct
{
int code;
char *msg;
cJSON_bool success;
struct
{
char *token;
} data;
} response;
//1.构造请求参数
root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "client", param.client);
cJSON_AddNumberToObject(root, "type", param.type);
cJSON_AddItemToObject(root, "data", data = cJSON_CreateObject());
cJSON_AddStringToObject(data, "identifier", param.data.identifier);
cJSON_AddStringToObject(data, "credential", param.data.credential);
json = cJSON_PrintUnformatted(root);
strncpy(signinbody, json, sizeof(signinbody));
printf("params: %s\n", signinbody);
free(json);
cJSON_Delete(root);
//2.发送请求
if ((p_resp = http_request_post(url, signinbody)) == NULL)
{
ERR("Not enough memory for malloc");
return -1;
}
if (p_resp->errcode)
{
ERR(p_resp->errtext);
return -1;
}
//3.处理响应
printf("%lu bytes data recieved: %s\n", (unsigned long)p_resp->datasize, p_resp->data);
//printf("%lu bytes header recieved: %s\n", (unsigned long)p_resp->headersize, p_resp->header);
root = cJSON_Parse(p_resp->data);
if ((root) && (tmp = cJSON_GetObjectItemCaseSensitive(root, "success")))
{
if ((response.success = tmp->valueint))
{
if ((tmp = cJSON_GetObjectItemCaseSensitive(root, "data")))
{
if ((tmp = cJSON_GetObjectItemCaseSensitive(tmp, "token")))
{
response.data.token = tmp->valuestring;
strncpy(g_config.token, response.data.token, sizeof(g_config.token));
}
}
}
}
cJSON_Delete(root);
http_response_free(p_resp);
return *g_config.token ? 0 : -1;
}