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

  • 相关阅读:
    Java运行时数据区域
    线程的实现原理
    redis分布式锁的实现
    Incorrect string value: 'xF0x9Fx92x8BTi...'错误
    linux命令之less命令
    Hive数据类型和DDL操作
    Hive安装、配置和使用
    CentOS 7安装配置MySQL 5.7
    Spring+SpringMVC+MyBatis整合
    MyBatis的事物管理和缓存
  • 原文地址:https://www.cnblogs.com/hanframe/p/4241983.html
Copyright © 2020-2023  润新知