hpsocket的使用,实现http和websocket

首先,从 官网下载打包文件。
如果项目是32位+debug+unicode,则hpsocket的lib也要用对应版本。


image.png

头文件


image.png

include头文件

//hpsocket
#include "include/hpsocket/HPTypeDef.h"
#include "include/hpsocket/HPSocket4C-SSL.h"
#ifdef _DEBUG
#       pragma comment(lib, "include/hpsocket/lib/HPSocket4C_UD.lib")
#else
#       pragma comment(lib, "include/hpsocket/lib/HPSocket4C_U.lib")
#endif

.h

定义变量和回调函数

    HP_HttpClientListener m_HttpClientListener;
    HP_HttpClient m_HttpClient;

    static En_HP_HttpParseResult __stdcall OnHeader(HP_HttpClient pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue);
    static En_HP_HttpParseResult __stdcall OnHeadersComplete(HP_HttpClient pSender, CONNID dwConnID);
    static En_HP_HttpParseResult __stdcall OnUpgrade(HP_HttpClient pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType);
    static En_HP_HttpParseResult __stdcall OnBody(HP_HttpClient pSender, CONNID dwConnID, const BYTE* pData, int iLength);
    static En_HP_HttpParseResult __stdcall OnMessageComplete(HP_HttpClient pSender, CONNID dwConnID);
    static En_HP_HandleResult __stdcall OnClose(HP_Client pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode);
    static En_HP_HandleResult __stdcall OnWSMessageHeader(HP_HttpClient pSender, HP_CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen);
    static En_HP_HandleResult __stdcall OnWSMessageBody(HP_HttpClient pSender, HP_CONNID dwConnID, const BYTE* pData, int iLength);
    static En_HP_HandleResult __stdcall OnWSMessageComplete(HP_HttpClient pSender, HP_CONNID dwConnID);

.cpp

实现回调函数

//实现回调函数

EnHttpParseResult CFrameWnd::OnHeader(HP_HttpClient pSender, CONNID dwConnID, LPCSTR lpszName, LPCSTR lpszValue)
{
    printf("HP_Client:OnHeader-> %s: %s\n", lpszName, lpszValue);
    //::PostOnHeader(dwConnID, lpszName, lpszValue);
    return HPR_OK;
}
EnHttpParseResult CFrameWnd::OnHeadersComplete(HP_HttpClient pSender, CONNID dwConnID)
{
    printf("HP_Client:OnHeadersComplete\n");
    return HPR_OK;
}

EnHttpParseResult CFrameWnd::OnUpgrade(HP_HttpClient pSender, CONNID dwConnID, EnHttpUpgradeType enUpgradeType)
{
    printf("HP_Client:OnUpgrade\n");
    /*
    if (enUpgradeType == HUT_WEB_SOCKET)
    {
        m_spThis->m_bWebSocket = TRUE;
        m_spThis->OnCbnSelchangeMethod();
    }
    */

    return HPR_OK;
}

//pData指向的缓冲区很大,并且是重复利用,不会用\0结尾,需要自己根据长度拷贝过去
EnHttpParseResult CFrameWnd::OnBody(HP_HttpClient pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
    printf("HP_Client::OnBody %d bytes\n", iLength);

    BYTE* p = new BYTE[iLength + 1];
    memset(p, '\0', iLength + 1);
    memcpy(p, pData, iLength);
    string str = StringParse::UTF8ToGB((char*)p);
    printf("p_res:%s\n", str.c_str());

    //::PostOnBody(dwConnID, pData, iLength);
    return HPR_OK;
}


EnHttpParseResult CFrameWnd::OnMessageComplete(HP_HttpClient pSender, CONNID dwConnID)
{
    return HPR_OK;
}

EnHandleResult CFrameWnd::OnClose(HP_Client pSender, CONNID dwConnID, EnSocketOperation enOperation, int iErrorCode)
{
    printf("HP_Client:OnClose\n");
    return HR_OK;
}


EnHandleResult CFrameWnd::OnWSMessageHeader(HP_HttpClient pSender, CONNID dwConnID, BOOL bFinal, BYTE iReserved, BYTE iOperationCode, const BYTE lpszMask[4], ULONGLONG ullBodyLen)
{
    printf("HP_Client:OnWSMessageHeader\n");
    return HR_OK;
}

