curl的应用

1

#include <string>
#include <curl/curl.h>  
#include "cJSON.h"

/* 为了通过编译定义的宏 */
#define OUT
#define INOUT
#define IN

#define TMS_LOG0(lLogLevel, ulErrCode, str)
#define TMS_LOG1(lLogLevel, ulErrCode, str, str1)
#define TMS_LOG2(lLogLevel, ulErrCode, str, str1, str2)

typedef unsigned int ULONG_32;
typedef unsigned long SIZE_T;

/* 类所需要的宏、结构体的定义 */

/** RESTFUL接口HTTP头格式枚举 */
typedef enum tagTMSMethodType
{
    TMS_METHOD_GET                           = 0,         /* HTTP 头GET  */
    TMS_METHOD_PUT                           = 1,         /* HTTP 头PUT  */
    TMS_METHOD_POST                         = 2,         /* HTTP 头POST */
    TMS_METHOD_DELETE                      = 3,         /* HTTP 头DELETE */
    TMS_METHOD_INVALID                    = 0xFFFFFFFF /* 无效值 */
}TMS_METHOD_TYPE_E;

#define  TMS_WA_REST_LIBCURL_OUT_TIME                   (40)                      /* rest接口POST请求传输超时时间*/                           
#define  TMS_WA_REST_LIBCURL_CONNECT_OUT_TIME           (40)                      /* rest接口POST请求连接超时时间*/ 
#define  TMS_WA_REST_HTTP_CONTENT_TYPE                  "application/json"      /* rest接口POST请求头类型 */
#define  TMS_WA_REST_RECV_LEN                           (1024)                      /* rest接口POST请求接收消息最大长度 */
#define  TMS_WA_REST_RECV_CODE                          "0"                     /* REST接口返回正常状态码 */
#define  ERR_COMMON_SUCCEED (0)             /* 成功通用码 */
#define  ERR_COMMON_FAIL    (1)             /* 失败通用码 */

/* 与DBE交互的Restful接口错误码 */
#define    TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE          (0x0EEEE000UL)  
#define    TMS_WA_RESTFUL_CURL_UNSUPPORTED_PROTOCOL     (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 1)    /* 协议不支持 */
#define    TMS_WA_RESTFUL_CURL_FAILED_INIT              (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 2)    /* CURL初始化失败 */
#define    TMS_WA_RESTFUL_CURL_URL_MALFORMAT            (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 3)    /* URL格式错误 */
#define    TMS_WA_RESTFUL_CURL_NOT_BUILT_IN             (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 4)    /* Curl未安装 */
#define    TMS_WA_RESTFUL_CURL_COULDNT_RESOLVE_PROXY    (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 5)    /* 代理解析失败 */
#define    TMS_WA_RESTFUL_CURL_COULDNT_RESOLVE_HOST     (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 6)    /* 解析主机失败 */
#define    TMS_WA_RESTFUL_CURL_COULDNT_CONNECT          (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 7)    /* 链接主机或代理失败 */
#define    TMS_WA_RESTFUL_CURL_FTP_WEIRD_SERVER_REPLY   (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 8)    /* 不确定的FTP服务器 */
#define    TMS_WA_RESTFUL_CURO_REMOTE_ACCESS_DENIED     (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 9)    /* 访问被拒绝 */
#define    TMS_WA_RESTFUL_CURL_HTTP_RETURNED_ERROR      (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 22)   /* 返回的错误代码> = 400 */
#define    TMS_WA_RESTFUL_CURL_OPERATION_TIMEDOUT       (TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + 28)   /* 超时 */



/* TMS_MAC_RestDataRecive回调函数所需的第四个参数 */
typedef struct tagTMSRecvDataInfo
{
    ULONG_32 ulBufferlen;        /* 返回信息的Buff长度 */
    ULONG_32 ulBufferOffset;    /* 返回信息开始位置 */
    char *pcBufferAddr;            /* 指向接收返回信息的Buffer */
}TMS_RECV_DATA_INFO_S;

/* 发送curl网络数据的结构体 */
typedef struct tagSendDataInfo
{
    /* 数据 */
    CHAR *pcData;

    /* 数据发送地址 */
    CHAR *pcPostData;

    /* 数据截止地址 */
    CHAR *pcLastData;
}TMS_SEND_DATA_INFO_S;


