栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

WinInet库之Http通信

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

WinInet库之Http通信

// 超文本传输协议(HyperText Transfer Protocol)是互联网上应用最广泛的协议,主要是用于网页的浏览。
// HTTP采用了请求-应答模式,也就是俗称的客户端/服务器模型,简称C/S模型。
// 其中,客户端向服务器发送一个请求,请求一般包括请求行、请求头和请求体三个部分。
// 在请求头中包含请求头中包含请求方法、URL、协议版本以及请求修饰符,客户消息和内容的类似于MIME的消息结构。
// 服务器以一个状态作为响应,响应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容。

// HTTP常用的请求方法有GET、POST、PUT、DELETE四个,对应着对网络资源的查、改、增、删四个操作。
// HTTP采用TCP通信,主要是保证传输数据的稳定性、完整性。

// HTTP文件上传,主要是向服务器发送POST请求,将数据按照服务器的接收格式传输到服务器上,服务器再根据接收格式接收数据,完成文件的上传操作。
// HTTP文件下载,主要是向服务器发送GET请求,服务器接收到相应的请求后,便会读取资源数据并返回,这就完成的文件下载操作。

// PS:HttpOpenRequest函数:
// 功能:创建一个HTTP请求句柄。
// 原型:HINTERNET HttpOpenRequest(
//          _In_ HINTERNET hConnect,
//          _In_ LPCTSTR lpszVerb,
//          _In_ LPCTSTR lpszObjectName,
//          _In_ LPCTSTR lpszVersion,
//          _In_ LPCTSTR lpszReferer,
//          _In_ LPCTSTR *lplpszAcceptTypes,
//          _In_ DWORD dwFlags,
//          _In_ DWORD_PTR dwContext
//       )
// 参数:hConnect:由InternetConnect函数返回的连接句柄。
//       lpszVerb:请求的方法,默认为GET。
//       lpszObjectName:目标对象字符串,通常为文件名称、可自行模块或者查找标识符。
//       lpszVersion:HTTP版本,如果为NULL,表示使用1.1或1.0版本的HTTP协议。
//       lpszReferer:指向URL文档地址,如果为NULL,则不指定HTTP头。
//       lplpszAcceptTypes:表示客户接受的内容类型,比如"text/json"等。
//       dwFlags:标志,可以为以下值的一个或多个:
//            INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP:禁用检测这种特殊类型的重定向。
//            INTERNET_FLAG_IGNORE_CERT_CN_INVALID:根据请求中给出的主机名禁用检测从服务器返回的基于SSL/PCT的证书。
//            INTERNET_FLAG_KEEP_CONNECTION:保持连接。
//            INTERNET_FLAG_NO_AUTH:不会自动尝试验证。
//            INTERNET_FLAG_NO_cookieS:不会自动为请求添加cookie标头,也不会自动将返回的cookie添加到cookie数据库。
//            INTERNET_FLAG_NO_UI:禁用cookie对话框。
//            INTERNET_FLAG_RELOAD:强制从源服务器上下载所请求的文件,而不是从缓存中下载。
//            INTERNET_FLAG_SECURE:启用HTTPS。
//       dwContext:指定OpenRequest操作的上下文标识。
// 结果:成功返回HTTP请求句柄,失败返回NULL。

// PS:HttpSendRequestEx函数:
// 功能:将指定的请求发送到HTTP服务器。
// 原型:BOOL HttpSendRequestEx(
//           _In_ HINTERNET hRequest,
//           _In_ LPINTERNET_BUFFERS lpBuffersIn,
//           _Out_ LPINTERNET_BUFFERS lpBuffersOut,
//           _In_ DWORD dwFlags,
//           _In_ DWORD_PTR dwContext
//       )
// 参数:hRequest:由HttpOpenRequest创建的请求句柄。
//       lpBuufersIn:可选,指向INTERNET_BUFFERS结构的指针。
//       lpBuffersOut:保留,必须为NULL。
//       dwFlags:保留,必须为NULL。
//       dwContext:指定由应用程序定义的上下文值,前提是状态回调函数已注册。
// 结果:成功返回TRUE,失败返回FALSE。

// PS:HttpQueryInfo函数:
// 功能:查询有关HTTP请求的信息。
// 原型:BOOL WINAPI HttpQueryInfo(
//           HINTERNET hRequest,
//           DWORD dwInfoLevel,
//           LPVOID lpBuffer,
//           LPDWORD lpdwBufferLength,
//           LPDWORD lpdwIndex
//       )
// 参数:hRequest:由HttpOpenRequest函数创建的Request句柄。
//       dwInfoLevel:请求要查询的属性和修改请求的标志组合。
//       lpBuffer:接收信息的缓存区。
//       lpdwBufferLength:接收缓存区大小。
//       lpdwIndex:用于枚举具有相同名称的多个头的基于零的头索引。
// 结果:成功,返回TURE,失败,返回FALSE。

