zoukankan      html  css  js  c++  java
  • 一个封装HTTP请求的函数(C++)

    这里封装了HTTP请求的,支持GET与POST,并支持各种参数组合,调用方式很简单
    使用DEVWEB::WebRequest(string(“http://www.luaie.com/”),ret);就可以了
    如果使用POST需要填冲RequestParam参数结构,具体可以参考以下代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    namespace DEVWEB
    {
        struct ACloseSkt
        {
            ACloseSkt(SOCKET h)
            {
                m_h = h;
            }
            ~ACloseSkt()
            {
                if(m_h)
                    closesocket(m_h);
                m_h = 0;
            }
            SOCKET m_h;
        };
        struct RequestParam
        {
            bool            bPost;      //是否为POST请求
            const char*     pPostData;  //为POST数据,需要自已维护内存;
            unsigned int    uiPostLen;  //为POST数据长度,主要为了兼容可以上传二进制数据,一般请求就为pPostData字符串长度
            const char*     pReferer;   //请求的引用页面,就是来源页面
            const char*     pAttachHeader;//附加自定义头
            bool            bBlock;     //true=阻塞式连接,false=异步连接,*******注意:使用异步必须设置超时时间
            unsigned int    uiTimeout;  //异步超时 单位ms
            RequestParam(){
                memset(this,0, sizeof(RequestParam));
                bBlock = true; bPost = false;
            }
        };
        void GetRealIP(string& ip, string& retip)
        {
            retip = ip;
            unsigned long t = inet_addr((char*)(LPCSTR)ip.c_str());
            if (t == INADDR_NONE)
            {
                hostent* hostInfo = gethostbyname((char*)(LPCSTR)ip.c_str());
                if (hostInfo)
                {
                    struct in_addr *addr;
                    addr = (struct in_addr*)hostInfo->h_addr_list[0];
                    if(addr!=NULL)
                    {
                        retip = inet_ntoa(*addr);
                    }
                }else{
                    TRACE1("GetRealIP can't parse domain %s ",ip.c_str());
                }
            }
        }
        //////////////////////////////////////////////////////////////////////////
        //szURL 一个完整的URL仅HTTP,HTTPS不支持,可以包含GET参数,如index.php?username=test
        //response 为请求返回的结果,包含HTTP头信息
        //pRP为附加参数,完成更复杂的请求
        ///////////////////////////////////////////////////////////////////////////
        bool WebRequest( const char* szURL, std::string& response, RequestParam* pRP = 0)
        {
            if (!szURL ) return false;
            SOCKET hSkt = socket(AF_INET,SOCK_STREAM,0);
            if (INVALID_SOCKET == hSkt){ OutputDebugString("WebRequest socket create failed! ");return false;}
            ACloseSkt askt(hSkt);
            //是否设置为异步
            if ( pRP && pRP->bBlock == false)
            {
                ULONG nMode = 1;
                ioctlsocket( hSkt,FIONBIO,&nMode);
            }
            string strURL(szURL),host,ip,requrl;
            unsigned int nport = 80;
            if ( stricmp(string(strURL.substr(0,7)).c_str(), "http://") )
            {
                OutputDebugString("WebRequest parse url error, need http:// ");
                return false;
            }else//parse url;
                size_t nMH = strURL.find(':',8);
                size_t nPre =strURL.find('/',8);
                if ( nMH == -1 && nPre == -1)
                {
                    host    = strURL.substr(7);
                    requrl  = "/";
                }else if ( nPre != -1){
                    if ( nMH != -1 && nPre > nMH){
                        host = strURL.substr(7,nMH-7);
                        nport = atoi( string(strURL.substr(nMH+1, nPre-1-nMH)).c_str());
                    }else{
                        host = strURL.substr(7,nPre-7);
                    }
                    requrl = strURL.substr(nPre);
                }else if (nMH != -1){
                    host = strURL.substr(7, nMH-7);
                    nport= atoi( string(strURL.substr(nMH+1)).c_str());
                    requrl = "/";
                }
            }
            GetRealIP(host,ip);
            sockaddr_in addr;
            addr.sin_addr.S_un.S_addr = inet_addr( ip.c_str() );
            addr.sin_port = htons(nport);
            addr.sin_family = AF_INET;
            if (pRP && pRP->bBlock)
            {
                if (SOCKET_ERROR == connect( hSkt, (sockaddr*)&addr,sizeof(addr)))
                {
                    OutputDebugString("WebRequest connect server failed! ");
                    return false;
                }
            }else{
                if (SOCKET_ERROR == connect( hSkt, (sockaddr*)&addr, sizeof(addr)))
                {
                    if ( WSAGetLastError() == 10035 )
                    {
                        //connectioning
                    }else{
                        OutputDebugString("WebRequest connect server failed! ");
                        return false;
                    }
                }
                DWORD dwTick = GetTickCount();
                do{
                    fd_set    Set,WSet;
                    FD_ZERO(&Set);
                    FD_ZERO(&WSet);
                    FD_SET(hSkt,&Set);
                    FD_SET(hSkt,&WSet);
                    timeval time;
                    time.tv_sec = 0;
                    time.tv_usec = 0;
                    int nS = select(0, &Set, &WSet, NULL, &time);
                    if( nS == SOCKET_ERROR )
                    {
                        OutputDebugString("WebRequest connect server failed!(SELECT) ");
                        return false;
                    }else if(nS){
                        break;//connect sucess.
                    }else{
                        if ( (GetTickCount() - dwTick) > pRP->uiTimeout )
                        {
                            //timeout
                            OutputDebugString("WebRequest connect server timeout!(SELECT) ");
                            return false;
                        }
                    }
                }while(true);
            }
            //fill header;
            string header;
            bool bSendBin = false;
            if (pRP)
            {
                header.append( pRP->bPost ? "POST " : "GET ");
                header.append(requrl);
                header.append(" HTTP/1.1 ");
                header.append("host:");
                header.append(host);
                header.append(" User-Agent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) ");
                header.append("Content-Type:application/x-www-form-urlencoded ");
                header.append("Accept:text/html,application/xhtml+xml,*/* Connection:close ");
                char szCSize[50];
                sprintf(szCSize,"Content-Length:%d ",pRP->uiPostLen);
                header.append(szCSize);
                if (pRP->pPostData){
                    if ( strlen(pRP->pPostData) <= pRP->uiPostLen){
                        bSendBin = true;
                    }else{
                        header.append(pRP->pPostData);
                    }
                }
            }else{
                header.append("GET ");
                header.append(requrl);
                header.append(" HTTP/1.1 ");
                header.append("host:");
                header.append(host);
                header.append(" User-Agent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) ");
                header.append("Content-Type:application/x-www-form-urlencoded ");
                header.append("Accept:text/html,application/xhtml+xml,*/* Connection:close ");
            }
            size_t headerlen = header.size();
            size_t nSendLen = 0;
            const char* pdata = header.c_str();
            DWORD dwTick = GetTickCount();
            do
            {
                int n = send(hSkt, pdata + nSendLen, int(headerlen - nSendLen),0);
                if( n == SOCKET_ERROR ){
                    if ( 10035 == WSAGetLastError())
                    {
                        //wait for send.
                        if (pRP && GetTickCount() - dwTick >= pRP->uiTimeout)
                        {
                            OutputDebugString("WebRequest send failed! ");
                            return false;
                        }
                        Sleep(10);
                    }else{
                        OutputDebugString("WebRequest send failed! ");
                        return false;
                    }
                }else if( n==0)
                {
                    OutputDebugString("WebRequest send failed! ");
                    return false;
                    break;
                }else{
                    dwTick = GetTickCount();
                    nSendLen += n;
                }
            } while (nSendLen < headerlen );
            if(bSendBin && pRP && pRP->pPostData && pRP->uiPostLen)
            {
                nSendLen = 0;
                pdata = (const char*) pRP->pPostData;
                dwTick = GetTickCount();
                do
                {
                    int n = send(hSkt, pdata + nSendLen, pRP->uiPostLen - nSendLen,0);
                    if( n == SOCKET_ERROR ){
                        if ( 10035 == WSAGetLastError())
                        {
                            //wait for send.
                            if (pRP && GetTickCount() - dwTick >= pRP->uiTimeout)
                            {
                                OutputDebugString("WebRequest send timeout! ");
                                return false;
                            }
                            Sleep(10);
                        }else{
                            OutputDebugString("WebRequest send failed! ");
                            return false;
                        }
                    }else if( n==0)
                    {
                        OutputDebugString("WebRequest send failed! ");
                        return false;
                        break;
                    }else{
                        dwTick = GetTickCount();
                        nSendLen += n;
                    }
                } while (nSendLen < pRP->uiPostLen );
            }
            //recv response
            char    buf[2049];
            string& request = response;
            request.clear();
            dwTick = GetTickCount();
            do
            {
                int n = recv(hSkt, buf,2048,0);
                if ( n == SOCKET_ERROR )
                {
                    if ( 10035 != WSAGetLastError() )
                    {
                        OutputDebugString("DevWebService recv failed! ");
                        return 0;
                        break;
                    }else{
                        if (pRP && GetTickCount() - dwTick >= pRP->uiTimeout){
                            OutputDebugString("WebRequest recv timeout! ");
                            return false;
                        }
                        Sleep(10);
                    }
                }else if( n == 0 ){
                    //host close recv finish
                    OutputDebugString("WebRequest Recv FINISHED! ");
                    break;
                }else{
                    buf[n] = '';
                    request.append(buf);    dwTick = GetTickCount();
                }
            } while (true);
            return true;
        }
    }
    //test code
        string rs;
        char post[80];sprintf(post,"username=xj&userpassword=123456");
        DEVWEB::RequestParam rp;
        rp.bPost = true;
        rp.pPostData = post;
        rp.uiPostLen = strlen(post);
        if ( DEVWEB::WebRequest( "http://www.paobuke.com/wp-login.php", rs,&rp))
        {
            AfxMessageBox( rs.c_str());
        }
     
     

    近期一位朋友想写iOS上的应用,打算从微博应用做起,第一步先做一个微博客户端出来,然后做一个手机微博应用出来,具体做什么还不甚清楚,其实是在尝试中。而我正好在用asio写网络库,于是主动提出了承担web服务器网络库的部分,也是为了给我自己封装的网络库中增加一个http模块。

    http大家都不陌生,每天打开网页,地址栏前大多数显示的都是http,当然还有https等等,以前跟rangerlee讨论curl的时候有说过post和get,不是很清楚,查阅了众多文章和资料,有点小懂了。

    统一资源定位符(URL,英语 Uniform / Universal Resource Locator 的缩写)也被称为网页地址,是因特网上标准的资源的地址(Address)。其实URL就是代表一个特定地址的因特网标准资源URI。http请求中的get post put delete就是对这个资源进行 查 增 改 删 ,有点类似于数据库中的四大操作。get和post最主要的区别是前者是查询,后者是修改,get类似于C++中const函数,而post类似于set或者add函数。

    原理:

    GET

    根据HTTP标准,GET用于信息的获取,并且是安全和幂等的。

    安全:GET操作用于获取信息/资源,并非修改信息/资源。主要表现在不能修改信息。

    幂等:这是一个数学/计算机上的概念。对于单目运算来说,如果一次运算和多次运算的结果是一样的,则该运算是幂等的,例如:C++中的abs(abs(a)) = abs(a),所以abs函数运算就是幂等的;对于双目运算,两个相等的参与运算的值在运算之后的结果仍然等于这个值,则该运算是幂等的,例如:C++中的max(a, a) = a,所以max函数的幂等的。

    而GET是在同一个地址下获取到的资源是相同的,并且没有改变,所以GET是安全的、幂等的。

    不过,有些特殊情况也会认为是幂等的。例如:新闻某门户网站的头条新闻,可能在不断的更新,用户可能在不同的时间看到的内容不尽相同,但是这也认为是幂等的,因为对用户来说,他们访问的资源是同一个地址的。

    POST

    根据HTTP标准,POST用于可能修改服务器资源的请求。并没有什么特殊规定。

    例如:最常见的就是留言了,留言完之后页面会刷新,不管是整体刷新还是Ajax局部刷新,这时候用的请求就是POST

    表现形式:

    HTTP格式为:

    <request line>

    <headers>

    <blank line>

    [<request-body>]

    先是一个请求行(request line),用来说明请求类型、请求地址、HTTP版本;然后是头部(headers),用来说明服务器的一些附加信息;下来是一个空行(blank line);再下来是数据主体(request-body)。

    GET格式

    GET / HTTP/1.1
    Host: www.cppfans.org
    Connection: keep-alive
    Cache-Control: max-age=0
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.10 (KHTML, like Gecko) Chrome/23.0.1262.0 Safari/537.10 AlexaToolbar/alxg-3.1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Encoding: gzip,deflate,sdch
    Accept-Language: zh-CN,zh;q=0.8
    Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3

    POST格式

    POST /api/posts/create.json HTTP/1.1
    Host: duoshuo.com
    Connection: keep-alive
    Content-Length: 283
    Origin: http://duoshuo.com
    X-Requested-With: XMLHttpRequest
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.10 (KHTML, like Gecko) Chrome/23.0.1262.0 Safari/537.10 AlexaToolbar/alxg-3.1
    Content-Type: application/x-www-form-urlencoded
    Accept: */*
    Referer: http://duoshuo.com/cors/index.html?xdm_e=http%3A%2F%2Fjkirin.com&xdm_c=default693&xdm_p=1
    Accept-Encoding: gzip,deflate,sdch
    Accept-Language: zh-CN,zh;q=0.8
    Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3

    以上数据是通过Chrome的元素审查中的Network抓取到的。

    1.地址的区别

    举个例子:

    百度搜索的地址:

    http://www.baidu.com/s?tn=monline_4_dg&ie=utf-8&bs=http&f=8&rsv_bp=1&wd=http+get+post&rsv_sug3=9&rsv_sug1=7&rsv_sug4=325&inputT=2533

    Get请求会把数据附在URL之后,以?分割URL和传输数据,多个参数用&连接,上述URL地址可以堪为URL是http://www.baidu.com/s,后面的tn=monline_4_dg ie=utf-8 bs=http等都是参数。

    遇到空格用+替代,上述URL中的搜索词是http get post,而URL表现出来的是wd=http+get+post。

    数字和字母原样不变。wd=http+get+post

    中文和其他字符用Base64加密,例如有些URL表现为%D4%E3%A0%BD,其中%XX中XX表示该符号的16进制ANSII码。

    POST请求:把修改的数据放置在是HTTP包的包体中进行发送。

    Get请求的URL会在地址栏中显示出来,而Post只是修改,并不会改变URL。

    2.传输数据的限制

    HTTP协议对URL长度和传输的数据长度没有任何限制,不过在实际开发中会根据浏览器的限制条件做一些规定。

    GET:根据浏览器和操作系统有一些限制。例如:IE(包含IE内核)浏览器的URL限制是2K+35个字节长度,而其他浏览器理论没有限制,但却取决于操作系统支持的长度。

    POST:理论没有传输数据的限制,但总不能提交一个过大的数据,这样会很慢,所以Web服务器一般都会做限制的。

    3.安全性

    POST的安全性高于GET,这里是指Security而不是Safe,因为Get的URL可以通过分析得出一些数据出来,还有Cookie和历史记录等等都会造成一些恶意攻击或破解。

    好了,关于GET和POST就说这么多了,下来就是要写一个处理这些请求的http服务器了。有人会说为什么要自己写,而不是用Apache或者nginx等已经成熟的Web服务器?因为他们太复杂了,功能繁杂,而我却不需要这么多功能,所以我写一个简单实用的http server就可以了,不过可以借鉴成熟Web服务器的主要功能代码。敬请期待吧,估计测试和投入使用会时挺长时间的。

  • 相关阅读:
    SpringCloud Alibaba微服务实战十
    万字长文!分布式锁的实现全都在这里了
    python编程中的小技巧(持续更新)
    工作十年的数据分析师被炒,没有方向,你根本躲不过中年危机
    github入门操作快速上手
    167. 两数之和 II
    167. 两数之和 II
    167. 两数之和 II
    怎么使用Fiddler进行抓包
    怎么使用Fiddler进行抓包
  • 原文地址:https://www.cnblogs.com/fx2008/p/3682417.html
Copyright © 2011-2022 走看看