• 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
    ");
            return ;
        }
        return ;
    
    }
    
    int CHTTPParse::SendHttpPost(const char* url,const char* pData)
    {
        CURLcode code;
            
        TRACESVR_DEBUG("Http Data[%s]
    ",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]
    ", 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]
    ", code);
            return -3 ;
        }
         code =curl_easy_setopt(m_pCurlHandlder, CURLOPT_POSTFIELDS, pData);
        if (code != CURLE_OK)
        {
            TRACESVR("Failed to PostFields=%s, [code=%d]
    ",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 
    ", ct);
            }
        }
        else
        {
            TRACESVR("curl_easy_perform Error
    ");
        }
        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);

  • 相关阅读:
    Codeforces Round #592 (Div. 2)C. The Football Season(暴力,循环节)
    Educational Codeforces Round 72 (Rated for Div. 2)D. Coloring Edges(想法)
    扩展KMP
    poj 1699 Best Sequence(dfs)
    KMP(思路分析)
    poj 1950 Dessert(dfs)
    poj 3278 Catch That Cow(BFS)
    素数环(回溯)
    sort与qsort
    poj 1952 buy low buy lower(DP)
  • 原文地址:https://www.cnblogs.com/hanframe/p/4241983.html
Copyright © 2020-2023  润新知