// PS:基于WinInet库实现的HTTP文件上传步骤如下:
//     1.调用InternetCrackUrl函数对Url进行分解,从URL中提取网站的域名、资源路径、用户名、密码以及URL的附加信息等。
//     2.调用InternetOpen函数建立会话,获取会话句柄。连接过程中要指明INTERNET_SERVICE_HTTP,这表明连接到HTTP服务器上。
//     3.调用InternetConnect函数建立连接,获取连接句柄。
//     4.调用HttpOpenRequest打开HTTP的POST请求,同时指明POST的资源路径,并且设置HTTP的访问标志。
//     5.调用HttpSendRequestEx函数向服务器发送访问请求。
//     6.调用InternetWriteFile函数将本地数据写到远程主机上,即向服务器上传数据。等数据上传完毕后,调用HttpEndRequest函数来结束请求。
//     7.关闭句柄,释放缓存区资源。

// PS:示例代码:

// 数据上传
BOOL Http_Upload(char *pszUploadUrl, BYTE *pUploadData, DWORD dwUploadDataSize)
{
    // 变量(略)

    // 分解URL
    if (FALSE == Http_UrlCrack(pszUploadUrl, szScheme, szHostName, szUserName, szPassword, szUrlPath, szExtraInfo, MAX_PATH))
    {
        return FALSE;
    }

    // 数据上传
    do 
    {
        // 建立会话
        hInternet = ::InternetOpen("WinInet Http Upload v1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
        if (NULL == hInternet)
        {
            Http_ShowError("InternetOpen");
            break;
        }

        // 建立连接
        hConnect = ::InternetConnect(hInternet, szHostName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPassword, INTERNET_SERVICE_HTTP, 0, 0);
        if (NULL == hConnect)
        {
            Http_ShowError("InternetConnect");
            break;
        }

        // 拼接szUrlPath
        if (0 < ::lstrlen(szExtraInfo))
        {
            ::lstrcat(szUrlPath, szExtraInfo);
        }

        // 设置标记
        dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_KEEP_ConNECTION | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_cookieS |
                             INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;

        // 创建POST请求
        hRequest = ::HttpOpenRequest(hConnect, "POST", szUrlPath, NULL, NULL, NULL, dwOpenRequestFlags, 0);
        if (NULL == hRequest)
        {
            Http_ShowError("HttpOpenRequest");
            break;
        }

        // 发送请求,告诉服务器传输数据的总大小
        ::RtlZeroMemory(&internetBuffers, sizeof(internetBuffers));
        internetBuffers.dwStructSize = sizeof(internetBuffers);
        internetBuffers.dwBufferTotal = dwPostDataSize;
        bRet = ::HttpSendRequestEx(hRequest, internetBuffers, NULL, 0, 0);
        if (FALSE == bRet)
        {
            break;
        }

        // 发送数据
        bRet = ::InternetWriteFile(hRequest, pUploadData, dwUploadDataSize, &dwRet);
        if (FALSE == bRet)
        {
            break;
        }

        // 发送完毕,结束请求
        bRet = ::HttpEndRequest(hRequest, NULL, 0, 0);
        if (FALSE == bRet)
        {
            break;
        }

        // 接收响应报文信息头
        pResponseHeaderInfo = new unsigned char[dwResponseHeaderInfoSize];
        if (NULL == pResponseHeaderInfo)
        {
            break;
        }

        ::RtlZeroMemory(pResponseHeaderInfo, dwResponseHeaderInfoSize);
        bRet = ::HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, pResponseHeaderInfo, &dwResponseHeaderInfoSize, NULL);
        if (FALSE == bRet)
        {
            Http_ShowError("HttpQueryInfo");
            break;
        }

        // 从字段"Content-Length"中获取数据长度
        bRet = Http_GetContentLength((char*)pResponseHeaderInfo, &dwResponseHeaderInfoSize);
        if (FALSE == bRet)
        {
            break;
        }

        // 接收报文主体内容
        pBuf = new BYTE[dwBufSize];
        if (NULL = pBuf)
        {
            break;
        }

        pResponseBodyData = new BYTE[dwResponseBodyDataSize];
        if (NULL == pResponseBodyData)
        {
            break;
        }

        ::RtlZeroMemory(pResponseBodyData, dwResponseBodyDataSize);

        do
        {
            ::RtlZeroMemory(pBuf, dwBufSize);
            bRet = ::InternetReadFile(hRequest, pBuf, dwBufSize, &dwRet);
            if (FALSE == bRet)
            {
                Http_ShowError("InternetReadFile");
                break;
            }
            ::RtlCopyMemory((pResponseBodyData + dwOffset), pBuf, dwRet);
            dwOffset += dwRet;
        } while (dwResponseBodyDataSize > dwOffset);
    } while (FALSE);

    // 关闭并释放(略)

    return bRet;
}