EnHandleResult CFrameWnd::OnWSMessageBody(HP_HttpClient pSender, CONNID dwConnID, const BYTE* pData, int iLength)
{
    //::PostOnWSMessageBody(dwConnID, pData, iLength);

    printf("HP_Client::OnWSMessageBody %d bytes\n", iLength);

    BYTE* p = new BYTE[iLength+1];
    memset(p, '\0', iLength+1);
    memcpy(p, pData, iLength);
    string str = StringParse::UTF8ToGB((char*)p);
    printf("str:%s\n", str.c_str());

    return HR_OK;
}

EnHandleResult CFrameWnd::OnWSMessageComplete(HP_HttpClient pSender, CONNID dwConnID)
{
    printf("HP_Client:OnWSMessageComplete\n");
    //::PostOnWSMessageComplete(dwConnID);

    BYTE iOperationCode;

    ASSERT(::HP_HttpClient_GetWSMessageState(pSender, nullptr, nullptr, &iOperationCode, nullptr, nullptr, nullptr));

    if (iOperationCode == 0x8)
        return HR_ERROR;

    return HR_OK;
}

.cpp中处理逻辑,实现http功能和wss功能

//初始化
void CFrameWnd::InitHp() {
    // 加载 Cookie
    ::HP_HttpCookie_MGR_LoadFromFile(DEFAULT_COOKIE_FILE, FALSE);

    // 创建监听器
    m_HttpClientListener = ::Create_HP_HttpClientListener();


    ::HP_Set_FN_HttpClient_OnHeader(m_HttpClientListener, OnHeader);
    //这4个是强制必须设置的回调函数
    ::HP_Set_FN_HttpClient_OnHeadersComplete(m_HttpClientListener, OnHeadersComplete);
    ::HP_Set_FN_HttpClient_OnBody(m_HttpClientListener, OnBody);
    ::HP_Set_FN_HttpClient_OnMessageComplete(m_HttpClientListener, OnMessageComplete);
    ::HP_Set_FN_HttpClient_OnClose(m_HttpClientListener, OnClose);

    //::HP_Set_FN_HttpClient_OnPullReceive(m_HttpClientListener, OnPullReceive);
    //::HP_Set_FN_HttpClient_OnConnect(m_HttpClientListener, OnConnect);
    //::HP_Set_FN_HttpClient_OnRequest(m_HttpClientListener, OnRequest);
    //::HP_Set_FN_HttpClient_OnBody(m_HttpClientListener, OnBody);
        
        //ws要用到的回调函数
    ::HP_Set_FN_HttpClient_OnUpgrade(m_HttpClientListener, OnUpgrade);
    ::HP_Set_FN_HttpClient_OnWSMessageHeader(m_HttpClientListener, OnWSMessageHeader);
    ::HP_Set_FN_HttpClient_OnWSMessageBody(m_HttpClientListener, OnWSMessageBody);
    //::HP_Set_FN_HttpClient_OnDisconnect(m_HttpClientListener, OnDisconnect);  
}

//http实现方式1
void CFrameWnd::httpSync(){
    HP_HttpClientListener m_hListener = nullptr;
    HP_HttpsSyncClient m_pHttpsClient = nullptr;
    std::string syggurl = "https://www.baidu.com/";
    m_pHttpsClient = Create_HP_HttpsSyncClient(m_hListener);
    HP_HttpSyncClient_SetConnectTimeout(m_pHttpsClient, 30000);
    HP_HttpSyncClient_SetRequestTimeout(m_pHttpsClient, 30000);
    HP_TcpClient_SetSocketBufferSize(m_pHttpsClient, 4 * 1024 * 1024);
    HP_SSLClient_SetupSSLContext(m_pHttpsClient, SSL_SM_CLIENT, NULL, NULL, NULL, NULL);
    HP_HttpSyncClient_OpenUrl(m_pHttpsClient, "GET", syggurl.c_str(), nullptr, 0, nullptr, 0, FALSE);
    LPCBYTE __resp_body_ptr = nullptr;
    int ibytelen = 0;
    char* p_Gbk = nullptr;
    std::string p_res;
    if (!HP_HttpSyncClient_GetResponseBody(m_pHttpsClient, &__resp_body_ptr, &ibytelen)) {
        return ;
    }
    p_res = StringParse::UTF8ToGB((char*)__resp_body_ptr);
    std::cout << p_res << std::endl;
}

