c++利用jsoncpp libcurl 构造http 包(原)

我们手游要接入uc九游进行测试,要用http向uc那边的sdk 服务器post  json数据。

虽然他们提供了php,java还有c#的服务端demo,但是我们服务器是C++写的,我实在不想中间再转一层。

于是查了一些资料,发现libcurl可以用在c++里用来构造http包,然后json可以用jsoncpp这个开源api来整合,于是就直接开干!

 

1.下载libcurl http://curl.haxx.se/download/curl-7.40.0.zip

 

2.下载jsoncpp https://github.com/open-source-parsers/jsoncpp

 

3.实现一个http线程,接收主线程推送过来的消息,并转化为json数据,并post到目标地址,在回调里获取到返回数据。

具体实现代码

HttpParse.h

#ifndef HttpParse_h__
#define HttpParse_h__

#include <curl/curl.h>
#include <string.h>
#include <string>
#include "ConfigHelper.hpp"

#include "CodeQueue.hpp"
#include "Thread.hpp"
#include "TypesDefine.hpp"
#include "NowTime.hpp"
#include "StrStream.hpp"

using namespace std;
using namespace KylinLib;


struct stHttpData
{
    enum actiontype
    {
        uc_login = 1,        // 登陆
        uc_recharge = 2,    // 充值
        uc_extend = 3,        // 扩展数据
    };

    actiontype action;                //动作id,登录?注册?
    unsigned int uiUin;                //QQ号
    int iWorldid;                    //区id
    int iLoginWay;                    //登录来源
    int iChangeValue;                //变化值
    stHttpData()
    {
        memset(this,0,sizeof(*this) );
    }
};

class CHTTPParse
{
    CCodeQueue* m_pDataQueue;
    CURL* m_pCurlHandlder;
public:
    //enum {appID = 90010006,};
    enum {appID = 100705924,};
    CHTTPParse();
    ~CHTTPParse();

    // 增加http数据
    void AddOneHttpData(stHttpData::actiontype actType, unsigned int uiUin, int worldID, int changeValue = 0, int loginWay = 0);

    // 发送数据
    int ProcessMsgSend();

    static size_t OnWriteData(void* buffer, size_t size, size_t nmemb, void* lpVoid); 

private:
    // 初始化
    void Init();

    //Curl 初始化
    void  CurlInit();

    //UC登录
    int UCLogin(const char* szSid, const char* szAccount);

    //UC充值
    int UCRecharge(unsigned int Roleid, int iWorldid, const char* szAccount, int iRechargeNum);

    //UC扩展数据
    int UCSendExtend();

    //发送数据
    int SendHttpPost(const char* url,const char* pData);
};

//处理http交互的线程

class CHTTPParseThread : public CThread
{
    int m_iIsToBeBlocked;

public:
    CHTTPParseThread();
public:
    virtual int PrepareToRun()
    {
        return 0;
    }
    virtual int Run() ;

    virtual int IsToBeBlocked() 
    {
        return m_iIsToBeBlocked;
    }
    void SetBlockedStatus(int iStatus)
    {
        m_iIsToBeBlocked = iStatus;
    }
};

#define CHTTPParseMgr  CSingleton<CHTTPParse>::Instance()

#endif // HttpParse_h__

 

// HttpParse.cpp

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <json/config.h>
#include <json/json.h>

#include "HttpParse.hpp"
#include "LogAdapter.hpp"

#define  LUOPANGAPPID 100658092 

#define DoSend(host, stat, data) \
    CStrStream1024 strHttp; \
    strHttp << "http://" \
    << host \
    << "/" \
    << stat; \
    return SendHttpPost(strHttp.GetStr(), data);

#define InitNet() CurlInit()

CHTTPParseThread::CHTTPParseThread()
{
    m_iIsToBeBlocked =1;
}