// PS:基于WinInet库的HTTP文件下载步骤:
//     1.调用InternetCrackUrl函数分解URL,从URL中提取网站的域名、资源路径以及URL的附加信息等。
//     2.调用InternetOpen函数建立会话并获取会话句柄。
//     3.调用InternetConnect函数建立连接,并指定连接的类型为INTERNET_SERVICE_HTTP,即连接到HTTP服务器上。
//     4.使用HttpOpenRequest创建一个GET请求,同时指明访问服务器的资源路径并设置HTTP的访问标志。
//     5.使用HttpSendRequestEx函数将访问请求发送到服务器上。这样服务器就可以获取请求信息和返回响应头信息。
//     6.调用HttpQueryInfo函数获取返回的Response Header信息,并根据Content-Length字段中的数据确定接收的数据长度,申请接收数据的缓存区。
//     7.循环调用InternetReadFile函数接收数据,直到接收数据的长度等于返回数据的长度。
//     8.关闭句柄,释放数据缓存区。

// PS:示例代码:

// 数据下载

BOOL Http_Download(char* pszDownloadUrl, BYTE **ppDownloadData, DWORD *pdwDownloadDataSize)
{
    // 变量(略)

    // 分解URL
    if (FALSE == Http_UrlCrack(pszDownloadUrl, szScheme, szHostName, szUserName, szPassword, szUrlPath, szExtraInfo, MAX_PATH))
    {
        return FALSE;
    }

    // 拼接szUrlPath
    if (0 < ::lstrlen(szExtraInfo))
    {
        ::lstrcat(szUrlPath, szExtraInfo);
    }

    // 数据下载
    do 
    {
        // 建立会话
        hInternet = ::InternetOpen("WinInte Http Download v1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
        if (NULL == hInternet)
        {
            Http_ShowError("InternetOpen");
            break;
        }

        // 建立连接
        hConnect = ::InternetConnect(hInternet, szHostName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPassword, INTERNET_SERVICE_HTTP, 0, 0);
        if (NULL == hConnect)
        {
            Http_ShowError("InternetConnect");
            break;
        }

        // 设置标志
        dwOpenRequestFlags = INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_KEEP_ConNECTION | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_cookieS |
                             INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD;

        // 创建请求
        hRequest = ::HttpOpenRequest(hConnect, "GET", szUrlPath, NULL, NULL, NULL, dwOpenRequestFlags, 0);
        if (NULL == hRequest)
        {
            Http_ShowError("HttpOpenRequest");
            break;
        }

        // 发送请求
        bRet = ::HttpSendRequestEx(hRequest, NULL, 0, NULL, 0);
        if (FALSE == bRet)
        {
            Http_ShowError("HttpSendRequestEx");
            break;
        }

        // 接收响应的报文信息头
        pResponseHeaderInfo = new unsigned char[dwResponseHeaderInfoSize];
        if (NULL == pResponseHeaderInfo)
        {
            break;
        }
        ::RtlZeroMemory(pResponseHeaderInfo, dwResponseHeaderInfoSize);

        // 查询响应信息头
        bRet = ::HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, pResponseHeaderInfo, &dwResponseHeaderInfoSize);
        if (FALSE == bRet)
        {
            Http_ShowError("HttpQueryInfo");
            break;
        }

        // 从字段"Content-Length"中获取数据长度
        bRet = Http_GetContentLength((char*)pResponseHeaderInfo, dwResponseHeaderInfoSize);
        if (FALSE == bRet)
        {
            break;
        }

        // 申请动态内存,用于接收报文主体数据
        pBuf = new BYTE[dwBufSize];
        if (NULL == pBuf)
        {
            break;
        }

        ::RtlZeroMemory(pDownloadData, dwDownloadDataSize);

        // 循环接收数据
        do 
        {
            ::RtlZeroMemory(pBuf, dwBufSize);
            bRet = ::InternetReadFile(hRequest, pBuf, dwBufSize, &dwRet);
            if (FALSE == bRet)
            {
                break;
            }
            ::RtlCopyMemory((PVOID)(pDownloadData + dwOffset), pBuf, dwRet);
            dwOffset += dwRet;
        } while (dwDownloadDataSize > dwOffset);

        // 返回数据
        **ppDownloadData = pDownloadData;
        *pdwDownloadDataSize = dwDownloadDataSize;
    } while (FALSE);

    // 关闭句柄,释放缓存区(略)

    return bRet;
}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/310906.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号