/**
* 解析返回值的函数样例 \n
* @return ULONG_32,
* - 成功:ERR_COMMON_SUCCEED
* - 失败:见错误码文件
* @note 无
*/
ULONG_32 TMS_RestParseReciveValue(char *pszRecvBuffer)
{

    cJSON *poReturnJson = cJSON_Parse(pszRecvBuffer);

    if (NULL == poReturnJson)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_SYS_FAIL,"Failed to batch insert MAC record,return NULL.");
        return ERR_COMMON_FAIL;
    }

    cJSON *oMsgJson = cJSON_GetObjectItem(poReturnJson, "msg");
    if (NULL == oMsgJson)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_SYS_FAIL,"Failed to batch insert MAC record,return NULL.");
        return ERR_COMMON_FAIL;
    }
    std::string oMsg = oMsgJson->valuestring;

    cJSON *oCodeJson = cJSON_GetObjectItem(poReturnJson, "code");   if (NULL == oCodeJson)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_SYS_FAIL,"Failed to batch insert MAC record,return NULL.");
        return ERR_COMMON_FAIL;
    }
    std::string oCode = oCodeJson->valuestring;

    /* REST接口状态码(0表示正常,1表示错误)*/
    if (TMS_WA_REST_RECV_CODE != oCode)
    {
        TMS_LOG1(IMOS_ERROR, ERR_COMMON_SYS_FAIL,"Failed to batch insert MAC record, err msg:%s.", oMsg.c_str());
        return ERR_COMMON_FAIL;
    }

    return ERR_COMMON_SUCCEED;
}

/**
* @class IMOS_TMS_REST
* @brief 通过libcurl 库的POST、GET、PUT、DELETE
*/
class IMOS_TMS_REST
{
public:
    IMOS_TMS_REST(std::string oUrl, TMS_METHOD_TYPE_E ulMethod, char *pcData, ULONG_32(*pfRestParseRecive)(char *)):
      m_oUrl(oUrl), m_ulMethod(ulMethod), m_pcData(pcData), m_pfRestParseRecive(pfRestParseRecive)
    {
        m_stCallBackDataInfo.ulBufferlen = TMS_WA_REST_RECV_LEN;
        m_stCallBackDataInfo.ulBufferOffset = 0;
        m_stCallBackDataInfo.pcBufferAddr = m_szRecvBuffer;
        memset(m_szRecvBuffer, 0,  TMS_WA_REST_RECV_LEN);
    }
          
    ~IMOS_TMS_REST() 
    {
      
    }

public:
    /**
    * 发送数据的public接口 \n
    * @return ULONG_32,
    * - 成功:ERR_COMMON_SUCCEED
    * - 失败:见错误码文件
    * @note 无
    */
    ULONG_32 send();

/* 类内工具函数 */
private:
    /**
    * REST接口回调函数
    * @param [IN] void* ptr         指向返回内容的指针
    * @param [IN] size_t size       返回内容单位字节数
    * @param [IN] size_t nmemb      返回内容个数
    * @param [IN][OUT] void *stream      输入自定义参数
    * @return size * nmemb          返回内容单位字节数与返回内容个数的乘积
    * @note 无
    */
    static SIZE_T IMOS_TMS_REST_DataRecive(IN VOID *ptr, IN SIZE_T size, IN SIZE_T nmemb, INOUT VOID *stream);

    /**
    *  restful接口 libcurl 发送数据函数
    * @param [in] VOID * pContents 发送到数据所在缓冲区
    * @param [in] ULONG_32 ulSize  数据长度
    * @param [in] ULONG_32 ulMemNum 返回内容个数
    * @param [in] VOID *pStream 用户自定义要写入的指针
    * @return ULONG_32 返回实际传出的数据实际大小
    * @note
    */
    static ULONG_32 TMS_ReadCallBack(IN VOID *pContents, IN ULONG_32 ulSize, IN ULONG_32 ulMemCount, OUT VOID *pStream);

    /**
    * 发送数据 \n
    * @return ULONG_32,
    * - 成功:ERR_COMMON_SUCCEED
    * - 失败:见错误码文件
    * @note 无
    */
    ULONG_32 IMOS_TMS_Send();
     
private:

    /* 构造回调函数所需的第四个参数 */
    TMS_RECV_DATA_INFO_S m_stCallBackDataInfo;

    /* 发送的数据 */
    char *m_pcData;

    /* URL */
    std::string m_oUrl;

    /* 传输方式 */
    ULONG_32 m_ulMethod;

    /* 存储接收返回信息的Buffer,注意大小 */
    char m_szRecvBuffer[TMS_WA_REST_RECV_LEN];

    /* 用来指向类外成员函数,用作返回值的解析 */
    ULONG_32(*m_pfRestParseRecive)(char *); 

};


/**
* REST接口批量写入终端特征移动采集设备轨迹信息到大数据public接口 \n
* @return ULONG_32,
* - 成功:ERR_COMMON_SUCCEED
* - 失败:见错误码文件
* @note 无
*/
ULONG_32 IMOS_TMS_REST::send()
{

    /* 发送数据 */
    ULONG_32 ulRet = IMOS_TMS_Send();
    if (ERR_COMMON_SUCCEED != ulRet)
    {
        TMS_LOG1(IMOS_ERROR, ERR_COMMON_SYS_FAIL,"Failed to batch insert MAC record, err code=%u.", ulRet);
        return ERR_COMMON_FAIL;
    }

    /* 解析REST接口返回值 */
    ulRet = m_pfRestParseRecive(m_szRecvBuffer);
    if (ERR_COMMON_SUCCEED != ulRet)
    {
        TMS_LOG0(IMOS_ERROR, ulRet, "Failed to batch insert MAC record.");
        return ERR_COMMON_FAIL;
    }

    return ERR_COMMON_SUCCEED;
}

/**
* REST接口回调函数
* @param [IN] void* ptr         指向返回内容的指针
* @param [IN] size_t size       返回内容单位字节数
* @param [IN] size_t nmemb      返回内容个数
* @param [IN][OUT] void *stream      输入自定义参数
* @return size * nmemb          返回内容单位字节数与返回内容个数的乘积
* @note 无
*/
SIZE_T IMOS_TMS_REST::IMOS_TMS_REST_DataRecive(IN VOID *ptr, IN SIZE_T size, IN SIZE_T nmemb, INOUT VOID *stream)
{
    /* 入参检测 */
    if ((NULL == ptr) || (NULL == stream))
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_INVALID_PARAM, "Failed: Invalid param.");
        return ERR_COMMON_FAIL;
    }

    /* 进行内存是否越界的判断 */
    TMS_RECV_DATA_INFO_S *pstRevcDataInfo = (TMS_RECV_DATA_INFO_S *)stream;
    ULONG_32 ulTotalBytes = size * nmemb;    

    if ((pstRevcDataInfo->ulBufferOffset + ulTotalBytes) >= pstRevcDataInfo->ulBufferlen)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_INVALID_PARAM, "Current data length greater data buffer lenth.");
        return ERR_COMMON_FAIL;
    }

    /* 进行内存拷贝 */
    memcpy(pstRevcDataInfo->pcBufferAddr + pstRevcDataInfo->ulBufferOffset, ptr, ulTotalBytes);
    pstRevcDataInfo->ulBufferOffset += ulTotalBytes;

    return ulTotalBytes;
}