// 注册 登录 支付
int CHTTPParseThread::Run()
{

    while(true)
    {
        if (m_iRunStatus == rt_stopped)
        {
            break;
        }
        
        int iNewMsgCount = 0;
        
        while(true)
        {
            int iRet = CHTTPParseMgr->ProcessMsgSend();
            if (iRet ==0)
            {
                iNewMsgCount++;
            }
            else
            {
                break;
            }
        }

        if (iNewMsgCount ==0)
        {        
            usleep(1000*10); //1毫秒
        }
        
    }
    return 0;
}

CHTTPParse::CHTTPParse()
{
    m_pDataQueue =NULL;
    m_pCurlHandlder = NULL;
    Init();
}
CHTTPParse::~CHTTPParse()
{
    if (m_pCurlHandlder)
    {    
        curl_easy_cleanup(m_pCurlHandlder);
    }
    curl_global_cleanup();      

}

// 增加上报数据
void CHTTPParse::AddOneHttpData(stHttpData::actiontype actType, unsigned int uiUin, int worldID, int changeValue /* = 0 */, int loginWay /* = 0 */)
{
    if (NULL == m_pDataQueue)
    {
        return;
    }
    stHttpData lplData;
    lplData.action = actType;
    lplData.uiUin = uiUin;
    lplData.iWorldid = worldID;
    lplData.iChangeValue = changeValue;
    lplData.iLoginWay = loginWay;
    m_pDataQueue->PushOneCode( (const unsigned char*)&lplData,sizeof(lplData) );
}

int CHTTPParse::ProcessMsgSend()
{
    if (m_pDataQueue)
    {
        stHttpData stData;
        int iCodelen;
        m_pDataQueue->PopOneCode((unsigned char*)&stData,sizeof(stData),iCodelen);        

        if ( iCodelen == sizeof(stData) )
        {        
            switch (stData.action)
            {
            case stHttpData::uc_login:  //登录
                return UCLogin("test", "account1234");
                break;
            case stHttpData::uc_recharge: //注册
                return UCRecharge(1, 2, "account1234", 4);
                break;
            case stHttpData::uc_extend:  //扩展
                return UCSendExtend();
                break;
            }
        }
        else
        {
            return -2;
        }
    }
    return -2;
}

size_t CHTTPParse::OnWriteData( void* buffer, size_t size, size_t nmemb, void* lpVoid )
{
    std::string* str = dynamic_cast<std::string*>((std::string *)lpVoid);  
    if( NULL == str || NULL == buffer )  
    {  
        return -1;  
    }  

    char* pData = (char*)buffer;  
    str->append(pData, size * nmemb);  
    return nmemb;   
}

void CHTTPParse::Init()
{
    //创建一个环形缓存队列来进行线程同步
    m_pDataQueue = new CCodeQueue(1024*100); //100K足够了吧
    if (m_pDataQueue)
    {
        m_pDataQueue->Initialize();
    }

    InitNet();
}

void  CHTTPParse::CurlInit()
{
    curl_global_init(CURL_GLOBAL_ALL);     

    m_pCurlHandlder = curl_easy_init();
    if (m_pCurlHandlder == NULL)
    {
        TRACESVR( "Failed to create CURL connection\n");
        return ;
    }
    return ;

}