//http实现方式2
void CFrameWnd::http() {
    bool succ = false;

    //初始化ssl
    bool isHttp = false;

    if (isHttp) {
        m_HttpClient = ::Create_HP_HttpClient(m_HttpClientListener);
        succ = ::HP_Client_Start(m_HttpClient, L"www.taokemiao.com", 80, FALSE);
    }
    else {
        m_HttpClient = ::Create_HP_HttpsClient(m_HttpClientListener);

        //succ = HP_SSLClient_SetupSSLContext(m_HttpClient, SSL_VM_NONE, cert_path.c_str(), key_path.c_str(), nullptr, nullptr);
        succ = HP_SSLClient_SetupSSLContext(m_HttpClient, SSL_SM_CLIENT, NULL, NULL, NULL, NULL);
        printf("HP_SSLClient_SetupSSLContext:%d\n", (int)succ);
        succ = ::HP_Client_Start(m_HttpClient, L"www.gmiao.com", 443, FALSE);
        printf("HP_Client_Start:%d\n", (int)succ);
        Sleep(1000);//ssl连接网站需要时间
    }


    THeader header[] = { {"Content-Type", "text/html"}/*,{"Host","www.gmiao.com:443"}*/};
    int iHeaderCount = sizeof(header) / sizeof(THeader);
    //succ = HP_HttpClient_SendRequest(m_HttpClient, "GET", "/", header, iHeaderCount, NULL, 0);
    //printf("HP_HttpClient_SendRequest:%d\n", (int)succ);
     
    
    //发送请求
    succ = HP_HttpClient_SendGet(m_HttpClient, "/", header, iHeaderCount);
    printf("HP_HttpClient_SendGet:%d\n", (int)succ);
}

//websocket功能实现
void CFrameWnd::wss() {
    bool succ = false;

    std::string key = "dGhlIHNhbXBsZSBub25jZQ==";  // 生成随机的Sec-WebSocket-Key

    m_HttpClient = ::Create_HP_HttpsClient(m_HttpClientListener);
    succ = HP_SSLClient_SetupSSLContext(m_HttpClient, SSL_SM_CLIENT, NULL, NULL, NULL, NULL);
    printf("HP_SSLClient_SetupSSLContext:%d\n", (int)succ);
    succ = ::HP_Client_Start(m_HttpClient, L"echo.websocket.org", 443, FALSE);
    printf("HP_Client_Start:%d\n", (int)succ);
    Sleep(1000);//ssl连接需要时间

    THeader header[] = { {"Upgrade", "websocket"}, {"Connection", "Upgrade"}, {"Sec-WebSocket-Key", key.c_str()}, {"Sec-WebSocket-Version", "13"}};
    int iHeaderCount = sizeof(header) / sizeof(THeader);

    //发送请求,告诉服务器把【此连接】从http协议升级为wss协议
    succ = HP_HttpClient_SendGet(m_HttpClient, "/", header, iHeaderCount);
    printf("HP_HttpClient_SendGet:%d\n", (int)succ);

    Sleep(3000);//等待服务器返回Upgrade: websocket
    //发送ws消息
    static const BYTE MASK_KEY[] = { 0x1, 0x2, 0x3, 0x4 };
    string data = "hello";
    succ = ::HP_HttpClient_SendWSMessage(m_HttpClient, TRUE, 0, 0x1, MASK_KEY, (BYTE*)data.c_str(), data.size(), data.size());
    printf("HP_HttpClient_SendWSMessage:%d\n", (int)succ);
    
}




websocket原理:
1,client_start连接服务器host并返回连接
2,用http get方式通过此返回的连接发送HEADER{ upgrade: websocket, connection: Upgrade,Sec-WebSocket-Key:xxxx},告诉服务器把此连接从http协议升级为websocket协议,
3、服务器会返回upgrade:websocket和sec-websocket-accept的header,如果收到这个表示现在已经升级为websocket连接
4、可以用HP_HttpClient_SendWSMessage给服务器发送websocket消息了

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容