/**
*  restful接口 libcurl 发送数据函数
* @param [in] VOID * pContents 发送到数据所在缓冲区
* @param [in] ULONG_32 ulSize  数据长度
* @param [in] ULONG_32 ulMemNum 返回内容个数
* @param [in] VOID *pStream 用户自定义要写入的指针
* @return ULONG_32 返回实际传出的数据实际大小
* @note
*/
ULONG_32 IMOS_TMS_REST::TMS_ReadCallBack
(
 IN VOID *pContents, 
 IN ULONG_32 ulSize, 
 IN ULONG_32 ulMemCount, 
 OUT VOID *pStream
 )
{
    ULONG_32 ulTotalBytes = 0;    
    TMS_SEND_DATA_INFO_S *pstSendDataInfo = (TMS_SEND_DATA_INFO_S *)pStream;
    /* 已发送完全 */
    if (pstSendDataInfo->pcPostData >= pstSendDataInfo->pcLastData)
    {
        return 0;
    }

    if ((0 == ulSize) || 
        (0 == ulMemCount) ||
        (ulSize * ulMemCount) < 1)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_INVALID_PARAM, "Send Data Error.");
        return 0;
    }

    ulTotalBytes = pstSendDataInfo->pcLastData - pstSendDataInfo->pcPostData;
    if (ulTotalBytes > (ulSize * ulMemCount))
    {
        ulTotalBytes = ulSize * ulMemCount;
    }

    memcpy(pContents, pstSendDataInfo->pcPostData, ulTotalBytes);
    pstSendDataInfo->pcPostData += ulTotalBytes;

    TMS_LOG1(IMOS_INFO, ERR_COMMON_SUCCEED, "Send Len = %u", ulTotalBytes);

    return ulTotalBytes;
}
/**
* 大数据中批量插入终端特征移动采集设备轨迹信息(Json数据) \n
* @return ULONG_32,
* - 成功:ERR_COMMON_SUCCEED
* - 失败:见错误码文件
* @note 无
*/
ULONG_32 IMOS_TMS_REST::IMOS_TMS_Send()
{
    if (NULL == m_pcData)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_INVALID_PARAM, "Failed: Invalid param m_poRoot");
        return ERR_COMMON_FAIL;
    }

    /* 构造CURL */
    CURL *poCurl = NULL;
    CURLcode ulRet = CURLE_OK;
    struct curl_slist *pstHttpHeader = NULL;

    /* 初始化CURL指针 */
    poCurl = curl_easy_init();
    if (NULL == poCurl)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to Rest curl_easy_init");
        return ERR_COMMON_FAIL;
    }

    /* 构造发送回调函数所需的参数 */
    TMS_SEND_DATA_INFO_S stSendDataInfo;
    memset(&stSendDataInfo, 0, sizeof(TMS_SEND_DATA_INFO_S));
    if (NULL != m_pcData)
    {
        stSendDataInfo.pcData = (CHAR *)m_pcData;
        stSendDataInfo.pcPostData = (CHAR *)m_pcData;
        stSendDataInfo.pcLastData = stSendDataInfo.pcPostData + strlen(m_pcData);
    }

    do
    {
        /* 设置传输超时时间       */
        ulRet = curl_easy_setopt(poCurl, CURLOPT_TIMEOUT, TMS_WA_REST_LIBCURL_OUT_TIME);
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_TIMOUT, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        /* 设置连接超时时间 */
        ulRet = curl_easy_setopt(poCurl, CURLOPT_CONNECTTIMEOUT, TMS_WA_REST_LIBCURL_CONNECT_OUT_TIME);
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CONNECT TIME OUT, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        /* 设置超时不产生信号 */
        ulRet = curl_easy_setopt(poCurl, CURLOPT_NOSIGNAL, 1L);
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_NOSIGNAL, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        switch (m_ulMethod)
        {
        case TMS_METHOD_DELETE:
            {
                /* 设置为DELETE请求 */
                ulRet = curl_easy_setopt(poCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
                break;
            }
        case TMS_METHOD_PUT:
            {
                /* 设置为PUT请求 */
                ulRet = curl_easy_setopt(poCurl, CURLOPT_PUT, 1);
                break;
            }
        case TMS_METHOD_GET:
            {
                /* 设置为GET请求 */
                ulRet = curl_easy_setopt(poCurl, CURLOPT_CUSTOMREQUEST, "GET");
                break;
            }
        default:
            {
                /* 设置为post请求 */
                ulRet = curl_easy_setopt(poCurl, CURLOPT_POST, 1);
                break;
            }
        }
 
        if (CURLE_OK != ulRet)
        {
            TMS_LOG2(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set Method(%u), enCurlRet = %d.", m_ulMethod, (ULONG_32)ulRet);
            break;
        }

        /* 设置post的url */
        ulRet = curl_easy_setopt(poCurl, CURLOPT_URL, m_oUrl.c_str());
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_URL, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        /* 设置http头信息 */
        std::string oRestHttpContentType = "Content-Type: ";
        oRestHttpContentType += TMS_WA_REST_HTTP_CONTENT_TYPE;
        pstHttpHeader = curl_slist_append(pstHttpHeader, oRestHttpContentType.c_str());
        if(NULL == pstHttpHeader)
        {
            TMS_LOG0(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call curl_slist_append, maybe out of memeroy.");
            break;
        }
        
        ulRet = curl_easy_setopt(poCurl, CURLOPT_HTTPHEADER, pstHttpHeader);
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_HTTPHEADER, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        /* 设置post的数据 */
        if (TMS_METHOD_POST == m_ulMethod)
        {
            /* 设置post的数据 */
            ulRet = curl_easy_setopt(poCurl, CURLOPT_POSTFIELDS, m_pcData);
            if (CURLE_OK != ulRet)
            {
                TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_POSTFIELDS, enCurlRet = %d.", (ULONG_32)ulRet);
                break;
            }
        }
        else if (TMS_METHOD_POST != m_ulMethod)
        {

            /* 设置PUT的数据 */
            ulRet = curl_easy_setopt(poCurl, CURLOPT_READFUNCTION, TMS_ReadCallBack);
            if (CURLE_OK != ulRet)
            {
                TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_READFUNCTION, enCurlRet = %d.", (ULONG_32)ulRet);
                break;
            }

            ulRet = curl_easy_setopt(poCurl, CURLOPT_UPLOAD, true);
            if (CURLE_OK != ulRet)
            {
                TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_UPLOAD, enCurlRet = %d.", (ULONG_32)ulRet);
                break;
            }

            ulRet = curl_easy_setopt(poCurl, CURLOPT_READDATA, &stSendDataInfo);
            if (CURLE_OK != ulRet)
            {
                TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_READDATA, enCurlRet = %d.", (ULONG_32)ulRet);
                break;
            }
            /* 当向服务器上传文件时,该选项用来告诉 curl 库期望上传的文件的大小 */
            ulRet = curl_easy_setopt(poCurl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)(stSendDataInfo.pcLastData - stSendDataInfo.pcPostData));
            if (CURLE_OK != ulRet)
            {
                TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_READDATA, enCurlRet = %d.", (ULONG_32)ulRet);
                break;
            }
        }
        else
        {
            /* 设置BODY为空 */
            ulRet = curl_easy_setopt(poCurl, CURLOPT_NOBODY, false);
            if (CURLE_OK  != ulRet)
            {
                TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_NOBODY, enCurlRet = %d.", (ULONG_32)ulRet);
                break;
            }
        }

        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set CURLOPT_POSTFIELDS, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        /* 设置post的回调函数 */
        ulRet = curl_easy_setopt(poCurl, CURLOPT_WRITEFUNCTION, IMOS_TMS_REST_DataRecive);
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set FuncCallBack, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        /* 设置post的返回包的处理函数的第四个参数 */
        ulRet = curl_easy_setopt(poCurl, CURLOPT_WRITEDATA, &m_stCallBackDataInfo);
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call set Param for FunCallBack, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }

        /* 完成请求 */
        ulRet = curl_easy_perform(poCurl);
        if (CURLE_OK != ulRet)
        {
            TMS_LOG1(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to curl_easy_perform, enCurlRet = %d.", (ULONG_32)ulRet);
            break;
        }
    } while (0);

    if(NULL != pstHttpHeader)
    {
        curl_slist_free_all(pstHttpHeader);
    }
    /* 结束会话 */
    curl_easy_cleanup(poCurl);

    if (CURLE_OK != ulRet)
    {
        TMS_LOG0(IMOS_ERROR, ERR_COMMON_FAIL, "Failed to call the REST ULONG_32erface!");
        return TMS_WA_RESTFUL_CURL_ERR_FAILED_BASE + ulRet;
    }

    return ERR_COMMON_SUCCEED;
}

ULONG_32 main()
{
    char ppp[48] = {"org@53935#201709111634158"};   
    std::string URL = "http://192.169.12.239:61005/VIID";
    TMS_METHOD_TYPE_E ulMethod = TMS_METHOD_POST;

    IMOS_TMS_REST fdf(URL, ulMethod, ppp, TMS_RestParseReciveValue );
    fdf.send();


    system("pause");
    return 0;
}
 

111

猜你喜欢

转载自www.cnblogs.com/liyubo/p/9092952.html