int CHTTPParse::SendHttpPost(const char* url,const char* pData)
{
    CURLcode code;
        
    TRACESVR_DEBUG("Http Data[%s]\n",pData);
    if (NULL == m_pCurlHandlder)
    {
        return -1;
    }
    code =curl_easy_setopt(m_pCurlHandlder, CURLOPT_NOSIGNAL, 1L);
    if (code !=CURLE_OK)
    {
        TRACESVR("Failed to set URL [%d]\n", code);
        return -2 ;
    }

    //设置超时  
    curl_easy_setopt(m_pCurlHandlder, CURLOPT_TIMEOUT, 1); 
    //curl_easy_setopt(m_pCurlHandlder, CURLOPT_CONNECTTIMEOUT, 3); 

    //设置method为post
    //curl_easy_setopt(m_pCurlHandlder, CURLOPT_POST, 1);
    curl_easy_setopt(m_pCurlHandlder, CURLOPT_VERBOSE, 1L);
    curl_slist *http_headers = NULL;
    http_headers = curl_slist_append(http_headers, "Accept: application/json");
    http_headers = curl_slist_append(http_headers, "Content-Type: application/json");
    http_headers = curl_slist_append(http_headers, "charsets: utf-8");
    curl_easy_setopt(m_pCurlHandlder, CURLOPT_CUSTOMREQUEST, "POST");
    code = curl_easy_setopt(m_pCurlHandlder, CURLOPT_HTTPHEADER, http_headers);

    code = curl_easy_setopt(m_pCurlHandlder, CURLOPT_URL, "http://192.168.1.166/sdkdemo/restful/dispatch.php?do=cp/account.verifySession");
    if (code != CURLE_OK)
    {
        TRACESVR("Failed to set URL [%d]\n", code);
        return -3 ;
    }
     code =curl_easy_setopt(m_pCurlHandlder, CURLOPT_POSTFIELDS, pData);
    if (code != CURLE_OK)
    {
        TRACESVR("Failed to PostFields=%s, [code=%d]\n",pData, code);
        return -4;
    }
    code =curl_easy_setopt(m_pCurlHandlder, CURLOPT_WRITEFUNCTION, CHTTPParse::OnWriteData);
    string strResp;
    code =curl_easy_setopt(m_pCurlHandlder, CURLOPT_WRITEDATA, (void *)&strResp); 
    curl_easy_setopt(m_pCurlHandlder, CURLOPT_SSL_VERIFYPEER, false);
    curl_easy_setopt(m_pCurlHandlder, CURLOPT_SSL_VERIFYHOST, false);
    curl_easy_setopt(m_pCurlHandlder,CURLOPT_FOLLOWLOCATION,1);

    code = curl_easy_perform(m_pCurlHandlder);
    if(CURLE_OK == code)
    {
        char *ct =NULL;

        code = curl_easy_getinfo(m_pCurlHandlder, CURLINFO_CONTENT_TYPE, &ct);

        if((CURLE_OK == code) && ct)
        {
            TRACESVR("We received Content-Type: %s \n", ct);
        }
    }
    else
    {
        TRACESVR("curl_easy_perform Error\n");
    }
    curl_easy_cleanup(m_pCurlHandlder); 

    return 0;
}

int CHTTPParse::UCLogin(const char* szSid, const char* szAccount)
{
    Json::Value root;
    // id
    root["id"] = GETNOWTIMEUS;

    // service
    root["service"] = "account.verifySession";

    Json::Value gameid;
    gameid["gameId"] = 123456;
    root["game"] = gameid;

    Json::Value sid;
    sid["sid"] = "eeeeettttttt555444";
    root["data"] = sid;

    // encrypt
    root["encrypt"] = "md5";

    // sign
    root["sign"] = "cce4cef6ea157f411932f9651555836e";

    Json::FastWriter writer;  
    std::string strWrite = writer.write(root);

    DoSend("192.168.1.166", "sdkdemo/restful/dispatch.php?do=cp/account.verifySession", strWrite.c_str());
}
// 其他函数还没调试,就不贴出来了

 

注意事项

1.设置http post数据格式和accept格式

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

 

2.json数据如果有问题,会直接报 500 internal server erro 的错误,其实就是json的数据格式不对。最好填充完,用工具检测一下json字符串是否合法

 

3.jsoncpp中要用 Json::FastWriter将json Value类型格式化,如下代码中的strWrite 就是json格式的字符串(需要post的数据),而不是调用asString()进行转化,后者会导致程序直接崩溃。

Json::FastWriter writer;  
    std::string strWrite = writer.write(root);

 

posted @ 2015-01-22 16:08  hanframe  阅读(5168)  评论(0编辑  收藏  举报